最近做東西的時候,需要獲取應用軟件大小,看了很多人寫的方法,大同小異。今天就參考別人的代碼加一些自己的理解。整理一下,分享給大家。
下面是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
以上是內容主要是針對實際項目中用到的例子,結合網上關於獲取軟件大小的文章,做了一個綜合性的演示。如果大家有什麼問題,歡迎交流。