編輯:關於Android編程
今天碰到個問題,想獲取某個已安裝的包的大小,沒找到合適的方法。搜索了一下,發現PackageManager裡面有個getPackageSizeInfo方法,可惜是hide的,而且它執行之後,會將結果回調給IPackageStatsObserver的onGetStatsCompleted方法。後來想直接計算/data/app和/system/app裡面的apk大小,可是有時候會碰到權限問題,需要root才可以獲取大小。 再後來,我想起系統的設置裡面有一個應用程序管理,它裡面列出了所有程序的占用空間大小、數據大小和緩存大小。恩,這個就是突破口。
以前寫過一篇獲取其他包的Context ,這個東西是真有用,這個結合反射,可以做很多神奇的事情,比如今天的這個。
上代碼:
Java代碼
復制代碼 代碼如下:
package chroya.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.concurrent.CountDownLatch;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageStats;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
public class Main extends Activity {
private PackageStats ps;
public void getPackageStats(String packageName) {
try {
//獲取setting包的的Context
Context mmsCtx = createPackageContext("com.android.settings",
Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
//使用setting的classloader加載com.android.settings.ManageApplications類
Class<?> maClass = Class.forName("com.android.settings.ManageApplications", true, mmsCtx.getClassLoader());
//創建它的一個對象
Object maObject = maClass.newInstance();
/*
* 將私有域mPm賦值。因為mPm在SizeObserver的invokeGetSize中用到了,
* 卻因為沒有執行onCreate而沒有初始化,所以要在此處初始化。
*/
Field f_mPm = maClass.getDeclaredField("mPm");
f_mPm.setAccessible(true);
f_mPm.set(maObject, mmsCtx.getPackageManager());
/*
* 給mHandler賦值為重新定義的Handler,以便接收SizeObserver的
* onGetStatsCompleted回調方法中dispatch的消息,從中取PackageStats對象。
* */
Field f_mHandler = maClass.getDeclaredField("mHandler");
f_mHandler.setAccessible(true);
f_mHandler.set(maObject, new Handler() {
public void handleMessage(Message msg) {
if(msg.what == 1) {
//此處獲取到PackageStats對象
ps = (PackageStats) msg.getData().getParcelable("ApplicationPackageStats");
Log.d("", ""+ps.codeSize);
}
}
});
//加載內部類SizeObserver
Class<?> sizeObserverClass = Class.forName("com.android.settings.ManageApplications$SizeObserver", true, mmsCtx.getClassLoader());
Constructor sizeObserverConstructor = sizeObserverClass.getDeclaredConstructors()[0];
sizeObserverConstructor.setAccessible(true);
/*
* 創建SizeObserver對象,兩個參數,第一個是外部類的對象,
* 也就是ManageApplications對象,第二個是msgId,也就是
* 分發消息的id,跟Handler接收的msgId一樣。
* */
Object soObject = sizeObserverConstructor.newInstance(maObject, 1);
//執行invokeGetSize方法
sizeObserverClass.getMethod("invokeGetSize", String.class,
CountDownLatch.class).invoke(soObject, packageName, new CountDownLatch(1));
} catch (NameNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getPackageStats("chroya.demo");
}
}
注釋都在代碼裡面了,稍微理解一下應該都能懂的。
獲取到PackageStats對象,就可以從中獲取到應用程序的占用空間大小、數據大小和緩存大小。
另,這畢竟只是hack code,不可能通用。這段代碼的局限性是,只有1.5能用,而且如果別人把setting包去掉了,也沒法使用。要寫出各版本SDK通用的代碼,就必須查看每個版本的setting包,看代碼有何變化,然後根據上面給出的思路為每個版本寫一個方法,就ok了。
想要獲得成功,首先要自己相信自己,再者要贏得周圍朋友的信任!
Android 顏色處理(八) SweepGradient 掃描/梯度渲染為什麼什麼叫掃描渲染呢? 相信大家都看過雷達掃描的效果,尤其是在安全軟件中. &nbs
隨著蘋果向iPhone6以上的機型推送VoLTE高清語音通話運營商配置更新文件,更多網友開始關注這一新的語音技術,那麼現在國內有哪些手機是支持VoLTE高清
之所以單獨把這塊內容提煉出來,在於其具備的一定的層次性,結構上具備統一性,API函數的設計需要實現OMX架構獨有的接口。1. 在上一博文Android4.2.2下Stag
1、xml代碼:復制代碼 代碼如下:<?xml version=1.0 encoding=utf-8?> <LinearLayout xml