Android media媒体库分析之:分类别统计媒体文件大

对系统媒体库不了解的线看这儿:

先看一下要实现的效果:

Android media媒体库分析之:分类别统计媒体文件大

上图是系统设置中分类别对文件所占空间的统计,项目中要统计媒体文件所占空间,于是研究了一下系统的做法,收获如下:

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文件。如下:


这样就可以解决第一个问题了;

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/0f062c5a9a7e8d96a8d365d19af0263c.html