Mobile/Android(Kotlin)

[Android/Kotlin] Insert images into SQLite(SQLite에 이미지 저장)

개발왕 금골드 2020. 8. 19. 15:00
반응형

안녕하세요 골드입니다.

 오늘은 안드로이드에서 제공하는 SQLite 데이터베이스에 이미지를 저장하는 방법에 대해서 글을 쓰도록 하겠습니다. 저는 레이아웃을 리사이클러뷰로 만들 것입니다. 빠른 진행을 위해 리사이클러뷰에 대한 글을 작성하진 않지만 링크를 하나 남겨놓겠습니다. 

https://kumgo1d.tistory.com/43

 

 

[Android/Kotlin] RecyclerView를 사용해서 ListView와 GridView 만들기

안녕하세요 골드입니다.  오늘은 Android에서 RecyclerView를 사용해서 ListView와 GridView를 만드는 방법에 대해서 글을 쓰도록 하겠습니다.  Android Studio 3.1을 기준으로 안드로이드에서 정말 많이 사용�

kumgo1d.tistory.com

 

1. data class 선언

 kotlin은 data class라는 것을 제공합니다. java에서 데이터베이스를 사용하려면 getter와 setter를 정의한 클래스를 하나 생성해야 했습니다. 하지만 kotlin에서는 class 앞에 data 키워드를 적용하면 이 부분을 자동으로 생성해줍니다. 

 Memo라는 data class를 하나 생성했습니다. 이미지는 바이너리 형식으로 저장되고 null가능이기 때문에 ByteArray?로 선언하였습니다.

 

2. SQLiteOpenHelper를 상속받는 Helper

 SQLiteOpenHelper는 안드로이드에서 SQLite를 사용할 수 있게 도와주는 클래스입니다. 해당 클래스를 상속받아서 SQLite를 커스텀해서 사용할 수 있습니다. 

 Context는 설명서같은 개념입니다. 거의 모든 객체가 Context를 가지고 있습니다. name은 SQLite 파일명입니다. 사용하려고 하는 파일의 이름을 넣으면 됩니다. (SQLite는 하나의 파일로 존재합니다.)

 onCreate를 오버라이드하고 table을 생성합니다. 저는 table을 memo라고 짓겠습니다. memo 테이블에 두 개의 변수가 존재합니다. no라는 변수는 integer형이며 고유 키값을 가집니다. no값은 따로 선언하지 않아도 자동으로 넘버링됩니다. 이후에 이 no변수는 데이터를 가져오는데 사용됩니다. image라는 변수는 blob형으로 저장하도록 합니다. blob은 크기가 큰 바이너리 형식의 데이터를 저장할 때 사용합니다.

https://developer.android.com/reference/java/sql/Blob

 

Blob  |  Android 개발자  |  Android Developers

 

developer.android.com

 

 onUpgrade는 필수로 오버라이드해야하는 함수입니다만, 저는 사용하지 않았습니다.

 insertMemo함수는 table에 기존에 저장되어 있던 변수들이 아닌 처음으로 변수들을 데이터베이스에 넣을 때 사용합니다. ContentValues()를 사용합니다. ContentValues()는 쉽게 말해서 앱이 저장한 데이터와 다른 앱이 저장한 데이터들에 대한 접근을 도와줍니다. 내부적으로 ArrayMap으로 되어 있기 때문에 저장할 때, key-value 형식으로 저장합니다. 

https://developer.android.com/guide/topics/providers/content-providers

 

콘텐츠 제공자  |  Android 개발자  |  Android Developers

Content providers manage access to a structured set of data. They encapsulate the data, and provide mechanisms for defining data security. Content providers are the standard interface that connects data in one process with code running in another process��

developer.android.com

 

 selectMemo()함수는 데이터베이스에 저장된 값을 가져오는 함수입니다. 리사이클러뷰에 리스트 형식으로 전달할 것이며 이 리스트는 값이 변하기 때문에 MutableList로 선언했습니다. select 쿼리 문으로 memo 테이블에 쿼리하고 커서 객체로 데이터들을 가리킵니다. (dumpCursor를 사용하면 로그창에서 데이터에 대한 정보를 바로 볼 수 있기 때문에 사용하였습니다. 꼭 필요한 코드는 아닙니다.) 이후 커서 객체를 활용하여 데이터베이스 안에 데이터가 있으면 list에 추가하고 없으면 빠져나올 수 있도록 while문을 사용합니다. 데이터를 전부 추가하였다면 while문을 빠져나오고 커서와 데이터베이스를 닫고 list를 return합니다. 이후 이 list는 adapter로 전달되어 리사이클러뷰에 뿌려지게 됩니다. 

 

 helper 클래스에 마지막입니다. 기존에 데이터들을 update하는 함수와 삭제하는 함수입니다. 두 함수의 공통점은 어떤 데이터를 업데이트(혹은 삭제)할 때 데이터를 식별하는 변수가 no변수라는 점입니다. no변수를 기준으로 업데이트(혹은 삭제)할 데이터를 정해서 진행합니다. 

 

 

