- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章Android APP与媒体存储服务的交互由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
简介: 本文介绍如何在 Android 中,开发者的 APP 如何使用媒体存储服务(包含MediaScanner、MediaProvider以及媒体信息解析等部分),包括如何把 APP 新增或修改的文件更新到媒体数据库、如何在多媒体应用中隐藏 APP 产生的文件、如何监听媒体数据库的变化等等。 Android 原生有一套媒体存储服务,进程名是 android.process.media,主要负责把磁盘中的文件信息保存到数据库当中,供其他 APP 使用以及 MTP 模式使用。因此 APP 可以随时快速查询到机器上有多少音乐,音乐的时长、标题、艺术家、专辑封面都可以获取到。下面就介绍我们开发的 APP 如何与这个媒体存储服务打交道。 Note:MTP 模式是 Android 3.0 开始引入的,其数据来源于媒体存储服务。 隐藏多媒体文件 应用场景:APP 产生了图片/音乐/视频类文件,不想让它显示在图库/音乐播放器。市面上有不少游戏,它的图片和音效文件没有做隐藏,出现在用户的图库/音乐播放器当中,引起用户反感。如果用户把它删除了,又可能会影响 APP 正常运行.
方法一:把文件设为隐藏。Linux 里文件前加点就是隐藏,例如“文件A”改成“.文件A”。或者把文件扩展名去掉,这样媒体存储服务扫描时就不会将其当作多媒体文件。 方法二:在文件夹下生成一个名为“.nomedia”的空白文件。这样同一个文件夹下的所有文件都不会被当作多媒体文件.
添加/修改多媒体文件 应用场景:APP 创建了一个新的多媒体文件,或者修改了一个已有多媒体文件。例如 APP 下载了一个音乐文件,需要通知媒体存储服务,用户就能在音乐播放器中看到这个文件。否则,只有下次媒体存储服务开始扫描整个磁盘,才会发现 APP 产生的新文件.
方法一 如果只有一个文件,并且不需要得到结果返回,直接发 Intent 通知媒体存储服务即可.
import java.io.File; import android.content.Context; import android.content.Intent; import android.net.Uri,
。
private static void requestScanFile(Context context, File file) { Intent i = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); i.setData(Uri.fromFile(file)); context.sendBroadcast(i); } 。
private static void requestScanFile(Context context, String file) { Intent i = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); i.setData(Uri.parse("file://" + Uri.encode(file))); context.sendBroadcast(i); } 。
Note:如果使用 Uri.parse() 从文件名生成 Uri,文件名必须要先 Uri.encode(),作用是把保留字符转义。例如文件名若包含“?”,不经过 Uri.encode 转义的话会被当作是查询参数,这样 uri.getPath() 获取的文件路径会丢失“?”之后的部分.
。
方法二 如果只有一个文件,并且需要文件 uri 结果返回,则使用回调函数.
import android.media.MediaScannerConnection; import android.net.Uri,
。
private void requestScanFile(Context context, String file) { MediaScannerConnection.scanFile(context, new String[] {file}, null, // mime types,可不指定 mListener); } 。
MediaScannerConnection.OnScanCompletedListener mListener = new MediaScannerConnection.OnScanCompletedListener() { public void onScanCompleted(String path, Uri uri) { // TODO: 获取到该文件在多媒体数据库中的 uri,进行下一步动作 } },
Note:还有一种方法,可以先往多媒体数据库插入一条包含文件路径的记录,插入后可以得到其 uri;然后再使用方法一通知媒体存储服务扫描此文件,把文件信息(如专辑名)补充完整。但不推荐使用这种方法,因为获得 uri 时文件信息并不完整.
。
方法三 如果文件较多,则发 Intent 通知媒体存储服务扫描整个磁盘。这种做法不是特别好,但又没发现其他更好的接口。第三方文件管理如“ES 文件管理器”就是使用这种方法的.
import android.content.Context; import android.content.Intent; import android.net.Uri,
。
private static void requestScanDisk(Context context) { Intent i = new Intent(Intent.ACTION_MEDIA_MOUNTED); String path = Environment.getExternalStorageDirectory().getPath(); i.setData(Uri.parse("file://" + Uri.encode(path))); context.sendBroadcast(i); } 。
。
监听数据变化 应用场景:多媒体数据库有变化,需要刷新 APP 显示界面。比较好理解,磁盘中的多媒体文件有新增、删除或者修改,APP 界面上要实时反应这些变化,刷新显示界面.
方法一 监听媒体存储相关 Intent。接受到 Intent 后,重新查询一次数据库。我们需要注意的 Intent 主要有以下几个: 1、Intent.ACTION_MEDIA_SCANNER_FINISHED: 媒体存储服务扫描整个磁盘完成后会发这个 Intent。可能有新增较多文件或者被删除。 2、Intent.ACTION_MEDIA_SCANNER_SCAN_FILE: 媒体存储服务扫描单个文件.
import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.Uri,
。
private void registerReceiver(Context context) { IntentFilter filter = new IntentFilter(Intent.ACTION_MEDIA_MOUNTED); filter.addAction(Intent.ACTION_MEDIA_SCANNER_FINISHED); filter.addAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE); filter.addDataScheme("file"); context.registerReceiver(mReceiver, filter); } 。
private BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); Uri uri = intent.getData(); if (uri != null && uri.getScheme().equals("file")) { Log.v("Receiver", "BroadcastReceiver action = " + action + ", uri = " + uri); if (Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)) { String filePath = uri.getPath(); // TODO: filePath 文件已改变,APP 刷新界面 } else if (Intent.ACTION_MEDIA_SCANNER_FINISHED.equals(action)) { // TODO: 整个磁盘扫描完成,APP 刷新界面 } } } },
另外,在 Intent.MEDIA_SCANNER_STARTED 和 Intent.ACTION_MEDIA_SCANNER_FINISHED 之间的时间里,媒体存储服务正在扫描文件,数据库会有变化,所以只有在收到 Intent.ACTION_MEDIA_SCANNER_FINISHED 之后查询的结果才是准确的。如果要检测媒体存储服务是否在扫描可以用以下方法:
import android.content.ContentResolver; import android.database.Cursor; import android.os.Environment; import android.provider.MediaStore,
。
private static boolean isMediaScannerScanning(ContentResolver cr) { Cursor cursor = null; try { cursor = cr.query(MediaStore.getMediaScannerUri(), new String[] { MediaStore.MEDIA_SCANNER_VOLUME}, null, null, null); if (cursor != null && cursor.getCount() > 0) { cursor.moveToFirst(); return "external".equals(cursor.getString(0)); } } finally { if (cursor != null) { cursor.close(); } } 。
return false; } 。
Note:APP 可能还需要监听存储设备的变化,例如 SD 卡拔出、磁盘挂载出去(USB 大容量存储模式)等等,这些情况下可能要把文件显示界面清空,或者退出程序。各个手机对于每个 Intent 定义可能略有不同,但基本上是以下几个: 1、Intent.ACTION_MEDIA_EJECT: 存储设备正常移除,例如在设置里卸载存储器。 2、Intent.ACTION_MEDIA_UNMOUNTED: 存储设备正常卸载,通常与 EJECT 先后出现。 3、Intent.ACTION_MEDIA_BAD_REMOVAL: 非正常移除存储设备,例如硬插拔 SD 卡.
。
方法二 监听数据库变化。如果需要在数据库发生变化时能实时接收到通知,可以使用 ContentObserver.
import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri,
。
private ContentObserver mContentObserver = new ContentObserver(null) { @Override public void onChange(boolean selfChange) { // 往后兼容 onChange(selfChange, null); } public void onChange(boolean selfChange, Uri uri) { // TODO: 数据已改变,APP 重新查询数据库并刷新界面 } },
private void setupCursor(Context context, Cursor c) { c.unregisterContentObserver(mContentObserver); // c 为需要显示的数据 } 。
此外,使用 CursorAdapter 和显示的 ListView 绑定,也可以达到同样目的。当 Cursor 内容发现变化,ListView 也会相应自动刷新.
最后此篇关于Android APP与媒体存储服务的交互的文章就讲到这里了,如果你想了解更多关于Android APP与媒体存储服务的交互的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
在 python 交互中,有没有办法在每次输入命令后自动从 python 文件执行方法? 例如:如果我有一个打印文件信息的方法,但我不想不断调用该方法,我怎样才能让它在 python 交互中的每个命令
当你使用Edge等浏览器或系统软件播放媒体时,Windows控制中心就会出现相应的媒体信息以及控制播放的功能,如图。 SMTC (SystemMedia
我在主菜单上使用标准的剪切,复制,粘贴操作。它们具有快捷键Ctrl-X,Ctrl-C和Ctrl-V。 当我打开模态表单时FindFilesForm.ShowModal,然后所有快捷方式都可以从表单中使
这是我想要实现的目标:打开一个 shell(korn 或 bash,没关系),从那个 shell,我想打开一个 ssh 连接(ssh user@host)。在某些时候,可能会提示我输入密码,或者可能会
我正在测试在C / C++程序中嵌入Python,但是我缺乏理解。 测试程序很简单: 初始化解释器; 从启动Timer的文件中执行python脚本(每0.1秒增加一个变量); 等待5秒(C++); 从
我正在尝试用java创建Excel文件。现在,我正在使用 Apache POI 库创建文件并将其保存到本地驱动器。有没有办法启动 Excel 并填充数据而不将其保存到硬盘驱动器? 最佳答案 考虑 Do
我有一个黑盒函数,它接受大约 10 个整数输入。该函数返回一个 pandas 数据框,我想捕获输出窗口(通过使用 bbwidget.children)并显示在布局中的其他地方。到目前为止,交互/交互似
我正在体验新的 QQuickWidget。我如何在 QQuickWidget 和 C++ 之间进行交互? C++ QQuickWidget *view = new QQuickWidget(); vi
我正在尝试设置一个使用 TWAIN 的 C# 应用程序 example from code project 除了我需要将 Form 转换为 IMessageFilter 和调用 IMessageFil
我想在使用 redis 的 python 中编写应用程序。我用谷歌搜索,但找不到我的问题的任何结果。通常,我这样做: import redis rs = redis.Redis('localhost'
最近做一个小项目,网页中嵌入google maps,输入经纬度坐标可以定位地图位置并加注标记,点击标记获取远端摄像头数据并在视频窗口实现播放。在实际操作过程中,由于经纬度数据和视频登录的用户名密码数
我需要在这里澄清一些事情: 我有一个网站,每次在浏览器中重新加载网站时都会更新两个变量的值。这个页面显然是一个 HTML 页面,但变量是由 javascript 函数更新的。此页面在我的服务器上运行。
我注意到,auto忽略双条件。这是一个简化的示例: Parameter A B : Prop. Parameter A_iff_B : A B. Theorem foo1: A -> B. Proo
使用 interactive使用多个小部件相当简单,例如: interactive(foo, w1=widget1, w2=widget2, ...) 但是,我想使用 VBox 和 HBox 的组合以
我们提供类似于 imagemagick 的浏览器页面 JavaScript,可帮助人们将图像转换为不同大小和格式。但是,它需要网页交互。 是否可以让人们自动进行这种交互——无需将图像发送到我们的服务器
大家好,我正在尝试制作一个具有大量动画和效果的交互式 UI。 但我不知道是否: 核心图形可以支持用户交互(触摸、拖动等) 核心图形支持对象旋转 核心图形可以以任何方式与 UIKit 和核心动画交互 谢
这是获取维基百科上一篇关于高盛的文章的介绍的链接。 http://en.wikipedia.org/w/api.php?action=query&prop=extracts&titles=Goldma
我正在尝试编写一个 AppleScript 来查询 iCal 并在任何日历中查找给定日期的所有事件。 我首先编写了一个简单的脚本,它对给定日历中的每个事件执行一些简单的操作: tell applica
我在我的 hudson 服务器上使用 jira 插件。将代码提交到 svn 时,我的提交注释包含在我的 jira 问题中,但有什么办法可以将注释归因于执行提交的实际人员,而不是让一个全局 jira 用
我正在播放一段视频来装饰我的用户界面。我隐藏了 AV 播放器控件,但用户仍然可以控制视频。例如,他们可以使用滑动手势快进或快退。 这让我特别惊讶,因为 AVPlayerView 上面有一个覆盖 Vie
我是一名优秀的程序员,十分优秀!