Android图片编辑器实践指南-2.图片视频选择器(1)

本文深入解析Android的MediaStore类,介绍如何使用MediaStore进行图片和视频的查询,以及如何设计单例模式的MediaChooseComponent组件。文章详细解释了单例设计模式的饿汉模式、懒汉模式和双重判空模式,以及它们在多线程环境下的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇将会介绍媒体选择器,包括图片选择器和视频选择器,更进一步的扩展到根据目录显示不同的图片。

2.1 图片选择器

具体开发图片选择器之前,先说明一下MediaStore类,之后所有的图片操作,查询都和这个类有关系。官网上对这个类的定义为:

The Media provider contains meta data for all available media on both internal and external storage devices.

简单理解就是对外提供设备上所有的媒体,它在android的包目录为:

package android.provider;

这个类属于provider,即ContentProvider组件之一,对外提供接口查询自身的数据。MediaStore这个类就是android系统提供的一个多媒体数据库类,这个类包括了多媒体数据库的所有信息,包括音频,视频和图像。因此用户直接利用ContentResolver调用相关的query方法去获取相关数据。在这个类中定义了较多的内部类,查看官网的API接口可看出包含MediaStore.Audio、MediaStore.Video、MediaStore.Images、MediaStore.Files4个内部类;同时包含了一个接口MediaStore.MediaColumes,该接口定义了所有与媒体相关的数据库标都会用到的数据库字段。见图1:

在这里插入图片描述图1:MediaStore类的结构图

图1显示了MediaStore类的结构图,包含了相关的内部类和MediaColumns接口,这里展开了Images内部类。Images类定义了一个名为ImageColumns的接口,该接口定义了单独针对Image的数据库字段。同时Images类定义类一个名为Media的内部类用于查询和Image相关的信息,此外还定义了一个名为Thumbnails的内部类用于查询和Image相关的缩略图的信息。

下面来看Image.Media的query函数,其代码非常简单,如下所示:
code 1:Image.Media query函数
code 1:Image.Media query函数

说明:可见Image.Media的query函数直接调用ContentResolver的query函数

ContentResolver的query函数分析如下code 2:
在这里插入图片描述
code 2:ContentResolver query函数

说明:

  • uri:指明要查询的数据库名称加上表的名称,从MediaStore类中可以找到相应信息的参数
  • projection:指定查询数据库表中的哪几列
  • selection:指定查询条件
  • selectionArgs:参数selection里有 ?这个符号是,这里可以以实际值代替这个问号。如果selection这个没有?的话,那么这个String数组可以为null。
  • sortOrder:指定查询结果的排列顺序

接下来新建一个包component存放基础的组件,在component里新建一个类MediaChooseComponent。这里思考一下,既然作为一个组件,那么必然是提供所有上层业务所使用的,那么这个类也就存在唯一的实例,因此这个类要设计成单例类。这里详细说明一下单例设计模式。

设计模式-单例

定义:一个类有且仅有一个实例,并且自行实例化向整个系统提供

在app整个生命周期中,往往需要唯一的一个类的实例,那么就应该使用单例模式,因此就类似上文中MediaChooseComponent,具体实现方式有如下几点:

  • 将类的构造方法私有化,使其不能在类的外部通过new来实例化对象
  • 在该类内部定义一个该类的static对象,声明private类型
  • 定义一个静态方法返回这个唯一的对象

实现方法分为饿汉模式,懒汉模式,双重判空

饿汉模式

直接定义并初始化static声明的变量,优点是不存在线程安全问题,缺点是不管你具体用不用这个类,它都会被加载到内存中,如下code3:
在这里插入图片描述
code 3:单例—饿汉模式

懒汉模式

延迟初始化,在需要的时候初始化,存在多线程安全问题,因为Java对象的创建过程不是原子操作,分为好几个步骤,具体可参看Java虚拟机,因此当多个线程同时访问的时候,就会出现线程安全问题,例如线程1判断instance == null,执行实例化过程;这个时候实例化还没完成,线程2同时也判断,此时instance==null 为true,因此也会去实例化对象,就会实例化2个对象出来。如下code4:
在这里插入图片描述
code 4:单例—懒汉模式

双重判空

如下code5,首先判断为空,然后加了锁,再判断下是否为空,如果为空则实例化对象。
在这里插入图片描述
code 5:单例—双重判空

说明:这里使用了final和volatile关键字,final关键字在修饰类的时候,该类不可被继承,因此不会被继承它的类所改变行为;volatile关键字修饰变量的时候表明该变量是对多线程可见的,满足一致性,即各个线程的工作内存能立即发现该变量的改变并保证一致性。

单例模式还有一些其他的实现方案,比如用枚举之类的,就不一一说明了,以上是最基础的实现方法。

现在来修改MediaChooseComponent为如下:首先定义了一个volatile static变量,通过getIns获取,在私有构造方法中初始化mediaResolver;定义了imageMediasCache作为image的缓存,同时定义了2个接口OnMediaChangeListener和OnMediaDirChangListener。从命名可看出是在Media发生改变或者MediaDir发生改变的时候发出通知,这里先忽略Dir相关的逻辑。

在这里插入图片描述
接下来就是获取Image的核心函数,在loadImageMedias方法中使用一个线程异步查询image media;在具体查询过程中,使用ContentResolve结合MediaStore最后生成MediaItem类型的对象加入到ArrayList中,最终得到需要到image数据。finally里面要close cursor。
在这里插入图片描述
总结
此篇初步介绍了MediaStore基础,并结合MediaChooseComponent组件详细介绍了单例设计模式,最终我们通过异步调用queryImageList()获取所有到Image media,并最终存放在数组中。下一篇将会完整实现图片选择器,并加入按照目录选取功能。

更多精彩技术分享请扫码关注小码时间(XiaoMaTime)

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值