-
[Android Studio] SQLite을 이용한 내장 DB 활용하기개발 끄적끄적/Android 2020. 6. 5. 01:08반응형
안드로이드에서는 어플리케이션의 효과적인 데이터 관리를 위해 내부 SQL Database인 SQLite Database를 지원합니다. 이를 이용해 용량이 크지 않은 데이터는 서버 통신 필요 없이 관리할 수 있습니다.
SQLite을 이용해 번호, 이름, 수량 세 정보를 지니고 있는 데이터 값들을 저장, 수정, 조회, 삭제해 보았습니다. 코드를 보며 하나하나 설명 드리겠습니다.
ItemData.kt
class ItemData (val pid:Int, val pName :String, val pQuantity:Int)
번호, 이름, 수량 세 정보를 지닌 데이터 클래스를 선언합니다.
MyDBHelper.kt
import android.content.ContentValues import android.content.Context import android.database.Cursor import android.database.sqlite.SQLiteDatabase import android.database.sqlite.SQLiteOpenHelper import android.graphics.Color import android.view.Gravity import android.widget.TableRow import android.widget.TextView import kotlinx.android.synthetic.main.activity_main.* class MyDBHelper(val context: Context?):SQLiteOpenHelper(context, DB_NAME, null, DB_VERSION) { companion object{ val DB_VERSION = 1 val DB_NAME = "mydb.db" val TABLE_NAME = "itemDatas" val PID = "pid" val PNAME = "pname" val PQUANTITY = "pquantity" } override fun onCreate(p0: SQLiteDatabase?) { val create_table = "create table if not exists $TABLE_NAME($PID" + " integer primary key autoincrement, $PNAME text, $PQUANTITY integer)" p0?.execSQL(create_table) } override fun onUpgrade(p0: SQLiteDatabase?, p1: Int, p2: Int) { val drop_table = "drop table if exists $TABLE_NAME" p0?.execSQL(drop_table) onCreate(p0) } fun insertProduct(itemData:ItemData):Boolean{ val values = ContentValues() values.put(PNAME, itemData.pName) values.put(PQUANTITY, itemData.pQuantity) val db = this.writableDatabase if(db.insert(TABLE_NAME, null, values) > 0){ val activity = context as MainActivity activity.pIdEdit.setText("") activity.pNameEdit.setText("") activity.pQuantityEdit.setText("") db.close() return true }else{ db.close() return false } } fun updateProduct(itemData:ItemData):Boolean{ val strsql = "select * from $TABLE_NAME where $PID = \'${itemData.pid}\'" val db = this.writableDatabase val cursor = db.rawQuery(strsql, null) if(cursor.moveToFirst()) { val values = ContentValues() values.put(PNAME, itemData.pName) values.put(PQUANTITY, itemData.pQuantity) db.update(TABLE_NAME, values, PID+"=?", arrayOf(itemData.pid.toString())) val activity = context as MainActivity activity.pIdEdit.setText("") activity.pNameEdit.setText("") activity.pQuantityEdit.setText("") cursor.close() db.close() return true } cursor.close() db.close() return false } fun deleteProduct(pid:String):Boolean{ val strsql = "select * from $TABLE_NAME where $PID = \'$pid\'" val db = this.writableDatabase val cursor = db.rawQuery(strsql, null) if(cursor.moveToFirst()){ db.delete(TABLE_NAME, PID+"=?", arrayOf(pid)) val activity = context as MainActivity activity.pIdEdit.setText("") activity.pNameEdit.setText("") activity.pQuantityEdit.setText("") cursor.close() db.close() return true } cursor.close() db.close() return false } fun findProduct(pname:String):Boolean{ val strsql = "select * from $TABLE_NAME where $PNAME = \'$pname\'" val db = this.readableDatabase val cursor = db.rawQuery(strsql, null) if(cursor.count != 0){ showRecord(cursor) cursor.close() db.close() return true } cursor.close() db.close() return false } fun findProduct2(pname:String):Boolean{ val strsql = "select * from $TABLE_NAME where $PNAME like \'$pname%\'" val db = this.readableDatabase val cursor = db.rawQuery(strsql, null) if(cursor.count != 0){ showRecord(cursor) cursor.close() db.close() return true } cursor.close() db.close() return false } fun getAllRecord(){ val strsql = "select * from $TABLE_NAME" val db = this.readableDatabase val cursor = db.rawQuery(strsql, null) if(cursor.count != 0){ showRecord(cursor) } cursor.close() db.close() } fun showRecord(cursor:Cursor){ cursor.moveToFirst() val count = cursor.columnCount val recordCount = cursor.count val activity = context as MainActivity activity.tableLayout.removeAllViews() //컬럼 타이틀 만들기 val tableRow = TableRow(activity) val rowParam = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT, count.toFloat()) tableRow.layoutParams = rowParam val viewParam = TableRow.LayoutParams(0,100,1f) for(i in 0 until count){ val textView = TextView(activity) textView.layoutParams = viewParam textView.text = cursor.getColumnName(i) textView.setBackgroundColor(Color.LTGRAY) textView.textSize = 15.0f textView.gravity = Gravity.CENTER tableRow.addView(textView) } activity.tableLayout.addView(tableRow) //실제 레코드 읽기 do{ val row = TableRow(activity) row.layoutParams = rowParam row.setOnClickListener{ for(i in 0 until count){ val txtView = row.getChildAt(i) as TextView when(txtView.tag){ 0 -> activity.pIdEdit.setText(txtView.text) 1 -> activity.pNameEdit.setText(txtView.text) 2 -> activity.pQuantityEdit.setText(txtView.text) } } } for(i in 0 until count){ val textView = TextView(activity) textView.layoutParams = viewParam textView.text = cursor.getString(i) textView.textSize = 13.0f textView.tag = i row.addView(textView) } activity.tableLayout.addView(row) }while(cursor.moveToNext()) } }
- onCreate() : TABLE_NAME 이 존재하지 않으면 테이블 생성
- onUpgrade() : 정보를 변경할 때 drop table 후 onCreate()를 호출해 테이블 생성
- insertProduct() : data insert 후 MainActivity로부터 context를 받아 3개의 EditText 값 초기화
- updateProduct() : itemData.pid 값을 바탕으로 data를 찾아 값을 변화시킴
- deleteProduct() : pid값을 바탕으로 data를 찾아 값을 제거함
- findProduct() : pname값을 바탕으로(완전히 일치) data를 찾아 showRecord() 호출
- findProduct2() : pname값을 바탕으로(pname 포함 여부) data를 찾아 showRecord() 호출
- getAllRecord() : TABLE_NAME 에서 데이터를 불러와 showRecord() 호출
- showRecord() : 전달 받은 데이터를 MainActivity의 tableLayout에 추가. row를 추가하며 setOnClickListener를 달아 클릭 시 MainActivity의 EditText의 text값을 변화시킴. Delete, Update를 편하게 하기 위함
MainActivity.kt
fun init(){ myDBHelper = MyDBHelper(this) insertBtn.setOnClickListener { val quantity = pQuantityEdit.text.toString().toInt() val name = pNameEdit.text.toString() val product = ItemData(0, name, quantity) val result = myDBHelper.insertProduct(product) if(result){ Toast.makeText(this, "DB Insert success", Toast.LENGTH_SHORT).show() getAllRecord() }else{ Toast.makeText(this, "DB Insert failed", Toast.LENGTH_SHORT).show() } } deleteBtn.setOnClickListener { val result = myDBHelper.deleteProduct(pIdEdit.text.toString()) if(result){ Toast.makeText(this, "DELETE success", Toast.LENGTH_SHORT).show() getAllRecord() }else{ Toast.makeText(this, "DELETE FAILED", Toast.LENGTH_SHORT).show() } } updateBtn.setOnClickListener { val id = pIdEdit.text.toString().toInt() val quantity = pQuantityEdit.text.toString().toInt() val name = pNameEdit.text.toString() val product = ItemData(id, name, quantity) val result = myDBHelper.updateProduct(product) if(result){ Toast.makeText(this, "update success", Toast.LENGTH_SHORT).show() getAllRecord() }else{ Toast.makeText(this, "update failed", Toast.LENGTH_SHORT).show() } } findBtn.setOnClickListener { val name = pNameEdit.text.toString() val result = myDBHelper.findProduct(name) if(result){ Toast.makeText(this, "RECORD found", Toast.LENGTH_SHORT).show() }else{ Toast.makeText(this, "NO match found", Toast.LENGTH_SHORT).show() } } searchSql.addTextChangedListener(object:TextWatcher{ override fun afterTextChanged(p0: Editable?) { val name = p0.toString() val result = myDBHelper.findProduct2(name) } override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { } override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) { } }) } fun getAllRecord(){ myDBHelper.getAllRecord() }
- insertBtn : MyDBHelper의 insertProduct()를 호출. MyDBHelper에서 pid 값으로 autoincrement 기능을 사용하기 때문에 ItemData의 pid에 쓰레기값을 넣음
- deleteBtn : pIdEdit의 텍스트값을 바탕으로 MyDBHelper의 deleteProduct() 호출. 반환값이 true일 시 getAllRecord()를 통해 RecyclerView의 데이터를 갱신
- updateBtn : pIdEdit의 값을 바탕으로 MyDBHelper의 updateProduct() 호출. pQuantity, pName 값으로 변경
- findBtn : pNameEdit 값을 바탕으로 MyDBHelper의 findProduct() 호출
- searchSql : EditText에 addTextChangedListener를 달아 텍스트 값에 변화를 줄 때마다 MyDBHelper의 findProduct2() 호출
위의 예제에선 사용자가 모든 데이터를 직접 입력해야한다는 번거로움이 있습니다.
사용자가 원하는 *.db 파일이 있을 경우 이를 추가하는 코드를 만들겠습니다.
먼저, res - raw 폴더를 만들고 해당 db파일을 넣어줍니다.
MainActivity.kt
private fun initDB(){ val dbfile = this.getDatabasePath("mydb.db") if(!dbfile.parentFile.exists()){ dbfile.parentFile.mkdir() } if(!dbfile.exists()){ val file = resources.openRawResource(R.raw.mydb) val fileSize = file.available() val buffer = ByteArray(fileSize) file.read(buffer) file.close() dbfile.createNewFile() val output = FileOutputStream(dbfile) output.write(buffer) output.close() } }
- line 2 : getDatabasePath() 메소드로 dbfile을 선언
- line 3 : dbfile의 parentFile이 존재하지 않다면 파일 생성
- line 6 : dbfile 존재 여부 판별 후 없다면 raw 폴더의 mydb.db 파일 불러옴
반응형'개발 끄적끄적 > Android' 카테고리의 다른 글
[Android Studio] ImageView 속성 알아보기 - ScaleType & Background vs Src (0) 2020.06.18 [Android Studio] Context란? Context의 정의, 종류와 사용 방법 (1) 2020.06.05 [Android Kotlin] Retrofit2 사용방법 - Interface와 Data Class까지 (1) 2020.06.04 [Android Kotlin] 카카오맵 사용하는 방법 (해시키 등록) + 내 위치 표시하기 (0) 2020.06.03 [Android Kotlin] 갤러리에서 이미지 가져와 RecyclerView에 적용하기 (0) 2020.06.03