반응형

getInflater


LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

LayoutInflater inflater = LayoutInflater.from(context);




Color

ContextCompat.getColor(getContext(),R.color.list_bg_normal));

public void setBackgroundColor( @ColorInt int color) {

vContainer.setBackgroundColor(color);

}


isetBackgroundResource( R.color.list_bg_normal);

public void setBackgroundResource( @DrawableRes int resid) {

vContainer.setBackgroundResource(resid);

}


String

String categoryName = Any.getContext().getResources().getString(R.string.default_category_name);



ImageView to Bitmap

Bitmap bitmap = ((BitmapDrawable) mivSumnail.getDrawable()).getBitmap();

반응형
반응형

복잡해 보이지만, 알고보면 간단한 Navigation Drawer Activity의 구조


안드로이드 모바일 앱에서 많이 보이는 Navigation Drawer Activity의 '레이아웃 구조'에 대해 정리 합니다.


뜯어보면 몇가지 레이아웃을 조합해서 만들어 놓은 UI 형태인데,

처음 접할때는 전체 구조가 머리속에 잘 안들어 오더라구요.



Navigation Drawer는 Android 프로젝트 생성시에도 기본으로 제공되는 Activity 타입니다.



Navigation Drawer Activity타입으로 프로젝트를 생성하면


기본으로 네개의 레이아웃을 생성해 주는데요, 각 레이아웃에 대해 간단히 분석해 보겠습니다.


(* app_bar_main.xml에 생성되는 FloatingActionButton은 설명의 편의를 위해 삭제 했습니다.)


[activity_main.xml]


DrawerLayout안에 app_bar_main을 포함하고 NavigationView를 배치한 형태 입니다.
app_bar_main은 include 형태로 포함되어 있으며, 

<include
layout="@layout/app_bar_main"
android:layout_width="match_parent"
android:layout_height="match_parent" />


nav_header_main은 NavigationView의 headerLayout 속성으로 설정되어 NavigationView가 그려질때 Header 영역에 그려지게 됩니다.
하위에 표시되는 메뉴는 activity_main의 app:menu="@menu/activity_main_drawer" 에 의해서 결정됩니다.

 

<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_main"
app:menu="@menu/activity_main_drawer" />


@drawer_layout ( DrawerLayout )

DrawerLayout은 윈도우의 한 쪽 혹은 양쪽 모서리에서 끌어낼 수있는 '서랍(Drawer)' 형태의 뷰와 

인터렉션을 위한 윈도우의 최상위 컨테이너 역할을 하는 레이아웃 입니다. ( ???? )

activity_main.xlm의 전체를 감싸고 있는 레이아웃이 DrawerLayout(@drawer_layout)위젯이며 

아래와 같은 코드를 통해 ActionBarDrawerToggle 인스턴스와 결합됩니다.




뿐만 아니라, Navigation View를 열거나 닫기 위해 다음과 같이 사용됩니다.




@nav_view ( Navigation View )

Navigation View는응용 프로그램의 표준 탐색(Navigation) 메뉴를 대표(?) 합니다. (메뉴 내용은 메뉴 리소스 파일로 채울 수 있습니다.)
NavigationView.OnNavigationItemSelectedListener 리스너를 설정하여, navigation menu 선택에 따른 동작을 처리 할 수 있습니다.




nav_header_main.xml

보통 홈버튼을 누르게 되면 펼쳐지는 Navigation뷰의 Header 부분을 표시하는 레이아웃 입니다.

이 레이아웃은 Navigation View의 header 영역을 표시하는 용도로 사용됩니다.


(* 포함된 ImageView나 TextView등의 위젯은 본 주제에서는 큰 의미가 없으므로 설명은 스킵합니다.)



app_bar_main.xml

Navigation View가 펼쳐지기 전에 전체 스크린으로 보게 되는 레이아웃 입니다.
여기부터는 일반적으로 구성되는 기본 레이아웃과 크게 다르지 않습니다. 
상단에 toolbar를 품은 AppBarLayout 을 배치하고, 
아래에 실제 내용을 보여줄 content_main을 include 하고 있습니다.

<include layout="@layout/content_main" /> 



content_main.xml

실제 보여주고자 하는 내용을 표현하게 될 content_main layout입니다.
ConstraintLayout이 content_frame을 감싸고 있습니다.


Navigation Drawer Layout은 일반적으로 Navigation 메뉴를 선택시 Fragment를 교체하는 형태로 사용되는데,

