標籤:
referce to : http://www.baidufe.com/item/8786bc2e95a042320bef.html
計算Android App所佔用d的手機記憶體(RAM)大小、App所產生的資料(Data)大小、App本身所佔用的磁碟空間(ROM)大小。當然,這個就必須用到PackageManager了。
1、查看Android中PackageManager源碼,找到getPackageSizeInfo方法:
/** * Retrieve the size information for a package. * Since this may take a little while, the result will * be posted back to the given observer. The calling context * should have the {@link android.Manifest.permission#GET_PACKAGE_SIZE} permission. * * @param packageName The name of the package whose size information is to be retrieved * @param observer An observer callback to get notified when the operation * is complete. * {@link android.content.pm.IPackageStatsObserver#onGetStatsCompleted(PackageStats, boolean)} * The observer‘s callback is invoked with a PackageStats object(containing the * code, data and cache sizes of the package) and a boolean value representing * the status of the operation. observer may be null to indicate that * no callback is desired. * * @hide */public abstract void getPackageSizeInfo(String packageName, IPackageStatsObserver observer);
2、getPackageSizeInfo方法有兩個參數,第一個是需要計算的App包名,第二個是一個回調。不過IPackageStatesObserver這個class在API裡貌似找不到,找了點兒資料,需要通過Android AIDL的方式來搞。方法:
1)、在src目錄下建立android.content.pm包
2)、在該包下建立PackageStats.aidl檔案,內容如下:
package android.content.pm; parcelable PackageStats;
3)、在該包下建立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);}
3、getPackageSizeInfo方法不能通過context.getPackageManager.getPackageSizeInfo的方式來調用,因為它其實是一個invoke受限的方法,所以必須通過反射實現:
/** * 擷取Android Native App的緩衝大小、資料大小、應用程式大小 * * @param context * Context對象 * @param pkgName * 需要檢測的Native App包名 * @throws NoSuchMethodException * @throws InvocationTargetException * @throws IllegalAccessException */public static void getPkgSize(final Context context, String pkgName) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { // getPackageSizeInfo是PackageManager中的一個private方法,所以需要通過反射的機制來調用 Method method = PackageManager.class.getMethod("getPackageSizeInfo", new Class[] { String.class, IPackageStatsObserver.class }); // 調用 getPackageSizeInfo 方法,需要兩個參數:1、需要檢測的應用程式套件名;2、回調 method.invoke(context.getPackageManager(), new Object[] { pkgName, new IPackageStatsObserver.Stub() { @Override public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException { // 子線程中預設無法處理訊息迴圈,自然也就不能顯示Toast,所以需要手動Looper一下 Looper.prepare(); // 從pStats中提取各個所需資料 Toast.makeText(context, "緩衝大小=" + Formatter.formatFileSize(context, pStats.cacheSize) + "\n資料大小=" + Formatter.formatFileSize(context, pStats.dataSize) + "\n程式大小=" + Formatter.formatFileSize(context, pStats.codeSize), Toast.LENGTH_LONG).show(); // 遍曆一次訊息佇列,彈出Toast Looper.loop(); } } });}
我是直接在Observer回調中通過Toast的方式直接顯示出來的,不過這個回調是在子線 程中非同步完成的,子線程中預設不處理訊息迴圈,所以Toast.show無法被正確執行,需要手動將Toast顯示部分的內容,加到Looper中,分別 調用Looper.prepare和Looper.loop方法即可!
4、當然,根據PackageManager中getPackageSizeInfo注釋中的提示,還需要在AndroidManifest.xml中加入permission:
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>
[Android Pro] PackageManager#getPackageSizeInfo (hide)