한국어

네트워킹

온누리070 플레이스토어 다운로드
    acrobits softphone
     온누리 070 카카오 프러스 친구추가온누리 070 카카오 프러스 친구추가친추
     카카오톡 채팅 상담 카카오톡 채팅 상담카톡
    
     라인상담
     라인으로 공유

     페북공유

   ◎위챗 : speedseoul


  
     PAYPAL
     
     PRICE
     

pixel.gif

    before pay call 0088 from app


https://arabiannight.tistory.com/entry/368?category=476074


안드로이드/Android DB 생성 및 관리 ( Cursor , Query )

안드로이드 프로젝트를 진행하다 보면 DATA를 보관하고 사용하게 되는 경우가 자주 발생하게 됩니다. 보통 회원가입을 통해 회원정보를 저장할때 많이 사용하는데요. 그럴경우 DATA를 계속적으로 보관하고 사용해야 하기 때문에 DATABASE(=DB) 라는 저장공간에을 사용하게 되는 것 입니다.

안드로이드에서는 이러한 경우를 대비해 SQLiteDatabase라는 DATABASE 를 제공해 주는데요. 만약 DATA를 저장해서 사용하게 되는 경우가 생길 경우 
 SQLiteDatabase 와 DatabaseHelper(DB생성 및 관리를 도와준다.) 를 사용해서 좀더 편리하게 DATABASE를 관리 할 수 있습니다.

DB를 사용하기 위해서는 우선 어떤 작업을 제일 먼저 해야할까요? 그렇습니다.ㅎ 일단 DB를 사용하기 위해서는 DB를 생성해야 합니다. DB는 TABLE 구조로 DATA를 관리하고있으므로 우선대야 할 작업이 TABLE 구조를 만드는 일입니다. 자 그럼 TABLE 구조를 만드는 코드를 보겠습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// DataBase Table
public final class DataBases {
     
    public static final class CreateDB implements BaseColumns{
        public static final String NAME = "name";
        public static final String CONTACT = "contact";
        public static final String EMAIL = "email";
        public static final String _TABLENAME = "address";
        public static final String _CREATE =
            "create table "+_TABLENAME+"("
                    +_ID+" integer primary key autoincrement, "    
                    +NAME+" text not null , "
                    +CONTACT+" text not null , "
                    +EMAIL+" text not null );";
    }
}




여기서 주의해서 보실 부분중에 
 autoincrement 란 속성이 있습니다. autoincrement 란 속성은 DATA를 DB에 넣을때 자동으로 "+1" 을 증가 시켜주는 주어 DATA를 식별 할 수 있는 고유 번호를 부여하는 속성 입니다. 위의 예제에서는 "_id" 라는 필드에 사용 되었습니다.





실제 위의 코드로 생성한 DB 테이블(address) 구조 입니다.
RecNo은 DB Tool 자체의 Number코드이니 "_id" 필드 부터 보시면 됩니다. 또한 "_id" 필드의 값이 +1씩 자동 증가한 모습을 볼 수 있습니다.




자 그럼, DB TABLE 구조에 대해 알아보았습니다. 다음은 
SQLiteDatabase 와  DatabaseHelper 를 통한 DB 관리 예제 설명 하겠습니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class DbOpenHelper {
 
    private static final String DATABASE_NAME = "addressbook.db";
    private static final int DATABASE_VERSION = 1;
    public static SQLiteDatabase mDB;
    private DatabaseHelper mDBHelper;
    private Context mCtx;
 
    private class DatabaseHelper extends SQLiteOpenHelper{
 
        // 생성자
        public DatabaseHelper(Context context, String name,
                CursorFactory factory, int version) {
            super(context, name, factory, version);
        }
 
        // 최초 DB를 만들때 한번만 호출된다.
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(DataBases.CreateDB._CREATE);
 
        }
 
        // 버전이 업데이트 되었을 경우 DB를 다시 만들어 준다.
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            db.execSQL("DROP TABLE IF EXISTS "+DataBases.CreateDB._TABLENAME);
            onCreate(db);
        }
    }
 
    public DbOpenHelper(Context context){
        this.mCtx = context;
    }
 
    public DbOpenHelper open() throws SQLException{
        mDBHelper = new DatabaseHelper(mCtx, DATABASE_NAME, null, DATABASE_VERSION);
        mDB = mDBHelper.getWritableDatabase();
        return this;
    }
 
    public void close(){
        mDB.close();
    }
 
}