다름과 같은 코드로 content_frame을 교체하는 방식으로 사용된다.

case R.id.nav_tools {

FragmentTransaction ft = getFragmentManagerInstance().beginTransaction();

Fragment fragment = new ToolFragment();

ft.replace(R.id.content_frame, fragment, TOOL_FRAGMENT_TAG);
ft.commit();
break;

}


Navigation Drawer ...

영어를 그대로 읽고 쓰다 보니 생각해 본적이 없었는데

직역하면 '탐색 서랍' 인가요???



반응형

'안드로이드' 카테고리의 다른 글

RecyclerView #1- 구조 및 기본 사용법  (0) 2019.03.13
코드 모음  (0) 2019.03.08
Android resource compilation failed  (3) 2019.02.23
Activity간 Object 공유- Parcelable  (0) 2019.02.21
EditText 포커스 문제  (0) 2019.02.13
반응형

Android resource compilation failed


오픈소스를 하나 다운받이 분석해 보려 한다.

타겟은 omniNotes


소스를 다운받고, 빌드해서 실행해 보려 했으나 빌드 부터 말썽이다.


발생하는 오류는

Android resource compilation failed

[Source Path]\omniNotes\build\intermediates\incremental\mergeFossDebugResources\merged.dir\values\values.xml:896: error: <item> inner element must either be a resource reference or empty.

Source Path]\omniNotes\build\intermediates\incremental\mergeFossDebugResources\merged.dir\values\values.xml:898: error: <item> inner element must either be a resource reference or empty..

.


구글링 해보니 관련 이슈가 엄청나게 많다.


이해한 수준에서 간단히 정리하자면
Gradle Build tool이 업데이트 되면서, <item> 태그의 규칙을 엄격하게 체크하게 된것(?) 

이런식으로 기술된 것들을

<item name="child_text" type="id">childText</item>


아래와 같이 수정해 주어야 한다.

<item name="child_text" type="id"> 


즉 에러에 나와 있는 문구를 준수하면 된다.

<item> inner element must either be a resource reference or empty..


하지만, 전체 프로젝트를 search해 봐도 유사한 부분은 없다.

이번 케이스는 빌드하면서 자동생성되는 파일이기 때문에 수정이 불가하다는 얘기다


아마도 프로젝트가 참조하는 라이브러리에 관련 부분이 포함되어 있고, 
리소스를 컴파일 하면서 해당 부분이 문제가 되는 케이스로 추측된다.

혹시나 해서 최신버전이 아닌 라이브러리 들을 모두 최신으로 업데이트 해봤지만
에러가 발생하는 파일의 갯수가 줄기는 했지만 완전히 해결이 되진 않았다.

이리 저리 찾아보다가, 수정사항을 폐기하고 github에서 소스들 다시 받았더니 정상적으로 빌드가 되기 시작한다.
이건 뭐....
찝찝하지만 그상태로 소스를 보다가, 다음날 다시 해보니 또 동일한 오류가 발생한다.

어제 github에서 소스를 다시 받으니 빌드가 되었던것이 생각나서 변경사항을 확인해 보니
다음과 같이 딱 두군데가 차이가 있다.



Gradle Scripts > build.gradle(Project)의 com.android.tools.build:gradle버전을 3.3.1에서 3.1.2로 수정해 주니 정상적으로 빌드가 된다.
buildscript {
repositories {
jcenter()
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.1.2'
classpath 'me.tatarka:gradle-retrolambda:3.2.5'
classpath 'me.tatarka.retrolambda.projectlombok:lombok.ast:0.2.3.a2'
classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6"
classpath 'com.dicedmelon.gradle:jacoco-android:0.1.1'
}
// Exclude the version that the android plugin depends on.
configurations.classpath.exclude group: 'com.android.tools.external.lombok'
} 



오늘 프로젝트 빌드시 팝업된 업데이트를 별생각없이 진행했는데 이 영향을 받은 것으로 보인다.





물론, 문제의 소지는 여전히 가지고 있고, 근본적인 해결책이 되진 않는다만
우선은 소스 분석이 목적이니 그냥 넘어가도록 하자.



* 처음에는 이런 에러도 떴었는데, 이리 저리 하다 보니 없어졌는데, 정확한 조치가 어떤것이었는지는 정확히 모르겠음


C:\Users\xxxx\.gradle\caches\transforms-1\files-1.1\library-0.0.2.aar\88f4da1871053ebc65d966332b9adccc\res\values\values.xml:52:5-49: AAPT: error: <item> inner element must either be a resource reference or empty. 


