計算Android App佔用的各種空間大小
阿新 • • 發佈:2019-02-10
一個小需求:計算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
>