Android์ 4๋ ์ปดํฌ๋ํธ ์ค ํ๋์ธ Content Provider๋ ์ฑ ๊ฐ ๋ฐ์ดํฐ ๊ณต์ ๋ฅผ ์ํ ํ์ค ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํตํด SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค, ํ์ผ, ๋คํธ์ํฌ ๋ฐ์ดํฐ ๋ฑ์ ๋ค๋ฅธ ์ฑ๊ณผ ์์ ํ๊ฒ ๊ณต์ ํ ์ ์์ต๋๋ค.
์ง๊ธ๋ถํฐ Content Provider์ ๋ํด ์์ธํ ์ค๋ช ํ๊ฒ ์ต๋๋ค.
Content Provider
Android์์๋ ๊ฐ ์ฑ์ด ์์ ๋ง์ ์ ์ฅ ๊ณต๊ฐ(SandBox)์ ๊ฐ์ง๊ณ ์๊ธฐ ๋๋ฌธ์, ๊ธฐ๋ณธ์ ์ผ๋ก ๋ค๋ฅธ ์ฑ์ด ์ง์ ๋ฐ์ดํฐ์ ์ ๊ทผํ ์ ์์ต๋๋ค. ๊ทธ๋ฌ๋ Content Provider๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณด์ ์ ์ฑ ์ ์ ์งํ๋ฉด์๋ ๋ฐ์ดํฐ ๊ณต์ ๊ฐ ๊ฐ๋ฅํฉ๋๋ค.
Content Provider๋ ์ฑ ๋ด๋ถ์ ๋ฐ์ดํฐ๋ฅผ ๋ค๋ฅธ ์ฑ์ด ์ ๊ทผํ ์ ์๋๋ก ํ์ฉํฉ๋๋ค. ์๋ฅผ ๋ค์ด, ์ฐ๋ฝ์ฒ ์ฑ์ ์ ํ๋ฒํธ๋ฅผ ๋ค๋ฅธ ์ฑ์ด ์ฝ์ ์ ์๋๋ก ํฉ๋๋ค.
์ฃผ์ ์ญํ ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ฑ์ด ๋ฐ์ดํฐ๋ฒ ์ด์ค, ํ์ผ, ๋คํธ์ํฌ ๋ฑ์ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ๊ณต์
- ๋ค๋ฅธ ์ฑ์ด ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ธฐ, ์ถ๊ฐ, ์์ , ์ญ์ ํ ์ ์๋๋ก API๋ฅผ ์ ๊ณต
- ๊ถํ ์ ์ด๋ฅผ ํตํด ํน์ ์ฑ๋ง ๋ฐ์ดํฐ ์ ๊ทผ ๊ฐ๋ฅ
Content Provider ๋์ ๋ฐฉ์
Content Provider๋ ContentResolver๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ, ์ฑ์ ์ด๋ฅผ ํตํด ๋ฐ์ดํฐ๋ฅผ ์ฝ๊ณ ์์ ํ ์ ์์ต๋๋ค.
URI(Uniform Resource Identifier)
Content Provider์์ ๋ฐ์ดํฐ๋ฅผ ์๋ณํ๋ ๊ณ ์ ํ ์ฃผ์์ ๋๋ค.
URI๋ content:// ํ์์ ๊ฐ์ง๋ฉฐ, ๋ฐ์ดํฐ์ ์ ๊ทผํ ๋ ์ฌ์ฉํฉ๋๋ค.
content://<Authority>/<Path>/<ID>
๊ตฌ์ฑ ์์ | ์ค๋ช |
content:// | Content Provider๋ฅผ ์๋ณํ๋ ๊ธฐ๋ณธ ํ๋กํ ์ฝ |
Authority | ํน์ Content Provider๋ฅผ ์๋ณํ๋ ๋ฌธ์์ด (AndroidManifest.xml ์์ ์ ์) |
Pah | ํ ์ด๋ธ ๋๋ ๋ฐ์ดํฐ ๊ทธ๋ฃน ๋ฑ ๋ฐ์ดํฐ์ ํน์ ๊ฒฝ๋ก |
ID (์ ํ ์ฌํญ) | ํน์ ํ(๋ ์ฝ๋)๋ฅผ ์๋ณํ๋ ID |
์๋ฅผ ๋ค์ด users ํ ์ด๋ธ์ ID๊ฐ 1์ธ ๋ฐ์ดํฐ์ ์ ๊ทผํ๋ค๋ฉด, URI๋ ์๋์ ๊ฐ์ต๋๋ค.
content://com.example.provider/users/1
CRUD ๋ฉ์๋
Content Provider๋ ๋ฐ์ดํฐ๋ฅผ ์กฐ์ํ๊ธฐ ์ํด ๋ค์์ ๋ฉ์๋๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋ฉ์๋ | ์ญํ |
query() | ๋ฐ์ดํฐ ์กฐํ |
insert() | ๋ฐ์ดํฐ ์ฝ์ |
update() | ๋ฐ์ดํฐ ์์ |
delete() | ๋ฐ์ดํฐ ์ญ์ |
getType() | URI์ ํด๋นํ๋ ๋ฐ์ดํฐ ํ์ ๋ฐํ |
Content Provider ๊ตฌํ
๋ค์์ SQLite ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ๊ธฐ๋ฐ์ผ๋ก Content Prvider๋ฅผ ๊ตฌํํ ์์ ์ ๋๋ค.
class MyContentProvider : ContentProvider() {
private lateinit var dbHelper: MyDatabaseHelper
override fun onCreate(): Boolean {
dbHelper = MyDatabaseHelper(context!!)
return true
}
override fun query(uri: Uri, projection: Array<String>?, selection: String?, selectionArgs: Array<String>?, sortOrder: String?): Cursor? {
val db = dbHelper.readableDatabase
return db.query("users", projection, selection, selectionArgs, null, null, sortOrder)
}
override fun insert(uri: Uri, values: ContentValues?): Uri? {
val db = dbHelper.writableDatabase
val id = db.insert("users", null, values)
return ContentUris.withAppendedId(uri, id)
}
override fun update(uri: Uri, values: ContentValues?, selection: String?, selectionArgs: Array<String>?): Int {
val db = dbHelper.writableDatabase
return db.update("users", values, selection, selectionArgs)
}
override fun delete(uri: Uri, selection: String?, selectionArgs: Array<String>?): Int {
val db = dbHelper.writableDatabase
return db.delete("users", selection, selectionArgs)
}
override fun getType(uri: Uri): String? {
return "vnd.android.cursor.dir/vnd.com.example.provider.users"
}
}
<provider
android:name=".MyContentProvider"
android:authorities="com.example.provider"
android:exported="false"
android:grantUriPermissions="true" />
๋ค๋ฅธ ์ฑ์์ Content Provider๋ฅผ ์ฌ์ฉํ ๋๋ ContentResolver๋ฅผ ํ์ฉํฉ๋๋ค.
๋ฐ์ดํฐ ์กฐํ
fun selectData() {
val cursor: Cursor? = contentResolver.query(
Uri.parse("content://com.example.provider/users"),
null, null, null, null
)
cursor?.use {
while (it.moveToNext()) {
val id = it.getInt(it.getColumnIndexOrThrow("id"))
val name = it.getString(it.getColumnIndexOrThrow("name"))
Log.d("ContentProvider", "User ID: $id, Name: $name")
}
}
}
๋ฐ์ดํฐ ์ฝ์
fun insertData() {
val values = ContentValues().apply {
put("name", "John Doe")
}
val uri = contentResolver.insert(Uri.parse("content://com.example.provider/users"), values)
Log.d("ContentProvider", "Inserted URI: $uri")
}
๋ฐ์ดํฐ ์์
fun updateData() {
val values = ContentValues().apply {
put("name", "Updated Name")
}
val updatedRows = contentResolver.update(
Uri.parse("content://com.example.provider/users"),
values, "id=?", arrayOf("1")
)
Log.d("ContentProvider", "Updated Rows: $updatedRows")
}
๋ฐ์ดํฐ ์ญ์
fun deleteData() {
val deletedRows = contentResolver.delete(
Uri.parse("content://com.example.provider/users"),
"id=?", arrayOf("1")
)
Log.d("ContentProvider", "Deleted Rows: $deletedRows")
}
์ค์ ๋ก ์ ๋ Content Provider๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํจ๊ป ์ฌ์ฉํ๊ธฐ๋ณด๋จ, ๊ฐค๋ฌ๋ฆฌ ์ฑ์์ ์ด๋ฏธ์ง์ ์ ๊ทผํ ๋ ์ฃผ๋ก ์ฌ์ฉํ์ต๋๋ค.
๋ค์์ ๊ฐค๋ฌ๋ฆฌ ์ฑ์์ ๊ฐ์ฅ ์ต๊ทผ ์ฌ์ง์ ๊ฐ์ ธ์ค๋ ์์์ ๋๋ค.
fun getLatestImageUri(context: Context): Uri? {
val contentResolver = context.contentResolver
val uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
val projection = arrayOf(MediaStore.Images.Media._ID, MediaStore.Images.Media.DATE_ADDED)
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC LIMIT 1"
val cursor = contentResolver.query(uri, projection, null, null, sortOrder)
cursor?.use {
if (it.moveToFirst()) {
val idIndex = it.getColumnIndex(MediaStore.Images.Media._ID)
val imageId = it.getLong(idIndex)
return ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, imageId)
}
}
return null
}
val latestImageUri = getLatestImageUri(context)
if (latestImageUri != null) {
Log.d("Gallery", "Latest image URI: $latestImageUri")
}
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
Content Provider๋ Android์์ ์ฑ ๊ฐ ๋ฐ์ดํฐ๋ฅผ ์์ ํ๊ฒ ๊ณต์ ํ ์ ์๋๋ก ์ค๊ณ๋ ๊ฐ๋ ฅํ ์ปดํฌ๋ํธ์ ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค, ํ์ผ, ๋คํธ์ํฌ ๋ฐ์ดํฐ ๋ฑ์ ๋ค๋ฃฐ ์ ์์ผ๋ฉฐ ๊ถํ ์ ์ด๋ฅผ ํตํด ๋ณด์์ฑ์ ๋์ผ ์ ์์ต๋๋ค. ๋ค๋ง, ๊ตฌํ์ด ๋ณต์กํ๊ณ ์ฑ๋ฅ ๋ฌธ์ ๋ฅผ ๊ณ ๋ คํด์ผ ํ๋ ํ๊ณ๊ฐ ์กด์ฌํฉ๋๋ค.
์ด์ ๋ฐ๋ผ ์ ์ ํ ๊ถํ ์ค์ ๊ณผ URI ๊ด๋ฆฌ๋ก ํจ์จ์ ์ด๊ณ ์์ ํ๊ฒ ๋ฐ์ดํฐ๋ฅผ ๊ณต์ ํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์๋๋ก์ด๋ ๊ฐ๋ฐ์ ๋ก๋๋งต์ ๋ฐ๋ผ ์ ๋ฆฌํ ๋ด์ฉ์ ๋๋ค.
'๐ป Programming > Android Developer AtoZ' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Android] App Components - (6) Intent ์๋ฒฝ ๊ฐ์ด๋ (1) | 2025.03.24 |
---|---|
[Android] App Components - (4) Broadcast Receiver ์๋ฒฝ ๊ฐ์ด๋ (0) | 2025.03.21 |
[Android] App Components (3) - Service ์๋ฒฝ ๊ฐ์ด๋ (1) | 2025.03.19 |
[Android] App Components (2) - Activity ์๋ฒฝ ๊ฐ์ด๋ (1) | 2025.03.05 |
[Android] App Components (1) - ์๋๋ก์ด๋ 4๋ ์ปดํฌ๋ํธ (0) | 2025.02.28 |