위의 예제 소스에서 보시는 바와 같이,


 
onCreate(SQLiteDatabase db) : 최초 DB를 만들때 한번만 호출됩니다.

onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) : 버전이 업데이트 되었을 
경우 DB를 다시 만들어 줍니다. DATABASE_VERSION = 1, 2, 3 이런식으로 수정해 주시면 자동
으로 기존의 TABLE을 삭제하고 새로운 TABLE을 만들어 줍니다.

getWritableDatabase()  :  DB를 사용하기위해 생성하거나 열어 줍니다.
DB를 읽거나 쓸수 있는 권한을 부여 합니다.


 





다음은 DB를 사용하는 ACTIVITY 화면 입니다. 실제 사용자가 DB에 DATA를 저장, 삭제, 갱신, 조회 등의 작업을 수행하는 클래스 입니다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
public class TestDataBaseActivity extends Activity {
     
    private static final String TAG = "TestDataBaseActivity";
    private DbOpenHelper mDbOpenHelper;
    private Cursor mCursor;
    private InfoClass mInfoClass;
    private ArrayList<infoclass> mInfoArray;
    private CustomAdapter mAdapter;
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
         
        setLayout();
         
        // DB Create and Open
        mDbOpenHelper = new DbOpenHelper(this);
        mDbOpenHelper.open();
         
        mDbOpenHelper.insertColumn("김태희","01000001111" , "angel@google.com");
        mDbOpenHelper.insertColumn("송혜교","01333331111" , "asdffff@emdo.com");
        mDbOpenHelper.insertColumn("낸시랭","01234001111" , "yaya@hhh.com");
        mDbOpenHelper.insertColumn("제시카","01600001111" , "tree777@atat.com");
        mDbOpenHelper.insertColumn("성유리","01700001111" , "tiger@tttt.com");
        mDbOpenHelper.insertColumn("김태우","01800001111" , "gril@zzz.com");
         
//        startManagingCursor(mCursor);
         
         
        mInfoArray = new ArrayList<infoclass>();
         
        doWhileCursorToArray();
         
        for(InfoClass i : mInfoArray){
            DLog.d(TAG, "ID = " + i._id);
            DLog.d(TAG, "name = " + i.name);
            DLog.d(TAG, "contact = " + i.contact);
            DLog.d(TAG, "email = " + i.email);
        }
         
