Android

Android 获取图片以及视频列表

最近需要做一个深度定制的图库的功能,于是,如何获取相册列表,以及如何获取相册里面的图片信息成为了重中之重,本文只是封装了一些代码。其实获取图片以及视频信息只要你知道其数据库如何设计,那么一切都会变得非常简单。好了,我们开始吧。

首先,我们需要获取的信息分为:图片相册、图片相册里面有那些图片,视频相册,视频相册里有那些视频。于是,封装了两个类:

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 是我之前封装的类,就不赘述了。

full-stack-trip

Share
Published by
full-stack-trip

Recent Posts

Android 自定义 View 入门

说来惭愧,工作数年,连基本的自…

4 年 ago

retrofit 同时支持 xml 和 json

retrofit 解析 jso…

4 年 ago

mysql - 存储过程 从入门到放弃

最近有个报表的需求,于是乎用了…

4 年 ago

奶嘴战略 - 你不得不知道的扎心真相(一)

一句:英雄枯骨无人问,戏子家事…

4 年 ago

acme.sh 的简单使用

acme.sh 是纯 shel…

4 年 ago

wrk -更现代化的http压测工具

wrk 是一款更现代化的 ht…

4 年 ago