今天写了一个程序来获得所有程序的缓存。在写这个程序的过程中遇到了很多的困难,并且一一解决了,现在我来给大家分享一下,如何获得安卓内所有程序的缓存信息:
首先,需要获得所有已经安装的程序的基本信息通过packageManager来拿到
List<PackageInfo> installedPackages = manager.getInstalledPackages(0);
拿到所有的程序基本信息后,通过for循环来拿到程序的包名,然后通过查询android源码,在setting里面找到了拿到缓存大小的源码,通过packageManager的getPackageSizeInfo方法来拿到。
public abstract void getPackageSizeInfo(String packageName, int userHandle,
IPackageStatsObserver observer);
然而这个方法是隐藏的,我们通过反射来拿到这个方法
Class<?> loadClass = getClassLoader().loadClass("android.content.pm.PackageManager");
Method method = loadClass.getDeclaredMethod("getPackageSizeInfo", String.class,int.class,IPackageStatsObserver.class);
在这个方法中,userHandle是一个难点,在android 4.2之后,这个userHandle才出现。handle就是句柄的意思,这个含义在C语言中经常出现。在这里,我们通过句柄来获取这个具体的APP,在这里,我们在方法中设置 Progress.getUserId() / 10000;来进行设置。
为什么会/100000呢,因为在安卓内部,默认能够设置的APP数量就是100000,通过这个计算来拿到handle.
在getPackageSizeInfo 这个方法中,我们还需要设置IPackageStatsObserver 这个类。下面我们通过继承来实现这个类
private class MyIPackageStatsObserver extends IPackageStatsObserver.Stub{
private PackageInfo packageInfo;
public MyIPackageStatsObserver(PackageInfo packageInfo){
this.packageInfo = packageInfo;
}
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
// TODO Auto-generated method stub
//获取到当前手机应用缓存大小
long cacheSize = pStats.cacheSize;
if(cacheSize != 0){
System.out.println("当前应用的名字"+packageInfo.applicationInfo.loadLabel(manager));
CacheInfo cacheInfo = new CacheInfo();
cacheInfo.icon = packageInfo.applicationInfo.loadIcon(manager);
cacheInfo.cacheSize = cacheSize;
cacheInfo.appName = packageInfo.applicationInfo.loadLabel(manager).toString();
cacheInfos.add(cacheInfo);
System.out.println("获得缓存数据是对的,拿到了数据"+cacheSize);
}
adapter.notifyDataSetChanged();
}
}
static class CacheInfo{
Drawable icon;
long cacheSize;
String appName;
}
在实现的过程中,我通过在子线程里面来加载这些数据,发现,这个实现的类去实现需要延长一段时间。为了详细的讲述,我先上代码来看看我是怎样来实现的
private void initUI(){
manager = getPackageManager();
cacheInfos = new ArrayList<CacheInfo>();
adapter = new MyAdapter();
listView = (ListView) findViewById(R.id.list_view);
new Thread(){
public void run() {
//数据加载完成后,开始初始化adapter
List<PackageInfo> installedPackages = manager.getInstalledPackages(0);
// for (PackageInfo packageInfo : installedPackages) {
// getCacheSize(packageInfo);
// }
int count=0;
while(count != installedPackages.size()){
getCacheSize(installedPackages.get(count));
count++;
System.out.println(count + "安装程序数量");
}
handler.sendEmptyMessage(0);
};
}.start();
}
大家可以看到,我是在数据加载完成之后,发送一个消息来刷新UI,使listView来显示数据,可是我发现,
getCacheSize这个会延迟,也就是在发送消息之后,他才进行数据的加载,这个好像是因为AIDL接口的调用而产生的延时,为了解决这个延时,我在这个接口的实现函数中添加了adapter.notifyDataSetChanged();<span style="white-space:pre"> </span>
因为onGetStatsCompleted这个函数是一个回调函数,在主线程中运行,所以就完美的解决了这个问题。