이 블로그 검색

2011년 10월 18일 화요일

안드로이드 DB 컴포넌트

 아래의 형태의 DB 컴포넌트를 따로 만들어서, DB를 사용을 객체를 통해 이루어지게 한다.
이렇게 하면 DB 사용이 깔끔해 진다.

Ex)

protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.search_bar);

dbAdapter = new DiscoverDbAdapter(getApplicationContext());
dbAdapter.open();
                ....................
                ..................
      }
    ............
    ............

     dbAdapter.insearchKeyword(dateFormat.format(calendar.getTime()), keyword);   
     ..................................


     ArrayList<String> lstHistory = dbAdapter.getHistory();
      ........................
      ........................
      dbAdapter.close();


}



public class DiscoverDbAdapter {
private static final String DATABASE_NAME = "discover_history.db";
private static final String TABLE_NAME = "search_history_discover";

private static final String HISTORY_DATE = "history_date";
private static final String HISTORY_SEARCH = "search_keyword";

private DatabaseHelper dbHelper;
private SQLiteDatabase db = null;
private Context context = null;

public DiscoverDbAdapter(Context context){
this.context = context;
}

/* open 메써드를 만들어서 dbHelper를 생성하고, 읽기&쓰기 속성을 준다.

public DiscoverDbAdapter open() throws SQLException{
dbHelper = new DatabaseHelper(context);
db = dbHelper.getWritableDatabase();

return this;
}

/* close 메써드를 만들어서 helper와 db 객체를 닫는다.

public void close(){
if(dbHelper != null) dbHelper.close();
if(db != null) db.close();
}

/* helper 클래쓰를 내부에 만든다.

private class DatabaseHelper extends SQLiteOpenHelper{

public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, 1); //version
}

/* 생성 함수 - Create Table
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + "(_id INTEGER PRIMARY KEY, " + HISTORY_DATE + " CHAR(14), " + HISTORY_SEARCH + " VARCHAR(30));");
}

/* Upgade 는 옵션
@Override
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {

}

}

/* 각종 DB를 사용하는 여러 Function 들(inSearchKeyWord(), getHistory(), ... 등등)을 메서드로 Adapter 내부에 선언해서,
객체를 호출 한 뒤, 메서들 사용하는 방식으로 쓴다. */
public void insearchKeyword(String date, String keyword){
Cursor c = db.rawQuery("SELECT * FROM " + TABLE_NAME, null);
if(c.getCount() > 9){
deleteHistory();
}
if(!keyword.trim().equals(""))
db.execSQL("INSERT INTO " + TABLE_NAME + "(" + HISTORY_DATE + ", " + HISTORY_SEARCH + ") values('" + date + "', '" + keyword + "');");
c.close();
}

private void deleteHistory(){
db.execSQL("DELETE FROM " + TABLE_NAME + " WHERE " + "_id" +"=(SELECT " + "_id" + " FROM " + TABLE_NAME + " ORDER BY " + HISTORY_DATE + " ASC LIMIT 1);");
}

public ArrayList<String> getHistory(){
ArrayList<String> lstHistory = new ArrayList<String>();

Cursor c = db.rawQuery("SELECT * FROM " + TABLE_NAME + " ORDER BY " + HISTORY_DATE + " DESC", null);
while(c.moveToNext()){
lstHistory.add(c.getString(c.getColumnIndex(HISTORY_SEARCH)));
}
c.close();
return lstHistory;
}
}

안드로이드 getTag(), setTag(object) 사용

커스텀 뷰를 만들 때,
커스텀 뷰에 객체의 Data를 집어 넣을 때 일일히 setXX, getXX 을 쓰지 않고,
setTag(dataObj), cView.getTag() 하면 된다.

Ex)
* setTag
mLayout.setTag(bookInfo);  // bookInfo 는 Book형의 인스턴스이고 mLayout은 커스텀 뷰이다.

// 예컨데 Book 형이 다음과 같다면,
class Book{
   String title;
   String author;
   String ISBN;
   int version;
}

mLayout에 title, author, ISBN, version 등의 값을 bookInfo에 넘겨서 한번에 넘겨 줄 수 있다.

* getTag
Book bookInfo = (Book)mLayout.getTag();

요렇게 하면 mLayout에 set 되어 있던 book 형 값들을 가져올 수 있다.

