후~ 전편은 여기로!
2012/03/07 - [Android Study] - Android Study ListView Indexer 2편 

아흥 슬슬 어케 마무리 지어야 할지 매우 난감하네...
private class IconAdapter extends CursorAdapter implements SectionIndexer {
    private SectionIndexer mIndexer;
    
@Override
    public int getPositionForSection(int sectionIndex) {
        if (mIndexer == null) {
            return -1;
        }
        return mIndexer.getPositionForSection(sectionIndex);
    }
 
    @Override
    public int getSectionForPosition(int position) {
        if (mIndexer == null) {
            return -1;
        }
        return mIndexer.getSectionForPosition(position);
    }

    @Override
    public Object [] getSections() {
        if (mIndexer == null) {
            // 이거 null 리턴하면 200% 에러 발생함. 그냥 요롷게 주는게 속편함.
            return new String[] { " " };
        } else {
            return mIndexer.getSections();
        }
    } 
}
정말 별거 없는 내용임... 그냥 mIndexer 객체가 null 일 경우만 정해 주면 알아서 처리가 됨. 참 쉽죠잉~ 
다음 편은 PracticeIndexer class 내용 입니당~

'Android' 카테고리의 다른 글

Android Study ListView Indexer 5편  (0) 2012.03.07
Android Study ListView Indexer 4편  (0) 2012.03.07
Android Study ListView Indexer 2편  (1) 2012.03.07
Android Study ListView Indexer 1편  (0) 2012.03.07
LayoutInflater에 대하여...  (0) 2012.02.15
전편 필요 한분 ㄱㄱㅆ
2012/03/07 - [Android Study] - Android Study ListView Indexer 1편 

나는 늘 이게 문제인듯 ㅍㅍ 발행 해놓고 한동안 잠적질?? (마치 왕창 똥싸놓고 튀는 느낌ㅋ)
우리 이제 후후 실전 code를 짜보아요~ let's go!

Base 뼈대 Code.
private class IconAdapter extends CursorAdapter implements SectionIndexer {
    private PracticeIndexer mIndexer;
    @Override
    public int getPositionForSection(int section) {
        return 0;
    }

    @Override
    public int getSectionForPosition(int position) {
        return 0;
    }

