最近做东西的时候,需要获取应用软件大小,看了很多人写的方法,大同小异。今天就参考别人的代码加一些自己的理解。整理一下,分享给大家。
下面是AIDL相关方法获取应用大小的例子,这个网上也有很多。
应用的场景:要采集多个app 的应用相关信息,其中包括应用大小,然后和其他软件信息(包名,应用名称,应用图标等信息)一起上报信息。
这中间就涉及到一个问题:如何保证分别采集多个应用的其他信息完成后再一起上传?因 为获取size的上述方法一次只能获取一个应用的大小,而且获取应用其他信息的方法和应用大小属于异步操作。软件大小是通过上述方法单独获取,其他信息是通过其他方法获取。多个软件信息都要获取完,最终再执行上传操作。
解决办法: 使用回调和CountDownLatch,就可以解决上述情景。
1.AIDL文件
根据上图结构在src/main/aidl/android.content.pm/ 目录下添加IPackageStatsObserver.aidl 和 packageStats.aidl 2个文件。
下面是这2个文件的内容:
IPackageStatsObserver.aidl
package android.content.pm;
import android.content.pm.PackageStats;
oneway interface IPackageStatsObserver {
void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
}
packageStats.aidl
package android.content.pm;
parcelable PackageStats;
2.size大小获取
public void queryPackageSize(CountDownLatch latch,IQueryPkgSizeCallback callBack, Context context, String pkgName) throws Exception{
if ( pkgName != null){
//使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
PackageManager pm = context.getPackageManager(); //得到pm对象
try {
//通过反射机制获得该隐藏函数
Method getPackageSizeInfo = pm.getClass().getMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class);
//调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数
getPackageSizeInfo.invoke(pm, pkgName,new PkgSizeObserver(latch,callBack));
}
catch(Exception ex){
Log.e(TAG, "NoSuchMethodException") ;
ex.printStackTrace() ;
throw ex ; // 抛出异常
}
}
}
//aidl文件形成的Bindler机制服务类
public class PkgSizeObserver extends IPackageStatsObserver.Stub{
private IQueryPkgSizeCallback callback;
private CountDownLatch latch;
PkgSizeObserver(CountDownLatch latch,IQueryPkgSizeCallback callback){
this.latch = latch;
this.callback = callback;
}
/*** 回调函数,
* @param pStats ,返回数据封装在PackageStats对象中
* @param succeeded 代表回调成功
*/
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
throws RemoteException {
// TODO Auto-generated method stub
Log.i(TAG,"PkgSizeObserver succeeded="+succeeded);
if(succeeded){
cachesize = pStats.cacheSize ; //缓存大小n
datasize = pStats.dataSize ; //数据大小
codesize = pStats.codeSize ; //应用程序大小
totalsize = cachesize + datasize + codesize ;
Log.i(TAG, "cachesize--->"+cachesize+" datasize---->"+datasize+ " codeSize---->"+codesize);
callback.queryPkgSize(true,totalsize);
}else{
Log.i(TAG,"get size fail------>");
}
latch.countDown();//每成功获取一个app的值,计数器减1,直到计数器为0时,不在阻塞,执行后续任务
}
}
3.回调接口
public interface IQueryPkgSizeCallback{
void queryPkgSize(boolean isSucceed,long pkgTotalSize);
}
4.CountDownLatch使用
CountDownLatch latch = new CountDownLatch(list.size);//要请求的多个app的list集合,计数器的大小为list的大小
if (list != null) {
final ArrayList<对象名> apps = new ArrayList<>();//作为保存多个应用信息的list,最后返回的list
for(final Iterator<对象名> iterator = list.iterator(); iterator.hasNext();) {
final 对象名 info = iterator.next();
try {
mModule.queryPackageSize(latch,new 类名.IQueryPkgSizeCallback() {
@Override
public void queryPkgSize(boolean isSucceed, long pkgTotalSize) {
if(isSucceed){
Log.i(TAG,"getAllUserApp mAppInfoItem pkgName="+info.getAppPackage()+" system_flag="+info.getAppSystemFlag()+" app size="+mModule.formateFileSize(AEmmApplicaton.getContext(),pkgTotalSize));
info.setAppTotalSize(mModule.formateFileSize(AEmmApplicaton.getContext(),pkgTotalSize));
InstallApp.AppData app = new InstallApp.AppData(info.getAppPackage(), info.getAppName(),
info.getAppFirstInstallTime(), info.getAppVersion(), info.getAppImageToString(), info.getAppSystemFlag(), info.getAppTotalSize());
apps.add(app);//每获取一个完整的应用信息,存入list里面
Log.i(TAG,"succ----->mLock.unlock()");
}else{
Log.i(TAG,"getAllUserApp queryPkgSize fail");
}
}
}, context,info.getAppPackage());
} catch (Exception e) {
e.printStackTrace();
}
}
try {
latch.await();
data = new InstallApp(apps);//计数器为0时,执行此处任务
Log.i(TAG, "----> latch.await()"+" app.size="+apps.size());
} catch (InterruptedException e) {
e.printStackTrace();
}
至于对CountDownLatch使用的详细使用我就不详细讲述,网上有很多,如下链接可以参考:
http://www.importnew.com/15731.html
以上是内容主要是针对实际项目中用到的例子,结合网上关于获取软件大小的文章,做了一个综合性的演示。如果大家有什么问题,欢迎交流。