一、背景
公司需要定制相册选择页面ui样式,并且功能不是很多时,这时候要考虑自己去实现相册选择
二、我们需要了解的一些知识
1.获取相册图片地址首先是需要权限的,这里所需要的权限是文件读写权限Manifest.permission.WRITE_EXTERNAL_STORAGE,这个权限需要动态去申请,这里就不讲解了
2.Android Q以后,文件这一块改成了沙盒模式,应用只能访问自己沙盒下的文件和公共媒体文件。不在具有访问其它app文件的权限
三、具体实现代码
val mPageSize = 100
val projection = arrayOf(
MediaStore.Images.Media._ID,
MediaStore.Files.FileColumns.DATE_MODIFIED
)
/**
* 分页查询媒体库
* Android 8.0及以上使用 queryArgs 分页(以用来兼容Android11,android 11 不可用 sortOrder 分页)
* Android 8.0以下使用 sortOrder 分页
* page从0开始
*/
fun queryMediaStoreImages(context: Context, page: Int) {
val uri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
var cursor: Cursor ?= null
// 倒序+分页
val sortOrder = MediaStore.Images.Media.DATE_ADDED + " DESC limit " + mPageSize + " offset " + page * mPageSize
try {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val queryArgs = createSqlQueryBundle(null,null,sortOrder, mPageSize,page)
cursor = context.contentResolver.query(
uri,
projection,
queryArgs,
null
)
}else{
val selection: String? = null
val selectionArgs: Array<String>? = null
cursor = context.contentResolver.query(
uri,
projection,
selection,
selectionArgs,
sortOrder,
)
}
}catch (e: Exception){
LogUtils.d("获取手机相册错误")
}
val columnIndexID: Int
var imageId: Long
if (cursor != null) {
columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
var i = 0
while (cursor.moveToNext()) {
imageId = cursor.getLong(columnIndexID)
val uriImage = Uri.withAppendedPath(uri, "" + imageId)
Log.d("print","${++i}")
Log.d("print",uriImage.toString())
}
cursor.close()
}
}
/**
* android o以上处理返回bundler
*/
@RequiresApi(Build.VERSION_CODES.O)
fun createSqlQueryBundle(
selection: String?,
selectionArgs: Array<String?>?,
sortOrder: String?,
limitCount: Int,
offset: Int
): Bundle? {
if (selection == null && selectionArgs == null && sortOrder == null) {
return null
}
val queryArgs = Bundle()
if (selection != null) {
queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SELECTION, selection)
}
if (selectionArgs != null) {
queryArgs.putStringArray(ContentResolver.QUERY_ARG_SQL_SELECTION_ARGS, selectionArgs)
}
if (sortOrder != null) {
queryArgs.putString(ContentResolver.QUERY_ARG_SQL_SORT_ORDER, sortOrder)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R){
// 设置倒序
queryArgs.putInt(
ContentResolver.QUERY_ARG_SORT_DIRECTION,
ContentResolver.QUERY_SORT_DIRECTION_DESCENDING
)
// 设置倒序条件--文件添加时间
queryArgs.putStringArray(
ContentResolver.QUERY_ARG_SORT_COLUMNS,
arrayOf(MediaStore.Files.FileColumns.DATE_ADDED)
)
queryArgs.putString(ContentResolver.QUERY_ARG_SQL_LIMIT, "$limitCount offset $offset")
}
return queryArgs
}
四、代码讲解
1.我们自定义相册,肯定需要分页,这里的mPageSize是每页条数,queryMediaStoreImages()此方法传入页码,需要注意的是page是从0开始的。
2.这里分为了两种查询, 是因为o以后改为Bundle构建查询参数
3.这里返回的是Uri集合,如果想返回的是文件路劲,在循环解析cursor游标中使用如下代码
if (cursor != null) {
val columnIndexID = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
while (cursor.moveToNext()) {
val path = cursor.getString( columnIndexID)
}
cursor.close()
}
path就是文件地址,MediaStore.Images.Media.DATA会提示过时,大概就是官方现在不推荐使用路基去访问
网友评论