Android media媒体库分析之:分类别统计媒体文件大小
转载自:http://www.linuxidc.com/Linux/2015-03/114754.htm
=====================================================================================================
对系统媒体库不了解的线看这儿:
- Androidmedia媒体库分析之:MediaProviderhttp://www.linuxidc.com/Linux/2015-03/114755.htm
- Android media媒体库分析之:调用系统媒体库完成指定媒体文件扫描http://www.linuxidc.com/Linux/2015-03/114756.htm
先看一下要实现的效果:
上图是系统设置中分类别对文件所占空间的统计,项目中要统计媒体文件所占空间,于是研究了一下系统的做法,收获如下:
1、从源码packages/app/下找到settings工程,找到存储功能的实现,相关类有:
com.android.settings.deviceinfo.StorageMeasurement
com.android.settings.deviceinfo.StorageVolumePreferenceCategory
其他相关源码:
com.android.defcontainer.DefaultContainerService
StorageMeasurement类中启动服务,绑定服务,通知界面更新;
StorageVolumePreferenceCategory显示界面
StorageMeasurement中建立了与DefaultContainerService服务的通信,指定要扫描的目录:
/** Media types to measure on external storage. */ private static final Set<String> sMeasureMediaTypes = Sets.newHashSet( Environment.DIRECTORY_DCIM, Environment.DIRECTORY_MOVIES, Environment.DIRECTORY_PICTURES, Environment.DIRECTORY_MUSIC, Environment.DIRECTORY_ALARMS, Environment.DIRECTORY_NOTIFICATIONS, Environment.DIRECTORY_RINGTONES, Environment.DIRECTORY_PODCASTS, Environment.DIRECTORY_DOWNLOADS, Environment.DIRECTORY_ANDROID);上面这个set就是定义了我们系统里面常用的目录:
public static String DIRECTORY_DOWNLOADS = "Download";public static String DIRECTORY_DCIM = "DCIM";public static String DIRECTORY_MUSIC = "Music";public static String DIRECTORY_PICTURES = "Pictures";public static String DIRECTORY_MOVIES = "Movies";...获取每个目录的大小:
for (String type : sMeasureMediaTypes) { final File path = currentEnv.getExternalStoragePublicDirectory(type); final long size = getDirectorySize(imcs, path); details.mediaSize.put(type, size); }
其中getDirectorySize方法通过IMediaContainerService调用了DefaultContainerService服务中的方法,在DefaultContainerService中获取到所有信息之后回调IMediaContainerService,再更新界面;
也就是说:系统只统计了上述几个目录的大小(sMeasureMediaTypes中定义的),如果你的歌曲是拷贝到其他目录,那系统存储里面是不会统计使用量。看来Android也不是很智能嘛!!!难度是考虑效率???
2、如何获取某个目录的大小?
先看一下系统是怎么做的:
下面方法是在DefaultContainerService中定义的,获取某一目录大小,获取某一文件大小;
@Override public long calculateDirectorySize(String path) throws RemoteException { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); final File directory = new File(path); if (directory.exists() && directory.isDirectory()) { return MeasurementUtils.measureDirectory(path); } else { return 0L; } } @Override public long[] getFileSystemStats(String path) { Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND); try { final StructStatFs stat = Libcore.os.statfs(path); final long totalSize = stat.f_blocks * stat.f_bsize; final long availSize = stat.f_bavail * stat.f_bsize; return new long[] { totalSize, availSize }; } catch (ErrnoException e) { throw new IllegalStateException(e); } }
但是
MeasurementUtils.measureDirectory(path)和Libcore.os.statfs(path)
两个方法我们都调不到,怎么办?
我们把MeasurementUtils类从源码中拷贝出来到我们的功能,但注意要保留包路径,否则可以编译通过,但无法运行,因为他里面用到了一个本地方法,需要加载一个so文件。如下:
这样就可以解决第一个问题了;
再来看第二方法,其实这个方法我们用不到,我们已经通过第一个方法获取到指定文件夹的大小了,那关于某一个文件的大小我们之间通过file可以拿到。
第二个方法有一个封装类:starfs,可以获取rom、sdcard的总大小和可用空间,如下:
/** * The size, in bytes, of a block on the file system. This corresponds to * the Unix {@code statfs.f_bsize} field. */ public int getBlockSize() { return (int) mStat.f_bsize; } /** * The total number of blocks on the file system. This corresponds to the * Unix {@code statfs.f_blocks} field. */ public int getBlockCount() { return (int) mStat.f_blocks; }
这个可以直接在我们获取总体容量时使用。
上面把系统是怎么做的大概搞清楚,下面我们来实现我们的需求:
一、思路:
1、Android media媒体库分析之:调用系统媒体库完成指定媒体文件扫描http://www.linuxidc.com/Linux/2015-03/114756.htm
这篇文章可以知道,媒体文件(音频、视频、图片)系统完成扫描之后就存入了数据库,那我们可以查询数据库,得到所有媒体文件,把这些文件的大小相加。
2、由于sdcard可以会unmount,所以在相加时要根据路径判断此文件是否存在;
3、下面时我实现的工具类,希望对你有用:
package com.linuxidc.jerome;import java.io.File;import java.util.ArrayList;import android.content.Context;import android.database.Cursor;import android.net.Uri;import android.os.Environment;import android.os.StatFs;import android.provider.MediaStore;public class MemoryUtil { Context mContext; public MemoryUtil(Context context) { mContext = context; } /** * 获得SD卡总大小 * * @return */ public long getSDTotalSize() { File path = Environment.getExternalStorageDirectory(); StatFs stat = new StatFs(path.getPath()); long blockSize = stat.getBlockSize(); long totalBlocks = stat.getBlockCount(); return blockSize * totalBlocks; } /** * 获得sd卡剩余容量,即可用大小 * * @return */ public long getSDAvailableSize() { File path = Environment.getExternalStorageDirectory(); StatFs stat = new StatFs(path.getPath()); long blockSize = stat.getBlockSize(); long availableBlocks = stat.getAvailableBlocks(); return blockSize * availableBlocks; } /** * 获得机身内存总大小 * * @return */ public long getRomTotalSize() { File path = Environment.getDataDirectory(); StatFs stat = new StatFs(path.getPath()); long blockSize = stat.getBlockSize(); long totalBlocks = stat.getBlockCount(); return blockSize * totalBlocks; } /** * 获得机身可用内存 * * @return */ public long getRomAvailableSize() { File path = Environment.getDataDirectory(); StatFs stat = new StatFs(path.getPath()); long blockSize = stat.getBlockSize(); long availableBlocks = stat.getAvailableBlocks(); return blockSize * availableBlocks; } /** * 外部存储中所有音频文件所占内存 * * @return */ public long getAudioTotalSize() { ArrayList<MemoryInfo> resultList = queryAllMediaList(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI); long size = 0L; for (MemoryInfo cInfo : resultList) { File file = new File(cInfo.getFilePath()); if(null!=file &&file.exists()){ size += cInfo.getFileSize(); } } return size; } /** * 外部存储中除音频、视频、图片之前其他文件所占内存 * * @return */ public long getOtherTotalSize() { long size = getSDTotalSize() - getSDAvailableSize() - getPictureTotalSize() - getVideoTotalSize() - getAudioTotalSize(); if (size < 0L) { size = 0L; } return size; } /** * 外部存储中所有图片文件所占内存 * * @return */ public long getPictureTotalSize() { ArrayList<MemoryInfo> resultList = queryAllMediaList(MediaStore.Images.Media.EXTERNAL_CONTENT_URI); long size = 0L; for (MemoryInfo cInfo : resultList) { File file = new File(cInfo.getFilePath()); if(null!=file &&file.exists()){ size += cInfo.getFileSize(); } } return size; } /** * 外部存储中所有视频文件所占内存 * * @return */ public long getVideoTotalSize() { ArrayList<MemoryInfo> resultList = queryAllMediaList(MediaStore.Video.Media.EXTERNAL_CONTENT_URI); long size = 0L; for (MemoryInfo cInfo : resultList) { File file = new File(cInfo.getFilePath()); if(null!=file &&file.exists()){ size += cInfo.getFileSize(); } } return size; } public ArrayList<MemoryInfo> queryAllMediaList(Uri uri) { //我们只需要两个字段:大小、文件路径 Cursor cursor = mContext.getContentResolver().query( uri,new String[] { MediaStore.Audio.Media.SIZE, MediaStore.Audio.Media.DATA }, null, null, null); ArrayList<MemoryInfo> musicList = new ArrayList<MemoryInfo>(); try{ if (cursor.moveToFirst()) { do { MemoryInfo mInfo = new MemoryInfo(); mInfo.setFileSize(cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE))); mInfo.setFilePath(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA))); }while(cursor.moveToNext()); } }finally{ if(cursor != null){ cursor.close(); } } return musicList; } class MemoryInfo { private long fileSize = 0L; private String filePath = ""; public long getFileSize() { return fileSize; } public void setFileSize(long fileSize) { this.fileSize = fileSize; } public String getFilePath() { return filePath; } public void setFilePath(String filePath) { this.filePath = filePath; } }}
更多相关文章
- 跑马灯结合TextSwitcher实现系统公告栏
- Android 通过按钮弹出系统菜单(通过Button显示菜单)转
- 如何更改android Studio logcat字体大小?
- 打开android 系统联系人
- android 9.0获取mac地址的方法
- Android实现音量调节的方法
- android的系统属性设置和应用
- android常用intent的方法