    @Override
    public Object[] getSections() {
        return null;
    }

위 뼈대 code만 체우면 제대로 된거 나올꺼 같은 느낌이 마구마구 샘솓음 으캬~
Indexer 사용 하려면 기본 뼈대니까 그냥 외워버리...기는 너무 큰가?
별거 없음 그냥 위에 @Override 함수하고 PracticeIndexer 만 체워 넣으면 되는 거니깐 너무 겁먹지 마시고..

PracticeIndexer class는 SecticeIndexer를 상속 받은 class

getSectionForPosition 함수는 현재 ListView position을 넣으면 해당 배열 위치가 반환 됨
getPositionForSection 함수는 현재 section 배열 위치를 넣으면 해당 position이 반환 됨

요지는  getSectionForPosition 이걸로 현재 section 위치 얻어옴. 이 위치에 다음 section의 위치를 얻고 싶응 께 getPositionForSection 요걸로 얻어 오는 거임.
왜 이렇게 하냐면 현재 List의 위치에 sectionIndexer가 끝인지 시작인지, 다음 껀지 모르니까 담 section 위치와 List의 현재 위치를 비교해서 처리 하려고 하는 거임.
무튼 실전 코드는 담편에... (난 편수 늘리기 대마왕~)

- 네가 알고 있는 지식을 순순히 내놓는다면 유혈 사태는 벌어지지 않을 것이다..?


후~ 간만에 돌아와서 Android 강좌를 하게 되었네... (웃음...)
자 전편에 이어서 마무리~ ㄱㄱㅆ

2012/02/08 - [Android Study] - Android List에 index를 표시해보자 1편 


Android 에서 IPhone 처럼 list에 index 표시 하려면 indexer라는 걸 이용 하는 것이 속편한거 같다.
Indexer는 2개가 있는데 SectionIndexer와 AlphabetIndexer 요고...
자세히 다 아는건 아닌데 그냥 사용해 본 경험만 있는 (읭? 무슨 말인지?)

내가 사용 할 녀석은 SectionIndexer 이거 쓸꺼임. 사용 할 곳은 Adapter(ListView 내용물 처리 해주는 녀석). 에다가 사용 할 예정임.

이렇게 말로만 하면 이해도 안되고 감흥도 없고 지루하기 짝이 없겠지??
그래서 준비한 code...
private class IconAdapter extends CursorAdapter implements SectionIndexer {
    ...
}

뭐 대충 이렇다는거 사실 SectionIndexer에는 3개의 abstract 함수가 존재함
그거 다 구현 해야하는데 그건 담편으로 넘길꺼임,
마찬가지로 BaseAdapter 여기에도 abstarct 함수가 존재함.
이건 예전에 강좌로 남겼기 때문에 버릴예정. 모르겠으면 전편 찾아보시길...

담편에서 보아용~
 

'Android' 카테고리의 다른 글

Android Study ListView Indexer 3편  (0) 2012.03.07
Android Study ListView Indexer 2편  (1) 2012.03.07
LayoutInflater에 대하여...  (0) 2012.02.15
Cursor close 해야 하는 이유와 하는 방법.  (2) 2012.02.14
Android database 만들기 7편  (0) 2012.02.10


지금 사랑하는 사람이 있다면 당장 달려가 사랑한다고 말해주세요.

'My Stroy' 카테고리의 다른 글

인도 출장  (0) 2012.03.22
아이고... 삭신이야~  (0) 2012.03.19
아흥 춥다~  (0) 2012.02.08
요세 하고 있는 일...  (0) 2012.02.04
혈액형별 뇌 그림??  (0) 2012.01.25

Android 사용 하다 보면 xml로 된 layout 파일을 어떤 식이든지 View 형태의 객체로 얻고 싶은 경우가 있을 것 이다. (없으면 말고...)

이 때 사용되는 녀석이 LayoutInflater 라는 녀석인데.
첨음 내가 이걸 접할때 대체 뭐하는 넘이지 하는 막연한 생각만 가지고 있어서 설명을 해볼까 함.

우선 layout.xml이 필요함.
그리고 LayoutInflater가 필요한데.
얻는 방법은 2가지가 있음.
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LayoutInflater inflater2 = getLayoutInflater();

각각 차이점은 inflater는 system에서 얻어 오는 방법이고,
inflater2는 Activity에서 제공하는 메소드를 이용해 얻어 오는 방법임. (둘다 별반 차이없음)

inflater는 View객체를 반환 해주는 4가지 메소드가 존재함.
// 리소스(R.layout.xxx), root
inflater.inflate(resource, root);
// XMLparser, root  
inflater.inflate(parser, root);
// 리소스(R.layout.xxx), root, attach 조건(보통 false)
inflater.inflate(resource, root, attachToRoot);
//  XMLparser, root, attach 조건(보통 false)
inflater.inflate(parser, root, attachToRoot);
이렇게 4가지 이고 각각의 파라메터에 대한 부연 설명을 하자면,
리소스는 프로젝트/res/layout 폴더에 들어 있는 xml 파일을 지정 하면됨,
XMLparser는 잘 안쓰니 버리고(나도 써본적이 없음),
root는 내가 지정한 리소스(xml 파일)이 어디에 붙을 껀지 지정하는 것임(없으면 null 넣으면됨),
attach 조건 이게 좀 복잡한데 이해 하려면  LayoutParams 이란 걸 알아야함.
LayoutParams은 xml 상에서 (android:layout_width, android:layout_height) 을 code로 정의 해주는 녀석인데 이녀석에 대한 생성 기준을 어디로 설정 할 것이냐 묻는 것이다.

예를 들어 내가 show_item.xml 파일을 list라는 LinearLayout 에다가 add 하고 싶다고 한다면.
//  LinearLayout 객체 생성
LinearLayout list = (LinearLayout)findViewById(R.id.list);
//  LinearLayout 객체 초기화 
list.removeAllViews();
//  LayoutInflater 객체 생성
LayoutInflater inflater = getLayoutInflater();
//  View 객체 생성
View view =inflater.inflater(R.layout.show_item, list(View를 붙일 녀석), false(붙일 조건));
//  LinearLayout 객체에 View 객체 추가 
list.add(view);
이렇게 될 것이다. 이때 붙일 조건이 중요한데 이녀석이 false 이면, show_item.xml에서 사용된 (android:layout_width, android:layout_height) 값들을 list에다가 새로 추가를 해주는 작업을 하게 된다. (맞니?...)
Android Developer에 있는 붙일 조건에 대한 설명
(Whether the inflated hierarchy should be attached to the root parameter? If false, root is only used to create the correct subclass of LayoutParams for the root view in the XML)

이렇덴다.. 후후. 
 

간혹 어플을 만들고 나면 logcat 에서 다음과 같은 error 문구가 발생 하는 걸 볼 수 있다.

04-18 07:59:04.280: ERROR/Cursor(31526): Finalizing a Cursor that has not been deactivated or closed. 
 

(없으면 말고~) 위에 저 에러는 내가 발생 시킨건 아니고 어디서 퍼온거임.

여튼 이런 에러의 원인을 설명 해보자면 (나도 확실히 아는건 아님)
정확히 버전은 기억이 안나지만 아마 Froyo 부터 일듯 싶음.

Android 2.2 부터 Cursor 객체에 대한 GC를 보장 하지 않기 때문인 듯 사료됨.
무슨 뜻인고 하니 JAVA는 사용하다가 안쓰는 객체는 V 머신에서 free를 해주는 방법을 취하고 있는데.
정상 적이라면 android도 java니깐 dalvik 에서 우리가 안쓰는 객체를 free 하는 작업을 해주고 있는 거임.

근데 Cursor 객체는 지금 당장 사용 중이 아니라도 뭔가 목적을 위해 일부로 열어 둔것 일 수 도 있으니 dalvik 에서 인위 적으로 free 안해주겠다는 것임.
이렇게 되면 Activity는 끝났는데 cursor만 안끝나는 경우가 생김. 그러면 어케 되냐면 cursor 하나 때문에 activity 전체가 종료가 안되는 경우가 발생 할 수 있음 (순전히 내생각...)

그래서 따로 Cursor에 대해서 close 해달라고 난리 치는거임. 후훗~

일반적으로 cursor는 그냥 cursor.close() 이걸로 해결 되는데
문제는 ListView에 연결해 놓은 cursor 들임...
대부분 CursorAdapter 라던지 뭐 이런 것들로 처리를 했을 텐데.
close() 시키는 방법은 Activity라면 onDestroy() 가 적당 할 것임. (종료 하는 부분이 좋음)
무튼 onDestroy() 함수에다가 CursorAdapter 라던지 ListView라던지 객체를 얻어서 보통은
mList.getAdapter().getCursor().close(); 이러던가, mAdapter.getCursor().close();
이런식으로 종료를 처리함.

굉장히 허접하지만... 후훗~ 

'Android' 카테고리의 다른 글

Android Study ListView Indexer 1편  (0) 2012.03.07
LayoutInflater에 대하여...  (0) 2012.02.15
Android database 만들기 7편  (0) 2012.02.10
Android database 만들기 6편  (0) 2012.02.10
Android database 만들기 5편  (0) 2012.02.10
이전글 필요한분.

2012/02/10 - [Android Study] - Android database 만들기 6편 

변경 전
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        return null;
    }
