CountDownLatch與AIDL獲取應用軟件大小結合使用實例

最近做東西的時候,需要獲取應用軟件大小,看了很多人寫的方法,大同小異。今天就參考別人的代碼加一些自己的理解。整理一下,分享給大家。
下面是AIDL相關方法獲取應用大小的例子,這個網上也有很多。

應用的場景:要採集多個app 的應用相關信息,其中包括應用大小,然後和其他軟件信息(包名,應用名稱,應用圖標等信息)一起上報信息。
這中間就涉及到一個問題:如何保證分別採集多個應用的其他信息完成後再一起上傳?因 爲獲取size的上述方法一次只能獲取一個應用的大小,而且獲取應用其他信息的方法和應用大小屬於異步操作。軟件大小是通過上述方法單獨獲取,其他信息是通過其他方法獲取。多個軟件信息都要獲取完,最終再執行上傳操作。

解決辦法: 使用回調和CountDownLatch,就可以解決上述情景。

1.AIDL文件
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

以上是內容主要是針對實際項目中用到的例子,結合網上關於獲取軟件大小的文章,做了一個綜合性的演示。如果大家有什麼問題,歡迎交流。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章