`

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

阅读更多
转自http://www.linuxidc.com/Linux/2015-03/114754.htm


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

    Android media媒体库分析之:MediaProvider http://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;
  }
}
}
分享到:
评论

相关推荐

    android-media-picker,一个简单易用的媒体选择器android库。从设备中选择任何图像、视频或音频.zip

    1. **设计目的**:Android Media Picker的目标是为开发者提供一个轻量级、高度可定制的媒体选择解决方案,使用户可以快速浏览和选择设备上的多媒体文件,无需编写大量的自定义代码。 2. **功能特性**:该库支持多选...

    androidx.media3.exoplayer,编译好的libvp9(libvpx)库

    6. **多媒体扩展**:AndroidX.media3库可能还包含了其他媒体相关的组件,可以方便地扩展到其他格式或特性,如AAC音频解码、HDR视频支持等。 7. **动态 Adaptive Streaming**:ExoPlayer支持DASH(Dynamic Adaptive ...

    android多媒体框架详细分析

    - **动态库的加载**: 根据需要动态加载所需的库文件。 - **omx_interface的实现**: 实现OMX (OpenMAX)接口,以支持多媒体编解码器。 - **注册表的填充**: 将编解码器信息注册到系统中,以便于管理和使用。 #### 七...

    Android多媒体构架分析

    4. 相册和媒体库:提供媒体文件的存储和检索功能,使得应用能够访问和管理用户媒体库。 5. 多媒体文件格式和编解码器:定义了Android系统支持的多媒体文件格式,以及如何使用编解码器来处理这些格式。 通过这份...

    android media

    8. **Pro Android Media Source Code**: 这个文件可能包含了一系列关于Android多媒体处理的示例代码,涵盖上述提到的各个知识点。通过学习这些代码,开发者可以更好地理解如何在实际项目中应用Android的多媒体API。 ...

    Android多媒体框架分析.pdf

    2. Media Framework:Media Framework 是 Android 多媒体框架的主要组件,负责音视频播放、下载、流媒体等任务。 3. OpenMAX 1L 接口:OpenMAX 1L 是一个开放的多媒体接口标准,提供了一套通用的可扩展接口,支持...

    Pro.Android.Media--Android多媒体开发白皮书

    根据给定的信息,“Pro.Android.Media--Android多媒体开发白皮书”是一本专注于Android平台上多媒体应用开发的专业书籍。本书由Shawn VanEvery编写,详细介绍了如何使用Android多媒体API创建动态移动应用,包括图形...

    Android 拍照更新媒体库,相册选取图片显示

    总的来说,实现"Android 拍照更新媒体库,相册选取图片显示"的功能需要对Android权限管理、意图交互、文件操作以及媒体库更新有深入理解。通过合理的设计和编程,我们可以提供一个流畅且可靠的用户体验,让用户能够...

    Android多媒体框架分析

    - **pvcommon**、**pvplayer**、**pvauthor**:库文件的Android.mk文件,无源文件。 - **tools_v2**:编译工具及可注册模块。 **Android Media APIs**: - **MediaPlayer**:用于播放音频和视频媒体。支持本地文件...

    android mediaScannder框架介绍

    Android多媒体扫描框架,即Media Scanner,是Android系统中用于检测和处理...当有新的媒体文件出现或已有的文件发生变化时,Media Scanner通过接收广播意图并进行扫描,确保媒体库始终与实际存储的媒体文件保持同步。

    android media framework

    OpenCORE是Google开发的一套开源媒体库,包含了多种音视频编解码器、音视频播放器等组件,是Android多媒体框架的基础。 ##### 2. OpenMAX OpenMAX (Open Media Abstraction Layer) 是一个跨平台的API规范,旨在提供...

    android 媒体键监听 以及 媒体键模拟

    在Android开发中,媒体键监听和模拟媒体键盘的实现是两个重要的功能,它们涉及到系统级事件处理和自定义用户交互。下面将详细讲解这两个概念及其实现。 首先,媒体键监听是指应用程序能够捕获并响应系统中的媒体键...

    Android多媒体框架初步分析

    ### Android多媒体框架初步分析 #### 一、多媒体框架概述 Android多媒体框架是Android系统中一个重要的组成部分,负责处理各种多媒体内容如音频、视频和图片。该框架基于第三方PacketVideo公司的OpenCORE平台实现...

    VLC播放流媒体arr文件

    在Android平台上使用VLC进行流媒体播放时,有时会涉及到特定的配置文件,例如“arr”文件。这个文件对于理解VLC在Android上的流媒体处理机制至关重要。 "arr"文件全称为"Advanced Playlist Representation",它是...

    Pro Android学习:media frameworks小例子

    5. **使用MediaStore**:可能的例子是将录制的媒体文件插入到MediaStore,以便用户可以通过系统的媒体库访问,或者通过ContentResolver查询录制文件的信息。 在`TestMedia`这个文件中,可能包含了实现以上操作的...

    Pro Android media development安卓媒体开发

    1. **Android Media Framework**:Android的媒体框架是多媒体开发的基础,它提供了对音频、视频和图像处理的底层支持。开发者需要理解Media Framework的层次结构,包括MediaCodec、MediaPlayer、MediaRecorder等组件...

    android media source

    在Android系统中,媒体源(Media Source)是一个关键的概念,它是多媒体播放的基础。Media Source代表了一个可以提供连续媒体数据的源头,例如音频、视频或它们的组合。Android平台提供了多种方式来创建和处理媒体源...

    Android MediaProjection截屏&amp;录屏-适配Android

    Android MediaProjection截屏&录屏 1、解决Android Q中java.lang.SecurityException: Media projections require a foreground service of type ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PROJECTION 异常 2、...

    android的多媒体系统.pdf

    - **多媒体库**: `frameworks/base/include/media/` 和 `frameworks/base/media/libmedia/` 目录下的内容,最终编译成`libmedia.so`库。 - **多媒体服务库**: `frameworks/base/media/libmediaplayerservice/` 目录...

    Pro Android Media

    ### Pro Android Media: 开发图形、音乐、视频和丰富的媒体应用程序 #### 一、概述 《Pro Android Media: Developing Graphics, Music, Video, and Rich Media Apps for Smartphones and Tablets》是一本专注于...

Global site tag (gtag.js) - Google Analytics