        mAdapter = new CustomAdapter(this, mInfoArray);
        mListView.setAdapter(mAdapter);
        mListView.setOnItemLongClickListener(longClickListener);
         
    }
     
    @Override
    protected void onDestroy() {
        mDbOpenHelper.close();
        super.onDestroy();
    }
     
     
    /**
     * ListView의 Item을 롱클릭 할때 호출 ( 선택한 아이템의 DB 컬럼과 Data를 삭제 한다. )
     */
    private OnItemLongClickListener longClickListener = new OnItemLongClickListener() {
        @Override
        public boolean onItemLongClick(AdapterView<!--?--> arg0, View arg1,
                int position, long arg3) {
             
            DLog.e(TAG, "position = " + position);
             
            boolean result = mDbOpenHelper.deleteColumn(position + 1);
            DLog.e(TAG, "result = " + result);
             
            if(result){
                mInfoArray.remove(position);
                mAdapter.setArrayList(mInfoArray);
                mAdapter.notifyDataSetChanged();
            }else {
                Toast.makeText(getApplicationContext(), "INDEX를 확인해 주세요.",
                        Toast.LENGTH_LONG).show();
            }
             
            return false;
        }
    };
     
     
    /**
     * DB에서 받아온 값을 ArrayList에 Add
     */
    private void doWhileCursorToArray(){
         
        mCursor = null;
        mCursor = mDbOpenHelper.getAllColumns();
        DLog.e(TAG, "COUNT = " + mCursor.getCount());
         
        while (mCursor.moveToNext()) {
             
            mInfoClass = new InfoClass(
                    mCursor.getInt(mCursor.getColumnIndex("_id")),
                    mCursor.getString(mCursor.getColumnIndex("name")),
                    mCursor.getString(mCursor.getColumnIndex("contact")),
                    mCursor.getString(mCursor.getColumnIndex("email"))
                    );
             
            mInfoArray.add(mInfoClass);
        }
         
        mCursor.close();
    }
     
     
    /**
     * OnClick Button
     * @param v
     */
    public void onClick(View v){
        switch (v.getId()) {
        case R.id.btn_add:
            mDbOpenHelper.insertColumn
                    (
                    mEditTexts[Constants.NAME].getText().toString().trim(),
                    mEditTexts[Constants.CONTACT].getText().toString().trim(),
                    mEditTexts[Constants.EMAIL].getText().toString().trim()
                    );
             
            mInfoArray.clear();
             
            doWhileCursorToArray();
             
            mAdapter.setArrayList(mInfoArray);         
            mAdapter.notifyDataSetChanged();
             
            mCursor.close();
             
            break;
 
        default:
            break;
        }
    }
     
    /*
     * Layout
     */
    private EditText[] mEditTexts;
    private ListView mListView;
     
    private void setLayout(){
        mEditTexts = new EditText[]{
                (EditText)findViewById(R.id.et_name),
                (EditText)findViewById(R.id.et_contact),
                (EditText)findViewById(R.id.et_email)
        };
         
        mListView = (ListView) findViewById(R.id.lv_list);
    }
}
</infoclass></infoclass>


위의 코드는 사용자가 직접 입력한 값을 DB에 추가하고, ListView에 뿌려주고 있으며, 또한 사용자가 ListView의 Item을 롱클릭 하였을 경우, Item을 DB와 ListView에서 삭제 시켜주는 코드 입니다.






이런 형식으로 짜여진 코드 입니다. 그런데 테스트 도중 아주 중요한 문제점을 하나 발견 했습니다. 바로 ListView의 Item을 롱클릭해서 DB와 Adapter의 DATA를 지우는 도중에 자동증가된 "_id" 의 값이 ArrayList의 포지션값과 다르다는 것을... 읔..

쉽게말해 ArrayList는 해당 Position을 지우면, 1,2,3,4,5 중 4를 지우면 자동으로 1,2,3,4로 포지션이 재할당 됩니다. (5번 포지션이 4번으로 바뀌는 것이죠.) 그런데 "_id" 속성은 DATA를 DB에 삽입 할 때 마다 +1을 증가시키지만, 마찬가지로 1,2,3,4,5 번중에 4번을 지우면 1,2,3,5 의 index를 가지게 된다는 말입니다.


이렇듯 말이죠.

 

 
그러므로 위의 index값이 일치하지 않는 문제를 가지고 있는 코드 입니다. 헐. 그럼 DATA를 삭제 할 수 없는 것일까요? ㅎㅎ그렇지 않습니다. 주민등록 번호나 전화번호 처럼 고유한 값을 가지고 DATA 삭제 처리를 해주면 됩니다. 주민등록번호나 전화번호는 전세계 하나밖에 없는 고유한 번호이기 때문에 해당 번호를 지우게 되도 중복으로 지워지는 일을 방지 할 수 있습니다.


자 그럼, 코드에 대해 마자 분석을 해보겠습니다.




우선 DB에서 값을 받아오는 Cursor라는 녀석이 있습니다.
DB 테이블에 담긴 DATA를 받아오는 Cousor는 SQLiteDatabase 의