변경 후 
    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {
        switch(Matcher.match(uri)){
        case KIND_DATA :
          // 질의 요청 Cursor 형태로 return 됨 그리고 좀 찾아보면 좋은거 있음
          // GroupBy, 라던지 Having이라던지 이런것도 가능 하게 해줌 
 
            return mPracticeDB.query(PRACTICE_TABLE, projection, selection, selectionArgs, null, null, sortOrder);
        default :
            return null;
        }
    }
 
변경 전
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
        return 0;
    }
변경 후 
    @Override
    public int update(Uri uri, ContentValues values, String selection,
            String[] selectionArgs) {
       // DB에 없뎃한 갯수 
        int count = 0;

        switch(Matcher.match(uri)){
        case KIND_DATA :
          // 질의 요청 DB에 업뎃요청
            count = mPracticeDB.update(PRACTICE_TABLE, values, selection, selectionArgs);
            break;
        default :
            count = 0;
        }
       // URI에 DB 갱신했다고 알려줌
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    } 

으캬~ 겨우 ContentProvider 다 완성 헀다.
이제 사용법이 궁금 하지 않음요?
 
DB 추가.
ContentValues values = new ContentValues();
        values.put(PracticeColumns.DATA, "Hello");
        Uri resutlUri = getContentResolver().insert(PracticeColumns.CONTENT_URI, values); 

DB 업데이트 (ID 값이 1번인 내용을 업데이트 할때)
ContentValues values = new ContentValues();
        values.put(PracticeColumns.DATA, "Android");
        int result = getContentResolver().update(PracticeColumns.CONTENT_URI, values,
                           PracticeColumns.ID + " = 1", null);
 
