最近需要获取手机中已安装应用的大小,查阅了一些资料,这里做个总结:
1,在我们可见调用的类中没有提供直接的方法来获取应用的大小,应用的大小分为了缓存大小(cachesize),数据大小(datasize),应用程序大小(codesize),但是PackageManager类有个getPackageSizeInfo方法如下:
public abstract void getPackageSizeInfo(String packageName,
IPackageStatsObserver observer);
只是这个方法是hide的,我们并不可以直接调用,所以我们需要用到反射,且涉及到AIDL
2,安装包得大小信息封装在PackageStats类中,我们需要获得安装包所对应的PackageStats对象,才可以获取我们需要的大小信息
3,以下为获取应用大小信息步骤:
第一步:
加入Android系统形成的AIDL文件:
1)IPackageStatsObserver.aidl中代码如下:
package android.content.pm;
import android.content.pm.PackageStats;
/**
* API for package data change related callbacks from the Package Manager.
* Some usage scenarios include deletion of cache directory, generate
* statistics related to code, data, cache usage(TODO)
* {@hide}
*/
oneway interface IPackageStatsObserver {
void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
}
2)PackageStats.aidl代码如下:
package android.content.pm;
parcelable PackageStats;
第二步:创建一个类继承IPackageStatsObserver.Stub,实际为aidl文件形成的Bindler机制服务类,当把该类的一个实例通过getPackageSizeInfo()调用时,该函数继而启动中间流程去获取相关包得信息大小,最后将查询信息回调至该类的onGetStatsCompleted(in PackageStats pStats, boolean succeeded)方法中,代码如下:
//aidl文件形成的Bindler机制服务类
public class PkgSizeObserver extends IPackageStatsObserver.Stub {
private String totalSize;
private String pakgeName;
private long cachesize;
private long datasize;
private long codesize;
public PkgSizeObserver(String pakgeName) {
this.pakgeName = pakgeName;
}
/*** 回调函数,
* @param pStats ,返回数据封装在PackageStats对象中
* @param succeeded 代表回调成功
*/
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
//缓存大小
cachesize = pStats.cacheSize;
//数据大小
datasize = pStats.dataSize;
//应用程序大小
codesize = pStats.codeSize;
totalSize = formateFileSize(pStats.cacheSize + pStats.dataSize + pStats.codeSize);
L.e("总大小---" + totalSize + "---缓存大小-----" + cachesize + "--数据大小----" + datasize + "--应用程序大小---" + codesize);
}
}
//系统函数,字符串转换 long -String (kb)
private String formateFileSize(long size){
return Formatter.formatFileSize(mActivity, size);
}
第三步:下面我们就用到反射,直接调用第二步写好的类,上代码
//得到大小
public void queryPacakgeSize(String pkgName) throws Exception {
if (pkgName != null) {
//使用反射机制得到PackageManager类的隐藏函数getPackageSizeInfo
PackageManager pm =context.getPackageManager(); //得到pm对象
try {
//通过反射机制获得该隐藏函数
Method getPackageSizeInfo = PackageManager.class.getDeclaredMethod(“getPackageSizeInfo”, String.class, IPackageStatsObserver.class);
//调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数
getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver(pkgName));
} catch (Exception ex) {
Log.e(TAG, "NoSuchMethodException");
ex.printStackTrace();
throw ex; // 抛出异常
}
}
}
到此我们就可以得到应用的大小了
4,这里说个坑,我在应用过程中发现,得到缓存,数据,应用大小的回调函数是在子线程中的,所以并不能在onGetStatsCompleted方法中更新UI,且我获取的是很多应用列表,想在item中写入大小,这里因为线程抢占时间不同,item更新并不能同时进行,可以观察手机设置中应用程序获取大小也并不是同时进行,所以如果需要列表设置应用大小注意处理线程问题