query(DataBases.CreateDB._TABLENAME, null, null, null, null, null, null);
매개인자 별로 테이블, 컬럼, 선택값, 선택값배열, 그룹, 조건절, 정렬등을 지정해 쿼리를 좀더 편리하게 쓸 수 있도록 하는 메서드 입니다.

rawQuery( "select * from address where name=" + "'" + name + "'" , null);
평소에 많이 보았던 전체 쿼리로 DATA를 다루는 메서드 입니다.

의 속성을 이용해서 DATA를 받아 올 수 있습니다.

커서를 이용해 해당 필드를 조회 하는 방법 입니다.

mCursor.getInt(mCursor.getColumnIndex("_id")),
mCursor.getString(mCursor.getColumnIndex("name")),
mCursor.getString(mCursor.getColumnIndex("contact")),
mCursor.getString(mCursor.getColumnIndex("email"))

해당 필드에 대한 값을 int, String 으로 얻어 올 수 있습니다.

또한 While 문며 ArrayList에 DaTa를 Add 시킬때,
mCursor.moveToNext() 란 속성을 이용했는데요. 이 속성은 커서가 다음 행에 커서를 이동 시키는 방법 입니다. 커서의 마지막 행까지 루프를 돌게 되는 방법 입니다.

startManagingCursor(mCursor) 란 속성은 Activity 딴에서 커서를 관리해 주는 메서드 입니다. 커서를 Close 하지 않고 이동하거나 하는 경우 메모리 문제와 오류가 발생 할 수 있기때문에 Activity 주기에 따라 커서를 Open , Close 해주는 아주 고마운 메서드인 셈 입니다.
(BUT, 그러나 Cursor객체는 DB에서 값을 받아온 후 바로 Close 해주는게 좋습니다. Cursor 객체가 할당하고 있는 메모리를 생각해서 말이죠.) 


mAdapter.notifyDataSetChanged() 이 메서드 역시 굉장히 중요한 메서드 입니다. ListView에 뿌려지는 Data들을 관리해주는 Adapter에게 "Data의 변동이 있으니 변경 사항을 적용해라." 라고 알려주는 메서드 입니다. 이 메서드를 호출 해야만 Data의 추가, 삭제가 ListView를 통해 보여지게 되니 정말로 중요한 메서드 입니다.









이렇게 해서 DB 관리 및 생성에 대해 알아 보았는데요. 간단하게 포스팅 할려고 했던게 너무 길어 지고 피곤한 하루 였기 때문에 설명에 호의적이지 못한 부분도 간혹(?) 있었던 거 같네요 ㅎㅎ 아무튼 끝까지 봐주셔서 감사하고 유용하게 사용 하셨으면 좋겠습니다. 

 오늘도, 건강한 하루 즐거운 하루 잘 마무리 하시구요!!
다음 포스팅때 뵙겠습니다.






파일첨부 :








출처 : 커니의 안드로이드 이야기 DB 예제 소스
URL :  http://androidhuman.tistory.com/ 


 

 


 