DB 삭제.  (ID 값이 1번인 내용을 삭제 할때) 
        int result = getContentResolver().delete(PracticeColumns.CONTENT_URI,
                          PracticeColumns.ID + " = 1", null);

DB 질문.
Cursor cursor = getContentResolver().query(PracticeColumns.CONTENT_URI,
               new String[] {PracticeColumns.ID, PracticeColumns.DATA}, null, null, null); 

요롷게 쓰면 된당께... 으흐흐. 

'Android' 카테고리의 다른 글

LayoutInflater에 대하여...  (0) 2012.02.15
Cursor close 해야 하는 이유와 하는 방법.  (2) 2012.02.14
Android database 만들기 6편  (0) 2012.02.10
Android database 만들기 5편  (0) 2012.02.10
Android database 만들기 4편  (0) 2012.02.10
이전글 필요 한사람.
2012/02/10 - [Android Study] - Android database 만들기 5편


흐앙 이제 URI로 내껀지 니껀지 구분 가능 해졌으니, 데이터 추가, 삭제, 갱신, 질의 이런거
추가 해봐야지~ 냥냥.. 


변경 전
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        return 0;
    }
변경 후
    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
       // 삭제 한 갯수 
        int count = 0;

        switch(Matcher.match(uri)) {
        case KIND_DATA :
          // database에 삭제 요청
            count = mPracticeDB.delete(PRACTICE_TABLE, selection, selectionArgs);
            break;
        }
       // uri에 DB 갱신했다고 알려줌
        getContext().getContentResolver().notifyChange(uri, null);
        return count;
    } 

변경 전
    @Override
    public String getType(Uri uri) {
        return null;
    }
변경 후 
    @Override
    public String getType(Uri uri) {
        switch(Matcher.match(uri)) {
        case KIND_DATA :
       // 해석 해보면 vnd는 mimeType 시작 문구이고
       // paracitce.cursor값이고 이 값은 
/data 디렉토리를 가리킴
       // 뭐대충 이런뜻임 dir 말고 item도 있음 
            return "vnd.practice.cursor.dir/data";
        default :
            return null;
        }
    } 

변경 전
    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }
변경 후 
    @Override
    public Uri insert(Uri uri, ContentValues values) {
       // 추가하고 리턴 받은 id값
        long id;

        switch(Matcher.match(uri)){
        case KIND_DATA :
          // Database에 추가.
            id = mPracticeDB.insert(PRACTICE_TABLE, null, values);
          // 완성된 URI 형태로 넘겨주기 위한 코드
            if( id > 0 ){
             // 정상대로 저장 했으면 uri에 noti를 해줌 DB 갱신 했다고 알려주는 것임
                Uri notiuri = ContentUris.withAppendedId(PracticeColumns.CONTENT_URI, id);
                getContext().getContentResolver().notifyChange(notiuri,null);
                return notiuri;
            }
            break;
        }
        return null;
    } 

움케케 너무 기니깐 담편으로 았싸 ㅋㅋ 12편 만들기 ㄱㄱㅆ ㅋㅋ 

'Android' 카테고리의 다른 글

Cursor close 해야 하는 이유와 하는 방법.  (2) 2012.02.14
Android database 만들기 7편  (0) 2012.02.10
Android database 만들기 5편  (0) 2012.02.10
Android database 만들기 4편  (0) 2012.02.10
Android database 만들기 3편  (0) 2012.02.10
전편... 필요한분
2012/02/10 - [Android Study] - Android database 만들기 4편 

아따 몹시 길구마이~

AndroidManifest 에 추가 해야 할 내용.

// 대충 설명하자면 Provider를 쓸껀데. Provider class 위치는 퍼랭이 글씨
// 지휘권? 같은 건데. 음 뭐랄까 내가 만들어 놓은 Provider class의 autorities 값이
// 빨갱이 글씨와 다르면 에러가 삑하고 남...
// 추가!! 내가 만든 provider 접근하려면 URI로 접근 해야하는데 그때 URI의 기본이
// 빨갱이 글씨임
// 예시 ) Uri.parser("content://com.practice.database/...");

    <provider android:name="com.android.provider.practice.AndroidProvider"
            android:authorities="com.practice.database"/>

