Android多媒体行业,Android多媒体管理浅析

简介

Android多媒体文件管理简单来说,有三个部分

扫描:MediaScannerService

存储:MediaProvider

查询:MediaStore

MediaScannerService

值得一提的是,MediaScannerService这类文件,AndroidStudio中不能直接search到,需要去官网查询其源码,这里推荐一个在线查看Android源码的链接androidxref.com/

public class MediaScannerService extends Service implements Runnable

// 核心方法

private void scan(String[] directories, String volumeName) {

...

try {

...

try {

...

MediaScanner scanner = createMediaScanner();

scanner.scanDirectories(directories, volumeName);

} catch (Exception e) {

...

}

...

} finally {

...

}

}

复制代码

应用级Service,用于媒体文件扫描

scan是其核心方法,从源码中可以看出,最终是调用了MediaScanner的scanDirectories方法

MediaScannerReceiver

与MediaScannerService配套的BroastReceiver

@Override

public void onReceive(Context context, Intent intent) {

final String action = intent.getAction();

final Uri uri = intent.getData();

if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {

// Scan both internal and external storage

scan(context, MediaProvider.INTERNAL_VOLUME);

scan(context, MediaProvider.EXTERNAL_VOLUME);

} else {

if (uri.getScheme().equals("file")) {

// 省略...

if (Intent.ACTION_MEDIA_MOUNTED.equals(action)) {

// scan whenever any volume is mounted

scan(context, MediaProvider.EXTERNAL_VOLUME);

} else if (Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action) &&

path != null && path.startsWith(externalStoragePath + "/")) {

scanFile(context, path);

}

}

}

}

复制代码

从onReceive方法中可以看出,MediaScannerReceiver执行scan的时机有三种

启动完毕,扫描内部存储和外部存储

sdcard挂载完毕,扫描外部存储

扫描单个文件

MediaScanner

具体执行scan动作的类

MediaScannerProvider

ContentProvider用于保存查询结果,结果由数据库保存

以外部存储为例,数据库的路径为/data/data/com.android.providers.media/databases/external.db

MediaStore

MediaStore是面向应用的入口,作用了是为了便于用户查询已经扫描过的数据

MediaStore中的资源有四类

MediaStore.Files

MediaStore.Audio

MediaStore.Images

MediaStore.Video

媒体库查询

核心方法

public final @Nullable Cursor query(@RequiresPermission.Read

@NonNull Uri uri,

@Nullable String[] projection,

@Nullable String selection,

@Nullable String[] selectionArgs,

@Nullable String sortOrder)

复制代码

Uri uri

Uri uri = MediaStore.Video.Media.INTERNAL_CONTENT_URI;

Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

复制代码

Uri总共有两种,分别对应内部存储和外部存储

String[] projection

String[] mediaColumns = {

MediaStore.Video.Media.DATA,

MediaStore.Video.Media.SIZE,

MediaStore.Video.Media.DATE_MODIFIED,

MediaStore.Video.Media.DURATION};

复制代码

用于指定查询后,返回给用户的媒体信息

String selection & String[] selectionArgs

这两个是可选项,用户可以通过这两个参数,定制化查询条件

String selection = MediaStore.Video.Media.MIME_TYPE + "=? or "

+ MediaStore.Video.Media.MIME_TYPE + "=? or "

+ MediaStore.Video.Media.MIME_TYPE + "=? or "

+ MediaStore.Video.Media.MIME_TYPE + "=? or "

+ MediaStore.Video.Media.MIME_TYPE + "=?"

String[] selectionArgs = new String[]{"video/mp4", "video/avi", "video/quicktime", "video/webm", "video/x-ms-wmv"}

复制代码

需要注意的是,selection中的条件和selectionArgs数组中的类型,需要是一一对应的,否则会发生异常

String sortOrder

查询的排序方式

.nomedia

文件夹中新建一个.nomedia的空文件,会屏蔽掉系统默认的媒体库扫描。遇到带有该文件的文件夹,只能通过文件遍历的方式进行扫描

MIME_TYPE

需要注意的是MIMETYPE不一定和文件的扩展名一致,比如mov格式的文件,MIMETYPE为video/quicktime等等

新增视频资源并通知手机相册

基本方法

方法一:发送广播,通知媒体库刷新

Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);

intent.setData(Uri.fromFile(new File(filePath)));

context.sendBroadcast(intent);

复制代码

方法二:插入数据库

也可以使用直接插入媒体库数据库的方法来实现(但这两种方法不能同时使用,会导致媒体库中出现重复的数据)

ContentValues values = new ContentValues(4);

values.put(MediaStore.Video.Media.TITLE, "");

values.put(MediaStore.Video.Media.MIME_TYPE, minetype);

values.put(MediaStore.Video.Media.DATA, path);

values.put(MediaStore.Video.Media.DURATION, duration_int);

context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);

复制代码

插入数据库的这种方法,这边博文中有详细介绍blog

方法三:MediaScannerConnection.scanFile

public static void insert(Context context, String[] paths, String[] types) {

MediaScannerConnection.scanFile(

context,

paths,

types,

new MediaScannerConnection.OnScanCompletedListener() {

@Override

public void onScanCompleted(String path, Uri uri) {

LogUtils.i(TAG, "insert onScanCompleted path " + path + " uri " + uri);

}

});

}

复制代码

机型适配

部分机型上述两种方法都不能实现实时刷新(只能重启手机才能看到效果),考虑可能是第三方ROM的改动导致的,将目录设置为/sdcard/DCIM/Camera可以解决大部分机型的问题,但vivo和魅族的手机仍旧不能刷新,vivo的地址应该为/sdcard/相机,魅族的地址应该为/sdcard/DCIM/Video

下面给出一个获取输出地址的方法

public static String getVideoOutputDir() {

String sdcardPath = Environment.getExternalStorageDirectory().getPath() + File.separator;

String brand = SystemUtil.getDeviceBrand();

if (TextUtils.isEmpty(brand)) {

return sdcardPath + "DCIM" + File.separator + "Camera";

}

brand = brand.toLowerCase();

if (brand.contains("vivo")) {

return sdcardPath + "相机";

} else if (brand.contains("meizu")) {

return sdcardPath + "DCIM" + File.separator + "Video";

}

return sdcardPath + "DCIM" + File.separator + "Camera";

}

public static String getDeviceBrand() {

return android.os.Build.BRAND;

}

复制代码

值得一提的是,如果想删除相册中的某个资源文件,OPPO的某些机型(ColorOS 3.1系统),会弹窗提示:删除图库中的照片和视频权限申请,需要用户手动去确认删除。这个没有特别好的办法

参考资料

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值