* 대략 다음과 같은 가이드가 존재한다.

1. 위에서 설명한 <item type="id> 관련 부분 수정

2. Gradle.property에 android.enableAapt2=false 추가

3. Build 폴더 삭제


* 참고사이트

https://stackoverflow.com/questions/52503768/android-resource-compilation-failed-in-v3-2

https://stackoverflow.com/questions/52076491/android-inner-element-must-either-be-a-resource-reference-or-empty

https://blog.codejun.space/37



반응형

'안드로이드' 카테고리의 다른 글

코드 모음  (0) 2019.03.08
Navigation Drawer 의 Layout구조  (2) 2019.02.27
Activity간 Object 공유- Parcelable  (0) 2019.02.21
EditText 포커스 문제  (0) 2019.02.13
Android Studio 단축키  (0) 2018.12.21
반응형

Activity간의 Object 공유 - Parcelable

 

하나의 Activity에서 다른 Activity로 데이터를 전달해야 하는 경우에

데이터를 전달하는 Activity에서는 Intent Class의 putExtra() 메소드를 이용해서 데이터를 세팅하고,

받는 쪽에서는 getExtra() 메소드를 이용해서 받게 된다.

 

puExtra()을 이용해서 전달할수 있는 데이터 타입은 대략 다음과 같다.

 

 

ActivityA에서 Book Class의 인스턴스를 관리하고,

ActivityB에서 Book Class의 정보를 UI에 표시하는 상황을 가정해 보자.

 

Book Class는 아래와 같다.

public class Book {
    int serial;
    String isbn;
    String title;
    Bitmap image;
}

 

Book Class의 전체 프라퍼티를 ActivityA에서 ActivityB로 전달하려면 아래와 같이, 프라퍼티 별로 하나씩 put()하고 get()할 수 밖에 없다.

MainActivity

intent.putExtra("serial", book.getSerial());
intent.putExtra("isbn", book.getIsbn());
intent.putExtra("title", book.getTitle());
intent.putExtra("image", book.getImage());
BookActivity

int serial = intent.getIntExtra("serial", 0);
String isbn = intent.getStringExtra("isbn");
String title = intent.getStringExtra("title");
Bitmap image = intent.getParcelableExtra("image");

 

아래와 같이 사용하고 싶은 생각이 들것이다.

MainActivity

Book book = new Book(1, "1-1-1-1", "슬럼독 밀리어네어", bitmap);

Intent intent = new Intent(getApplicationContext(), BookActivity.class);
intent.putExtra("book", book);
BookActivity

Book book = intent.getExtra("book");

 

우선은 Intent  putExtra() 메소스 중, 아래의 두가지 함수원형을 눈여겨 보자!

putExtra( String name, Parcelable value );
putExtra( String name, Serializable value);

우리가 전달하고자 하는 Class가 Serializable 하거나 Parcelable 하게 만들 수 있다면 가능할것 같지 않은가?

 

구글링을 하다 보니 도착한 Goolgle의 가이드를 보면( 링크를 잃어 버렸다),

Serializable 보다는 Parcelable을 권장하는 듯 하니 Parcelable 을 사용하는 방법을 확인해 보기로 하자.

(Serializable의 Java의 표준 인터페이스이며, Parcelable의 안드로이드 SDK에 포함된 인터페이스 이다)

 

Parcelable은 IPC를 이용하여 데이터를 공유하며 Serialiable과는 달리 리플렉션을 사용하지 않으므로

성능면에서 유리하다고 한다.

반면 전달하는 데이터의 해석코드를 필수적으로 작성해야 하므로, 유지보수 측면에서는 상대적으로 귀찮고

번거로운 작업이 동반된다.

 

개략적으로 개념을 잡아 보자면

여러 Activity가 접근할 수 있는 영역(아마도 커널 메모리)에 

1. 전달하고자하는 데이터를 순차적으로 저장 한다.

2. 저장된 데이터를 순차적으로 읽어서 해석할 수 있는 방법을 제공한다.

* 다만 데이터를 쓰고, 읽는 방법은 Parcelable Interface가 지원하는 메소드를 통해서만 가능하다.

* 쓰여진 데이터를 해석하는데 있어 데이터가 쓰여진 순서대로 읽어야 복원이 가능하기 때문에

Write한 순서와 Read한 순서를 일치시키는 것은 반드시 지켜져야한다.

* 개념적으로 직렬화/마샬링과 유사한 개념으로 생각하면 이해가 편할것 같다.

