设计一个图片选择器(上篇)

在项目的开发过程中,选择图片是非常常用的功能,例如选择头像功能,因为是单图选择一般都是使用系统图片选择器;而例如反馈,评论,发布信息等需要选择多张图片的场景使用系统选择器就不再适合了。

准备工作

  1. 访问图片需要添加存储卡权限,在6.0之上还需要实现运行时权限的申请(参考官方文档:https://developer.android.com/training/permissions/requesting)。
  2. 关于扫描手机中的文件的方法,(1)在手机存储还比较小的时候,通常使用扫描文件夹的方式,就是从根目录查询所有的文件夹下的图片,用时几秒即可扫描到所有的图片文件;而现在随着手机存储越来越大,图片很多的情况下还使用这种方式的话,耗时会大大增加,令人难以忍受。(2)直接查询系统中的数据库,系统中的external数据库(路径:/data/data/com.android.providers.media/databases/external.db)存储了手机中所有文件的信息,使用ContentProvider(https://developer.android.com/guide/topics/providers/content-providers)的方式来查询系统中的文件信息。

查询的方式主要有这两种:

  1. 使用ContentResolver查询,使用方式:Cursor cursor =getContext().getContentResolver().query(),使用返回的cursor来显示数据。
  2. 使用CursorLoader(https://developer.android.com/reference/android/content/CursorLoader.html),CursorLoader其实是封装了ContentResolver,继承自AsyncTaskLoader,实现后台加载数据,不会阻塞UI线程。

使用CursorLoader来实现:而android.content.CursorLoader在API28被标记为过时了,建议使用support library的CursorLoader。CursorLoader的使用方式与ContentResolver的使用方式类似,参数也大致相同,来看下构造方法

public CursorLoader(@NonNull Context context, @NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder){
     ……
}

其中context和uri不可为空,其他可空,下面来看下参数的含义

context:context对象

uri:需要查询的uri,基本都是以content://开头的内容提供者地址,如果想查询图片可以用:MediaStore.Images.Media.EXTERNAL_CONTENT_URI(content://media/external/images/media);查询视频可以用:MediaStore.Video.Media.EXTERNAL_CONTENT_URI(content://media/external/video/media);查询音频可以用:MediaStore.Audio.Media.EXTERNAL_CONTENT_URI(content://media/external/audio/media);查询所有文件可以用MediaStore.Files.getContentUri("external")(content://media/external/file)。其中图片,视频和音频都是数据库的视图,对文件表进行了优化,使用这三个可以降低开销。

projection:想查询的列的集合,为null时返回所有的列(最好不要为null,性能比较差)。例如文件的绝对路径为MediaStore.MediaColumns.DATA,文件类型为MediaStore.MediaColumns.MIME_TYPE等等。

selection:查询的条件。例如图片的筛选,只想查询jpg和png图片可以用:MediaStore.MediaColumns.MIME_TYPE + " in  ('image/jpeg', 'image/png')"

selectionArgs:配合selection使用,如果selection中包含?(例如MediaStore.MediaColumns.MIME_TYPE + " in  ('?', '?')"),那么selectionArgs中的内容会替换?(例如new String[]{"image/jpeg", "image/png"})。

sortOrder:排序规则。例如按修改时间排序:MediaStore.Files.FileColumns.DATE_MODIFIED + " desc"

使用LoadManager(https://developer.android.com/reference/android/app/LoaderManager) 来管理CursorLoader,与CursorLoader一样,使用support包的LoadManager。LoadManager有这样几个关键的方法

/**
* 初始化一个Loader,如果已经存在则返回存在的
*/
public abstract <D> Loader<D> initLoader(int id, @Nullable Bundle args, @NonNull LoaderManager.LoaderCallbacks<D> callback);

/**
* 重新创建Loader,已经存在的会被销毁
*/
public abstract <D> Loader<D> restartLoader(int id, @Nullable Bundle args, @NonNull LoaderManager.LoaderCallbacks<D> callback);

/**
* 销毁一个Loader,在页面销毁时需要销毁Loader
*/
public abstract void destroyLoader(int id);

值得注意的是,这些方法都必须在主线程运行。

id:可以随意定义,只要在同一个LoadManager中不重复即可。

args:加载Loader的参数,可空

callback:LoaderManager.LoaderCallbacks接口,有三个方法:(1)Loader<D> onCreateLoader(int id, @Nullable Bundle args),返回创建的Loader,返回我们自定义的CursorLoader即可。(2)void onLoadFinished(@NonNull Loader<D> loader, D data),当数据加载成功时,对应CursorLoader而言,data是一个Cursor,可以直接使用。(3)void onLoaderReset(@NonNull Loader<D> loader),当Loader重置时,此时可以进行清空数据的操作。

 最终显示的数据是一个Cursor,然后显示Cursor的内容。如果使用ListView,GridView来显示比较简单,可以直接继承CursorAdapter即可,然后解析Cursor中的内容来显示。对应RecyclerView则需要对Cursor进行转换处理。

显示图片,对于图片文件直接显示即可;对于视频可以显示其缩略图,显示失败则需要显示视频的第一帧图片;对于其他文件则只能来显示其文件类型名称了。可以自己写加载器或者选择第三方的加载器。

上篇部分就先说到这儿,后面我们开始着手写代码的实现。

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值