最近需要做一个深度定制的图库的功能,于是,如何获取相册列表,以及如何获取相册里面的图片信息成为了重中之重,本文只是封装了一些代码。其实获取图片以及视频信息只要你知道其数据库如何设计,那么一切都会变得非常简单。好了,我们开始吧。
首先,我们需要获取的信息分为:图片相册、图片相册里面有那些图片,视频相册,视频相册里有那些视频。于是,封装了两个类:
1、BucketModel.kt
class BucketModel {
var displayName: String? = null
var bucketId: String? = null
}
2、MediaModel.kt
class MediaModel {
var imageUri: String? = null
var imageId: Int? = null
}
最后,我们封装一个工具类,用于获取相册以及相册里有那些媒体。
3、MediaUtils.kt
import android.net.Uri
import android.provider.MediaStore
import kotlinx.coroutines.Deferred
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import top.kpromise.ibase.IApplication
import top.kpromise.igallery.model.BucketModel
import top.kpromise.igallery.model.MediaModel
import java.lang.StringBuilder
object MediaUtils {
private const val bucketId = "bucket_id"
private const val id = "_id"
private const val data = "_data"
private const val dateTime = "datetaken"
private val imageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
private val videoUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI
fun listImageBucketAsync(): Deferred<ArrayList<BucketModel>> {
return GlobalScope.async(Dispatchers.IO) {
listMediaBucket(imageUri)
}
}
fun listVideoBucketAsync(): Deferred<ArrayList<BucketModel>> {
return GlobalScope.async(Dispatchers.IO) {
listMediaBucket(videoUri)
}
}
private fun listMediaBucket(uri: Uri): ArrayList<BucketModel> {
val displayName = "bucket_display_name"
val projection = arrayOf(displayName, bucketId, id, "count ($bucketId) as mediaCount")
val cur = IApplication.app?.contentResolver?.query(uri, projection,
"0=0) group by ($bucketId", null, "$dateTime desc")
val result = ArrayList<BucketModel>()
cur ?: return result
while (cur.moveToNext()) {
val bucketModel = BucketModel()
bucketModel.displayName = cur.getString(cur.getColumnIndex(displayName))
bucketModel.bucketId = cur.getString(cur.getColumnIndex(bucketId))
bucketModel.coverMediaId = cur.getInt(cur.getColumnIndex(id))
bucketModel.mediaCount = cur.getInt(cur.getColumnIndex("mediaCount"))
result.add(bucketModel)
}
cur.close()
return result
}
private fun listMediaIdInBucket(bucketId: String?, uri: Uri, from: Int, size: Int): ArrayList<Int> {
val projection = arrayOf(id)
val selection = if (bucketId == null) null else "${this@MediaUtils.bucketId} = ?"
val selectionArgs = if (selection == null) null else arrayOf(bucketId)
val sortOrder = "$id desc"
val pageUri = uri.buildUpon().encodedQuery("limit=$from,$size").build()
val cur = IApplication.app?.contentResolver?.query(pageUri, projection, selection, selectionArgs, sortOrder)
val result = ArrayList<Int>()
cur ?: return result
while (cur.moveToNext()) {
val imageId = cur.getInt(cur.getColumnIndex(id))
result.add(imageId)
}
cur.close()
return result
}
fun listImageInBucketAsync(bucketId: String?, from: Int, size: Int): Deferred<ArrayList<MediaModel>> {
return GlobalScope.async(Dispatchers.IO) {
listImageInBucket(bucketId, imageUri, from, size)
}
}
fun listVideoInBucketAsync(bucketId: String?, from: Int, size: Int): Deferred<ArrayList<MediaModel>> {
return GlobalScope.async(Dispatchers.IO) {
listImageInBucket(bucketId, videoUri, from, size)
}
}
fun listImageByIdsAsync(ids: ArrayList<Int>): Deferred<ArrayList<MediaModel>> {
return GlobalScope.async(Dispatchers.IO) {
listMediaByIds(ids, imageUri)
}
}
fun listVideoByIdsAsync(ids: ArrayList<Int>): Deferred<ArrayList<MediaModel>> {
return GlobalScope.async(Dispatchers.IO) {
listMediaByIds(ids, videoUri)
}
}
private fun listImageInBucket(bucketId: String?, uri: Uri, from: Int, size: Int): ArrayList<MediaModel> {
val list = listMediaIdInBucket(bucketId, uri, from, size)
return listMediaByIds(list, uri)
}
private fun listMediaByIds(list: ArrayList<Int>, uri: Uri): ArrayList<MediaModel> {
val selection: String?
val result = ArrayList<MediaModel>()
val selectionArgs: Array<String?>?
if (list.isNullOrEmpty()) {
return result
} else {
val stringBuilder = StringBuilder()
val size = list.size
stringBuilder.append("$id in (?")
for (index in 1 until size) {
stringBuilder.append(",").append("?")
}
stringBuilder.append(")")
selection = stringBuilder.toString()
selectionArgs = arrayOfNulls(size)
list.forEachIndexed { index, i ->
selectionArgs[index] = "$i"
}
}
val projection = arrayOf(data, id)
val cur = IApplication.app?.contentResolver?.query(uri,
projection, selection, selectionArgs, "$dateTime desc")
cur ?: return result
while (cur.moveToNext()) {
val mediaModel = MediaModel()
mediaModel.imageUri = cur.getString(cur.getColumnIndex(data))
mediaModel.imageId = cur.getInt(cur.getColumnIndex(id))
result.add(mediaModel)
}
cur.close()
return result
}
}
4、调用的时候可以这样:
private fun listGallery() = GlobalScope.launch(Dispatchers.Main) {
val resultImage = MediaUtils.listImageBucketAsync().await()
val firstImage = MediaUtils.listImageInBucketAsync(resultImage[0].bucketId, from, size).await()
ILog.e("===image===", IJson.toPrettyFormat(IJson.toJson(firstImage, ArrayList::class.java)))
val videoResult = MediaUtils.listVideoBucketAsync().await()
val firstVideo = MediaUtils.listVideoInBucketAsync(videoResult[0].bucketId, from, size).await()
ILog.e("===video===", IJson.toPrettyFormat(IJson.toJson(firstVideo, ArrayList::class.java)))
}
为什么要分页呢?因为 sqlite in 后面的 array 最大是999,即一次最大能查询 999 条记录,再多就崩溃了。另外, 这里,ILog 以及 IJson 是我之前封装的类,就不赘述了。
评论