직렬화(serialization)

마샬링(Marshalling)

 

구현 방법은 다음과 같다.

1. 공유하고자 하는 Class가 Parcelable Interface를 상속받도록 구현한다.

public class Book implements Parcelable {
    int serial;
    String isbn;
    String title;
    Bitmap image;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
    }
}

 

2. 필수 추상 메소스를 구현한다.

* writeToParcel() 메소드가 전달할 데이터를 기록하는 메소드의 구현이다.

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(serial);
        dest.writeString(isbn);
        dest.writeString(title);
        dest.writeParcelable(image, flags);
    }

 

3. CREATOR를 구현한다.

public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        public Book[] newArray(int size) {
            return new Book[size];
        }
};

 

4. 생성자를 구현한다.

* 단순히 생성자라기 보다는 Parcelable data를 해석할 수 있는 방법의 구현이다.

public Book(Parcel src) {
        readFromParcel(src);
    }

public void readFromParcel(Parcel src) {
    serial = src.readInt();
    isbn = src.readString();
    title = src.readString();
    image = src.readParcelable(Bitmap.class.getClassLoader());
}

public Book(int serial, String isbn, String title, Bitmap image) {
    this.serial = serial;
    this.title = title;
    this.isbn = isbn;
    this.image = image;
}

 

전체 코드는 다음과 같다.

Book.java

( getter/setter의 구현은 필수 적이지 않다 )

package com.tistory.thepassion.pacelable;

import android.graphics.Bitmap;
import android.os.Parcel;
import android.os.Parcelable;

public class Book implements Parcelable {
    int serial;
    String isbn;
    String title;
    Bitmap image;

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(serial);
        dest.writeString(isbn);
        dest.writeString(title);
        dest.writeParcelable(image, flags);
    }

    public static final Parcelable.Creator<Book> CREATOR = new Parcelable.Creator<Book>() {
        public Book createFromParcel(Parcel in) {
            return new Book(in);
        }

        public Book[] newArray(int size) {
            return new Book[size];
        }
    };

    public Book(Parcel src) {
        readFromParcel(src);
    }

    public void readFromParcel(Parcel src) {
        serial = src.readInt();
        isbn = src.readString();
        title = src.readString();
        image = src.readParcelable(Bitmap.class.getClassLoader());
        // image = Bitmap.CREATOR.createFromParcel(src);
    }

    public Book(int serial, String isbn, String title, Bitmap image) {
        this.serial = serial;
        this.title = title;
        this.isbn = isbn;
        this.image = image;
    }

    public int getSerial() {
        return serial;
    }

    public void setSerial(int serial) {
        this.serial = serial;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getIsbn() {
        return isbn;
    }

    public void setIsbn(String isbn) {
        this.isbn = isbn;
    }

    public Bitmap getImage() {
        return image;
    }

    public void setImage(Bitmap image) {
        this.image = image;
    }
}

 

MainActivity.java

package com.tistory.thepassion.pacelable;

import android.content.Intent;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {
    Book book;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Resources res = getResources(); Drawable d = res.getDrawable(R.drawable.book);
        Bitmap bitmap = ((BitmapDrawable) d).getBitmap();

        book = new Book(1, "1-1-1-1", "슬럼독 밀리어네어", bitmap);

        Intent intent = new Intent(getApplicationContext(), BookActivity.class);
        intent.putExtra("book", book);

        startActivity(intent);
    }
}

 

ActivityB.java

package com.tistory.thepassion.pacelable;

import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v7.app.AppCompatActivity;
import android.widget.ImageView;
import android.widget.TextView;

public class BookActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_book);

        Intent intent = getIntent();

        Book book = intent.getParcelableExtra("book");
        ((TextView) findViewById(R.id.txtSerial)).setText(String.valueOf(book.getSerial()));
        ((TextView) findViewById(R.id.txtIsbn)).setText(book.getIsbn());
        ((TextView) findViewById(R.id.txtTitle)).setText(book.getTitle());
        ((ImageView) findViewById(R.id.imageView)).setImageBitmap(book.getImage());
    }
}

 

 

지금까지 읽어 내려오면서 궁금한 점이 있었는지 모르겠다.

Parcelable을 구현하기 전의 첫번째 예제에서도 Bitmap 객체를 넘겼었고,

마지막의 전체 구현 코드에서도 Bitmap 객체를 전달하고 있다.

 

예상한것처럼 Bitmap Class가 Parcelable을 implement하고 있기 때문이다.