update, delete 구문

일일히 루프 돌면서 작업 안해줘도 where 조건 없으면 모든 Table의 item에 적용 됨.
이런 간단한 것도 모르면, 엄청 해멘다..

Ex)
  db.execSQL("update WishList set deleteCheck = 'false' ");

모든 WishList Table의 deleteCheck 필드의 값을 전부 false 로 바꾼다.
일일히 커서로 돌리면서 바꿀 필요 없다.

쓰레드 사용 - ANR 방지

기본적인 쓰레드 사용
1. new Thread(new Runnable()).

2. run() 안쪽에 멀티 쓰레드로 처리할(메인 쓰레드에서 뺄 작업) 로직 삽입.
3. Handler 객체에 sendEmptyMessage()로 전달
4. 핸들러 객체 따로 구현, handleMessage() 내에 UI 작업 삽입.


<싱글 쓰레드의 경우>
----> 싱글 쓰레드(main 쓰레드) ---> 입력 UI --> [Data 처리 - Ex)서버 연동, DB 연동 etc ] --> 화면 출력 이 과정에서 ANR 발생 (UI무응답)


<멀티 쓰레드를 이용하는 경우>
----> 싱글 쓰레드(main 쓰레드) ---> 입력 UI --> --> 화면 출력
멀티 쓰레드 ---> [Data 처리 - Ex)서버 연동, DB 연동 etc ]


public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
     
        setContentView(R.layout.act_setup_friendrecommend);

        dialog1 = DialogUtils.createProgressDialog(this, "gringphone06_01");

new Thread(new Runnable(){
public void run(){
init();   <-- Data 처리 등 시간이 많이 걸리는 부분
mHandler.sendEmptyMessage(0);
}
}).start();
    }


Handler mHandler = new Handler()
{
public void handleMessage(Message msg)
{
switch(msg.what)
{
case 0:
btnRecommend.setText(StringUtils.getString(Act_Setup_FriendRecommend.this, "recommend"));
lvSelectList.setAdapter(selectPersonListAdapter);    <-- UI 처리 부분

break;
}
}
};

2011년 10월 11일 화요일

딜레이 주기

Handler mHandler = new Handler();
mHandler.postDelayed(new Runnable() {
        public void run()
        {
        Util.log("delay"); 
        }
       }, 500); //Delay time

2011년 10월 10일 월요일

프로그래밍 문제 해결 팁 1

거의 비슷한 뷰를 복사해서 쓴 적이 있는데
플리킹이 한 쪽은 되고 한 쪽은 되지 않은 적이 있었다.

이 문제를 해결하느라 엄청 삽질을 했느데,
결국 해결의 실마리는 로그캣에 많은 로그를 남기는 것이었다.
전혀 상관없어 보이는 코드에도 로그를 쓰고 비교를 해보니...
문제가 생긴 쪽에는 플리킹을 할 때마다
getView 호출하는 코드를 더 추가적으로 넣은 것을 알았다.
따라서 플리킹을 할 때마다 계속해서 getView를 호출하다 보니 이미지들이 움직일 수가
없는 것이었다.

로그가 없었으면 이 문제를 발견할 수 없었을 듯 하다.
정 안될 때는 상관없어 보이는 코드에도 밑져야 본전이니 로그를 남겨둬 보자..
자신이 전혀 짐작하지 못한 의외에 곳에서 한 실수를 찾을 수 있다.

2011년 10월 9일 일요일

안드로이드 리스트 복사

각종 리스트(ArrayList 등 포함)를 통째로 똑같이 복사하려면
addAll 메써드를 써야 한다.

예를들어,
ArrayList<String>sList = new ArrayList<String>();
sList.add("a");
sList.add("b");
sList.add("c");
sList.add("d");
 
ArrayList<String>tList = new ArrayList<String>();

tList = sList; (X) <-- 이런식으로 하면 안된다.. 왜냐면 tList가 변함에 따라 sList도 변한다.

tList.addAll(sList); (O)  <--- 이렇게 해야 한다. 

tList.add("e");  <-- 이럼에 따라, sList에도 "e","f" 가 추가된다.
tList.add("f");          왜냐면 tList = sList 하면 두 리스트의 주소값을 공유하게 되기 때문이다.