3. MemoActivity.kt에서 데이터 저장

 이제 정의한 코드들을 사용하는 일만 남았습니다. 이미지 데이터를 사용하기 위해 먼저 데이터를 변환하는 함수를 하나 생성합니다. 먼저 MemoActivity 클래스를 하나 생성하고 상단에 helper를 참조하는 코드를 한 줄 작성합니다. MemoActivity는 리사이클러뷰의 아이템을 클릭했을때 나타나는 Activity입니다.

 

 저는 ImageView를 사용할 것입니다. 이미지를 불러오는 코드를 보기 전에 저장하는 코드부터 작성하겠습니다. 이미지는 바이너리 데이터입니다. 쉽게 얘기해서 01010101이라는 뜻입니다. 이게 이미지의 본 모습인데, 우리가 본 이미지의 모습을 데이터베이스에 저장하기 위해서는 본 모습으로 넣어야 합니다. 데이터베이스가 우리의 이미지를 사진 찍어서 저장하면 좋겠지만 그렇게 작동하지 않습니다. 저장하기 위해 ImageView에 있는 이미지를 ByteArray로 변환해서 return합니다. 이미지를 저장할 수도 있고 아닐 수도 있기 때문에 매개변수의 값을 null가능형으로 선언하였습니다. 

 

 MemoActivity에 helper에서 작성한 insert와 update를 사용하기 위한 함수를 작성합니다. 코드는 간단합니다. insert는 ImageView에 있는 이미지를 data class에 담아서 insertMemo 인자에 전달합니다. update 역시 마찬가지로 ImageView에 이미지를 가져옵니다. 차이점은 Adapter 클래스에서 intent로 넘어 온 no를 사용해서 어떤 데이터가 update되었는지 알 수 있어야 한다는 점입니다. 

 

 save와 update는 여러분의 상황에 맞게 해당 버튼을 클릭하면 사용할 수 있게끔 작성해주세요. 저는 OptionMenu에 적용하였습니다.

 

 init함수를 생성합니다. 이 함수는 MainActivity에서 리사이클러뷰를 클릭하면 저장되어 있는 이미지가 나타나게 만드는 함수입니다. 항상 null체크에 주의하시고 null이 아니라면 해당 데이터를 디코드해서 ImageView에 넣어줍니다. init()은 MemoActivity의 onCreate()에 선언해주세요.

 

 

4. RecyclerAdapter 클래스

 RecyclerView를 사용한다면 Adapter 클래스를 반드시 생성해야 합니다. 맨 위에 링크를 두었으니 참고하시기 바랍니다. 여기서는 대략적인 코드 설명만 하겠습니다.

 Adapter에서도 helper 클래스에 대한 참조를 해야 합니다. listData 변수는 리사이클러뷰에 나타나는 리스트입니다. 

 onBindViewHolder()에서 holder를 활용해서 리사이클러뷰 아이템을 클릭했을 때 intent를 전달하는 코드를 작성하였습니다.

 holder는 inner class로 정의하였고 그 안에 setMemo 함수가 각 아이템의 이미지뷰에 ByteArray 이미지 변수를 디코드해서 Bitmap으로 변환한 후 set합니다. 주의할 점은 null 체크를 반드시 해야한다는 점입니다. 

 

 

5. MainActivity

 helper와 adapter를 참조하는 코드를 작성합니다.

 

 initSettings()라는 함수를 만들어서 리사이클러뷰 adapter를 설정하고 adapter의 helper를 설정합니다. 사진을 보여주기 위해서 그리드뷰로 만들었고 경계선을 나타내고 싶어서 Divider를 사용하였습니다. (Divider도 좋지만 경우에 따라서 Drawable로 직접 만드는 게 좋습니다.) adapter로 helper클래스의 select를 사용하면 데이터들을 가져올 수 있습니다. 마지막으로 변화를 적용합니다. initSettings()는 onCreate()나 onResume()에 선언해주세요.

 

***리사이클러뷰 아이템과 MemoActivity의 레이아웃 안에 ImageView를 추가하셔야 합니다. 아마 잘 아시겠지만, 중간중간 itemImage(리사이클러뷰의 ImageView)나 imageView(MemoActivity의 ImageView)라는 코드가 빨갛게 된다면 여러분이 추가한 ImageView의 id값과 일치하지 않아서 그렇습니다.

 

 

이제 플레이 해보겠습니다.

이미지가 있는 것과 없는 것 모두 저장된 것을 볼 수 있으며,

해당 아이템을 클릭하면 MemoActivity로 넘어가면서 저장된 이미지가 나타나는 것을 볼 수 있습니다.

 

여기까지 골드였습니다.

감사합니다.

 

 

 

참고자료 : https://stackoverflow.com/questions/9357668/how-to-store-image-in-sqlite-database

 

How to store image in SQLite database

In my application I am uploading an image from gallery and I want to store this image in the SQLite database. How do I store a bitmap in the database? I am converting bitmap to a string and saving ...

stackoverflow.com

https://stackoverflow.com/questions/40838370/sqlite-database-supports-blob-how-to-store-image-in-sqlite-in-android

 

Sqlite database supports blob....how to store image in sqlite in android?

I want to store image in sqlite db in android.My question is 1)do I need to convert image to blob before inserting or can simply insert bitmap/byte[] that android may covert to blob and store? ...

stackoverflow.com

한빛미디어/이것이 안드로이드다/고돈호 지음

반응형