public final class Bitmap implements Parcelable {
    private static final String TAG = "Bitmap";

    ....
    ....
}

 

Parcelable 을 통해 Object를 공유하고자 할때, 프라퍼티로 포함하고 있는 Class 또한

Parcelable 혹은 Serializable로 구현되어야 한다.

(binary data를 뽑아서 저장하고 복원할 수 있도록 한다면 불가능 하다고 할수는 없으니, 꼭 그런것은 아니다.)

 

사실 Bitmap을 포함한 Class를 다른 Activity로 넘기고 싶어 내용을 확인하고 정리하는 것이기는 한데...

Parcelable을 통해 전달할 수 있는 데이터의 사이즈에는 제한이 있다.

1MB 이상의 데이터를 전달하고자 할때 다음과 같은 에러가 발생할 수 있다.

Caused by: android.os.TransactionTooLargeException: data parcel size 1204788 bytes

 

1MB 제한은 구현한 Parcelable객체 하나당이 아닌 Activity가 속한 프로세스 전역에 걸친 한계 용량으로,

Parcelable을 통해 큰 사이즈의 데이터를 전달하는것은 적합하지 않다.

대략 50kb 미만의 데이터 사이즈를 권장하고 있다.

https://developer.android.com/guide/components/activities/parcelables-and-bundles

 

다른 측면에서 생각해보면

android.provider.MediaStore.ACTION_IMAGE_CAPTURE 를 이용해 촬영한 이미지를 얻을때,

onActivityResult 를 통해 섬네일이미지는 획득이 가능하지만, 

풀이미지를 얻기 위해서는 별도의 Uri를 통해야하는 이유를 이해할 수 있다. 

 

결국 bitmap을 전달해야 할 경우, 

Bitmap 객체가 아닌 파일 경로 혹은 대상 bitmap파일을 불러올수 있는 key를 전달하는 방식으로 우회해야 할것같다.

반응형

'안드로이드' 카테고리의 다른 글

Navigation Drawer 의 Layout구조  (2) 2019.02.27
Android resource compilation failed  (3) 2019.02.23
EditText 포커스 문제  (0) 2019.02.13
Android Studio 단축키  (0) 2018.12.21
Android Studio 화면구성  (0) 2018.05.13
반응형

GitHub private Repository 무료 사용가능



GitHub는 

Open Source 프로젝트들의 소스관리뿐만 아니라

개발자 개인이 소스관리 하기에 참 유용한 존재이죠.


다만 개인적인 사용성에 있어서는 

private Repository는 유료인 관계로, 

공개가 어려운 프로젝트를 관리하기에는 애로사항 있었습니다.


하지만

마이크로 소프트에서 깃허브를 인수하면서

무료 사용자에게도 Private Repository를 사용가능하도록 가격정책을 변경하였다고 하네요.



pricing page를 보면 3명의 협업자 제한으로 무료(free)로 사용 가능한 것으로 표기되어 있습니다..



물론 생성도 가능합니다.



저장소 옆에 [Private]라고 표시됩니다.



일단 저 개인적으로는 반가운 소식 입니다만

정말 좋은 변화일지는 좀 지켜봐야 겠죠?


반응형

'개발일반' 카테고리의 다른 글

DoD 5220.22-M 삭제알고리즘  (0) 2011.10.13
1.1 생성패턴:Abstract Factory  (0) 2008.04.14
1. 생성패턴  (0) 2008.04.14
디자인패턴(Design Patterns)  (0) 2008.04.14
반응형

안드로이드 애플리케이션 UI디자인&프로그래밍

도카시키 마모루 지음

이윤혜 옮김

정보문화사





저자가 개발한 안드로이드 앱을 실제 사례로, 아이템 구상부터 화면디자인, 개발, 운영까지의 개발프로세스 전반을 예제로 설명한 책.


아이템 구상부터 이미지 제작, 프로그래밍 까지... 따라하긴 쉽지 않다.


그래도 실제 앱을 구상하고 개발 출시하는 과정을 순차적으로 예시하고 있어 읽어보면 도움이 된다.


목차

1. 아이디어 구상

2. 실현가능성 확인

3. 아이콘 디자인

4. 리소스 제작

5. UI 설계

6. 레이이웃 XML 작성

7. 아키텍처 설계

8. 프로그래밍

9. 애플리케이션 제작 마무리

10. 구글플레이를 통한 배포

11. 피드백 분석



반응형

+ Recent posts