댓글 
  • 이전 댓글 더보기
  • 프로필사진알고싶은사람인데Your project contains error(s), please fix them before running your application. -> 실행 하면 이 오류뜹니다.

    Project has no project.properties file! Edit the project properties to set one. -> problem 입니다.
    2013.01.18 05:16
  • 프로필사진brightstar7777http://starkapin.tistory.com/394

    요사이트 한번 참고해 보실래요?
    2013.01.19 15:05
  • 프로필사진안녕하세요안녕하세요. 좋은 정보 잘보고갑니다.
    DB를 처음 시작해서 혹시나 메인에서 DB의 ID값을 이용하여 contact의 값만 호출할수 있나요?
    - id값을 이용해서 contact 내용을 받고 그걸 비교해서 update하게 하려고 하는데 ..
    잘모르겠습니다.. ㅠㅠ
    2013.02.05 13:58
  • 프로필사진아라비안왕자DBHelper Class에 select문 qurey 사용하는 부분이 있는데 그 부분을 id를 받아서 select contact from table ~~~~ 형식으로 사용하시면 됩니다.^^;; 답변이 늦어서 죄송하네요. 못봤네요 흑흑2013.04.08 23:12 신고
  • 프로필사진감사합니당담아가겠습니다~^^2013.03.22 11:59
  • 프로필사진아라비안왕자네^^ 감사합니다.2013.04.08 23:10 신고
  • 프로필사진감사요처음 접하는 저로썬 많은 도움되었습니다 감사합니다.^^2013.05.26 20:36
  • 프로필사진이지연안녕하세요 도움 많이 받았습니다! 그런데 DB 테이블은 어떻게 보나요?_?2013.05.30 18:33
  • 프로필사진나그네여러 방법이 있습니다만, 에뮬레이터라면 http://yangtaeho.tistory.com/54 여기 보셔도 되고.
    디바이스에 바로 보실려면 root권한이 필요하고요.
    직접 검색해보심이 좋을듯하네요
    2014.11.04 16:49
  • 프로필사진혀비아~ 너무 감사합니다. ㅜㅜ 메마른 사막에서 오아시스를 만난 기분입니다.2013.06.10 13:04
  • 프로필사진JunkMan좋은 정보 감사합니다.2013.06.26 18:56
  • 프로필사진비밀댓글입니다2013.09.16 18:19
  • 프로필사진맹구와부시맨삭제소스코드좀 알려주세요. 생초보라 자세하게 설명부탁요2013.11.04 21:11
  • 프로필사진Min잘보고 갑니더~2013.11.12 21:06
  • 프로필사진공대인이거 끄고 킬떄마다 리스트가 두배가 되는데 어케조절할수 있을까요
    2013.11.13 12:06
  • 프로필사진나그네TestDataBaseActivity에서 onCreate 할때마다 db에 저장되니 종료-실행 반복된 횟수만큼 저장되요. mDbOpenHelper.getAllColumns(); 해주시던지 아님 mDbOpenHelper.insertColumn(~)삭제해 주시면 될듯하네요.2014.11.04 16:26
  • 프로필사진이영완학교에서 텀프로젝트로 디비를 연동한 클라우딩서비스어플을 만드는거 하는 중인데요.. 저같이 초보를 위해서 정말 친절한 설명 감사드려요...ㅠㅠ 아 엄청난 은혜를 경험한 듯 하네요.2013.11.29 15:43
  • 프로필사진;;;;;InfoClass랑 CustomAdapter 는 뭘 import 시켜줘야하나요2013.11.30 18:46
  • 프로필사진나그네무슨말인지 모르겠네요..2014.11.04 16:29
  • 프로필사진이종수저는 db생성에서 table안에 table을 넣고 싶인데 create함수 부분과 데이터 읽고/쓰는 곳에서의 함수 사용방법좀알려주세요2013.12.21 12:56
  • 프로필사진김현일정말 좋은 내용인거 같습니다. 근대 가장 궁금한 것이 해당 데이터베이스는 어디에 저장이 되어 있는 것 인가요??2014.02.07 22:03
  • 프로필사진나그네/data/data/패키지명/databases/에 저장됩니다.
    ---------
    data폴더안에 또 data폴더 있습니다.
    2014.11.04 16:36
  • 프로필사진비밀댓글입니다2014.09.04 15:11
  • 프로필사진나그네안드로이드앱개발하는데, 아직 미숙한지라 아라비안나이트님 블로그에 와서 공부하다 갑니다^^
    앞으로도 좋은 포스팅 기대하겠습니다. 감사합니다!
    2014.11.04 16:45
  • 프로필사진모르겠어요작성자님 이 파일 그대로 임포트 하여 위의 수정부분까지 수정하였는데 모든 소스들에 x가 되어있고, can not be resolved 등과같은 이유로 오류가 떠서 run as가 되지 않는데 저 소스파일을 다운받아서 오류부분 수정하고 그대로 사용하기 전에 다른 걸 해야 하는건가요? 왜 안되는지 알려주시면 감사합니다.2014.12.02 19:36
  • 프로필사진비밀댓글입니다2016.10.27 02:57
  • 프로필사진알고싶은사람잘 보았습니다.
    한가지 의문이 있는데 안드로이드시스템에서는 디비를 어디에 두고 관리하는가요?
    시스템자체내에서 관리하는가요, 아니면 어떤 private storage에서 관리하는가요?
    2017.07.02 18:35