위 내용까지 잘 정의 했다면 database 생성은 된것임.
그럼 data를 쓰고 지우고 갱신하는 code 작성이 매우 필요할 때임 ㅋㅋ 움케케케...
Android에서는 URI 라는 것으로 ContentProvider에 접근을 함.
접근을 하려면 일단은 URI 란 걸 구분 해야할 필요가 있음.
왜냐면 너도나도 URI를 쓰는데 내꺼는 뭔지 남꺼는 뭔지 구분해야 하지 않겠음??
곰곰히 생각해보면 아직 그런 코드 적어 준적이 없음... 고로 지금 부터 추가를 해야함.

4편에서 설명해준  private SQLiteDatabase mPracticeDB;  코드 밑에 다음 코드 추가요.

// UIR의 기본 string으로 사용됨. 위에  "com.practice.database와 같아야 함
private static final String AUTHORITIE = "com.practice.database";
// 나중에 Switch 문으로 사용될 구분값 (우리가 URI를 던지면 이 값으로 변경됨)
private static final int KIND_DATA = 1;
// URI를 던지면 AUTHORITIE 부분 제외하고 남은 부분을 가지고 INT 타입으로
// 변경 해주는 녀석. 
private static final UriMatcher Matcher;
static {
    Matcher = new UriMatcher(UriMatcher.NO_MATCH);
    Matcher.addURI(AUTHORITIE, "data", KIND_DATA);
}

너무 기니깐 담편으로 갑세다.. 

'Android' 카테고리의 다른 글

Android database 만들기 7편  (0) 2012.02.10
Android database 만들기 6편  (0) 2012.02.10
Android database 만들기 4편  (0) 2012.02.10
Android database 만들기 3편  (0) 2012.02.10
Android database 만들기 2편  (0) 2012.02.10
전편 필요 한분.
2012/02/10 - [Android Study] - Android database 만들기 3편 


기본 메소드 설명은 다했고 내부 class하고 interface 하고 변수 설명!!
자~ 들어 갑니다.

// android 내부 폴더에 저장 될 database 파일명
// 실제 위치는 /data/data/패키지명/databases/

private static final String DATABASE_NAME = "practice.db"; 
// Database 버전 ( DB upgrade와 관련있음)
// 숫자를 올리면 버전 업글 작업함.
private static final int DATABASE_VERSION = 1;
// Database 내부에 내가 쓸 table 명
private static final String PRACTICE_TABLE = "Practice";

// Database 객체
private SQLiteDatabase mPracticeDB;

// SQL문 쓸수 있게 해주는 class
private class PracticeDatabase extends SQLiteOpenHelper {
      // 생성자는 기본이니깐 버리고... 
        public PracticeDatabase(Context context, String name,
                CursorFactory factory, int version) {
            super(context, name, factory, version);
        }
 
     // 요기서 database 파일을 만듬
        @Override
        public void onCreate(SQLiteDatabase db) {
     // sql 명령어. 해석하면 "Practice라는 테이블을 생성하는데,
     // _id라는 놈은 정수 타입이고 기본 값이고 자동으로 증가 됨
     // data라는 놈은 text를 타입 임
            db.execSQL("create table " + PRACTICE_TABLE 
                    + " (" + PracticeColumns.ID + " integer primary key autoincrement, "
                    + PracticeColumns.DATA + " text);");
        }

     // 요기서 database 파일을 업뎃함
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
     // 해석하면 Practice 테이블이 있으면 버리고, 새로 만들어! 
            db.execSQL("DROP TABLE IF EXISTS " + PRACTICE_TABLE);
            onCreate(db);
        }
    }

   // 이거슨 컬럼을 좀 쉽게 쓰자는 배려!!
    public interface PracticeColumns {
     // 요고 붸리 임포턴트!! (내가 Practice 테이블로 접근 할수 있는 주소!)
     // 특히 빨간색 문구는 접근권한 구분 용도로 많이 쓰임
        public static final Uri CONTENT_URI = Uri.parse("content://com.practice.database/data");
     // id 컬럼 값
        public static final String ID = "_id";
     // data 컬럼 값
        public static final String DATA = "data";
    }

헥헥 좀 길다... 담편 ㄱㄱ

'Android' 카테고리의 다른 글

Android database 만들기 6편  (0) 2012.02.10
Android database 만들기 5편  (0) 2012.02.10
Android database 만들기 3편  (0) 2012.02.10
Android database 만들기 2편  (0) 2012.02.10
Android database 만들기 1편  (0) 2012.02.10

+ Recent posts