출처: https://arabiannight.tistory.com/68 [아라비안나이트]

조회 수 :
13433
등록일 :
2019.10.14
23:04:45 (*.214.125.21)
엮인글 :
http://webs.co.kr/index.php?document_srl=3320678&act=trackback&key=560
게시글 주소 :
http://webs.co.kr/index.php?document_srl=3320678
List of Articles
번호 제목 글쓴이 날짜 조회 수
67 Mysql FOREIGN KEY admin 2020-02-16 10299
66 mysql db tables 별로 데이타 사용량 확인 쿼리 admin 2020-02-12 13152
65 [SQL] 테이블 안의 컬럼 값 변경, 수정, UPDATE admin 2019-10-21 19105
64 [Android] 안드로이드 - SQLiteDatabase 구현하기 admin 2019-10-14 14100
» [유용][실전]Android DB 생성 및 관리 ( Cursor , Query ) 리스트뷰 admin 2019-10-14 13433
62 간단한 Android Sqlite 예제 ( DB생성,테이블 생성, 데이터 입력, 테이터 보여주기) admin 2019-10-14 12598
61 [안드로이드] SQLiteDatabase와 SQLiteOpenHelper 사용법 예제 admin 2019-10-14 14621
60 두테이블비교 한쪽에 없는 값 추출 mysql left right outer join 서브쿼리 값사용 admin 2019-07-10 28358
59 원격 IP로 MySQL(MariaDB)에 접속 방법 해법 설정 순서 admin 2019-06-19 27029
58 oracle download install 오라클 다운로드 설치 admin 2018-05-29 18882
57 숫자 날짜 문자열 문자 공간 JSON MySQL 자료형 총 정리 phpMyAdmin 자료형 admin 2018-03-26 20572
56 mysql procedure admin 2017-11-16 18838
55 Sqlite very detail easy tutorial I recommand this admin 2017-09-09 20893
54 mysql 로컬접속 풀고 특정 아이피 접속 허가 허락 가능 하게 설정 하는 방법 admin 2017-09-05 22082
53 linux command chmod 리눅스 명령어 가장 쉽게 이해하기 설명 사용자 구룹 타인 권한 admin 2017-09-05 22542
52 mariadb CREATE USER CREATE USER statement creates new MariaDB accounts. admin 2017-09-01 69676
51 MySQL 데이터 베이스 백업 및 복구 방법 admin 2017-09-01 22302
50 Allowing MySQL Root Login from All IP Addresses : admin 2017-08-17 34325
49 Installation of MySQL Database Server admin 2017-08-17 20040
48 mysql 쿼리 로그 남기기 (실시간) admin 2015-04-15 26316
47 SQL Delete records using subqueries admin 2015-04-03 25731
46 Mysql privilege table GRANT SELECT,INSERT,UPDATE,DELETE ON db.table admin 2015-04-02 23412
45 안드로이드 SQLite 속도 향상! insert Transaction admin 2014-04-07 43623
44 MySQL에 원격 접속 허용 여러가지 아이피 아이피대역으로 admin 2014-04-02 134916
43 10gR2_sles10_install file admin 2014-03-18 27924
42 this is final answer assets sqlite Databases trouble copy External DB, check eclips admin 2014-02-18 32834
41 Browse SQLite data on the Android emulator admin 2014-02-15 36857
40 SQLite Database Browser file admin 2014-02-14 34436
39 SQLite Databases using External DB admin 2014-02-14 38121
38 sqlite DB copy admin 2014-02-14 35422