Android獲取應(yīng)用程序大小的方法
今天碰到個(gè)問題,想獲取某個(gè)已安裝的包的大小,沒找到合適的方法。搜索了一下,發(fā)現(xiàn)PackageManager里面有個(gè)getPackageSizeInfo方法,可惜是hide的,而且它執(zhí)行之后,會(huì)將結(jié)果回調(diào)給IPackageStatsObserver的onGetStatsCompleted方法。后來想直接計(jì)算/data/app和/system/app里面的apk大小,可是有時(shí)候會(huì)碰到權(quán)限問題,需要root才可以獲取大小。 再后來,我想起系統(tǒng)的設(shè)置里面有一個(gè)應(yīng)用程序管理,它里面列出了所有程序的占用空間大小、數(shù)據(jù)大小和緩存大小。恩,這個(gè)就是突破口。
以前寫過一篇獲取其他包的Context ,這個(gè)東西是真有用,這個(gè)結(jié)合反射,可以做很多神奇的事情,比如今天的這個(gè)。
上代碼:
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());
//創(chuàng)建它的一個(gè)對(duì)象
Object maObject = maClass.newInstance();
/*
* 將私有域mPm賦值。因?yàn)閙Pm在SizeObserver的invokeGetSize中用到了,
* 卻因?yàn)闆]有執(zhí)行onCreate而沒有初始化,所以要在此處初始化。
*/
Field f_mPm = maClass.getDeclaredField("mPm");
f_mPm.setAccessible(true);
f_mPm.set(maObject, mmsCtx.getPackageManager());
/*
* 給mHandler賦值為重新定義的Handler,以便接收SizeObserver的
* onGetStatsCompleted回調(diào)方法中dispatch的消息,從中取PackageStats對(duì)象。
* */
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對(duì)象
ps = (PackageStats) msg.getData().getParcelable("ApplicationPackageStats");
Log.d("", ""+ps.codeSize);
}
}
});
//加載內(nèi)部類SizeObserver
Class<?> sizeObserverClass = Class.forName("com.android.settings.ManageApplications$SizeObserver", true, mmsCtx.getClassLoader());
Constructor sizeObserverConstructor = sizeObserverClass.getDeclaredConstructors()[0];
sizeObserverConstructor.setAccessible(true);
/*
* 創(chuàng)建SizeObserver對(duì)象,兩個(gè)參數(shù),第一個(gè)是外部類的對(duì)象,
* 也就是ManageApplications對(duì)象,第二個(gè)是msgId,也就是
* 分發(fā)消息的id,跟Handler接收的msgId一樣。
* */
Object soObject = sizeObserverConstructor.newInstance(maObject, 1);
//執(zhí)行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");
}
}
注釋都在代碼里面了,稍微理解一下應(yīng)該都能懂的。
獲取到PackageStats對(duì)象,就可以從中獲取到應(yīng)用程序的占用空間大小、數(shù)據(jù)大小和緩存大小。
另,這畢竟只是hack code,不可能通用。這段代碼的局限性是,只有1.5能用,而且如果別人把setting包去掉了,也沒法使用。要寫出各版本SDK通用的代碼,就必須查看每個(gè)版本的setting包,看代碼有何變化,然后根據(jù)上面給出的思路為每個(gè)版本寫一個(gè)方法,就ok了。
想要獲得成功,首先要自己相信自己,再者要贏得周圍朋友的信任!
- Android編程實(shí)現(xiàn)檢測(cè)當(dāng)前電源狀態(tài)的方法
- Android安卓中循環(huán)錄像并檢測(cè)內(nèi)存卡容量
- Android系統(tǒng)檢測(cè)程序內(nèi)存占用各種方法
- Android實(shí)現(xiàn)獲取SD卡總?cè)萘浚捎么笮?,機(jī)身內(nèi)存總?cè)萘考翱捎么笮〉姆椒?/a>
- Android編程實(shí)現(xiàn)獲得內(nèi)存剩余大小與總大小的方法
- Android檢測(cè)手機(jī)中存儲(chǔ)卡及剩余空間大小的方法(基于Environment,StatFs及DecimalFormat)
相關(guān)文章
Android實(shí)現(xiàn)將View保存成Bitmap的方法
這篇文章主要介紹了Android實(shí)現(xiàn)將View保存成Bitmap的方法,涉及Android畫布Canvas、位圖bitmap及View的相關(guān)使用技巧,需要的朋友可以參考下2016-06-06edittext + listview 實(shí)現(xiàn)搜索listview中的內(nèi)容方法(推薦)
下面小編就為大家?guī)硪黄猠dittext + listview 實(shí)現(xiàn)搜索listview中的內(nèi)容方法(推薦)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-03-03Android編程根據(jù)系列圖片繪制動(dòng)畫實(shí)例總結(jié)
這篇文章主要介紹了Android編程根據(jù)系列圖片繪制動(dòng)畫的方法,以實(shí)例形式總結(jié)了Android根據(jù)圖片繪制動(dòng)畫的常見情況與具體實(shí)現(xiàn)技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11Android中Intent傳遞對(duì)象的3種方式詳解
這篇文章給大家介紹了Android中Intent傳遞對(duì)象的3種方式,分別是Serializable 方式、Parcelable 方式以及JSON 方式,有需要的朋友們可以一起參考借鑒,下面來一起看看吧。2016-09-09Android 使用registerReceiver注冊(cè)BroadcastReceiver案例詳解
這篇文章主要介紹了Android 使用registerReceiver注冊(cè)BroadcastReceiver案例詳解,本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-08-08獲取Android手機(jī)中所有短信的實(shí)現(xiàn)代碼
這篇文章主要介紹了獲取Android手機(jī)中所有短信的實(shí)現(xiàn)代碼,需要的朋友可以參考下2014-08-08Flutter實(shí)現(xiàn)文本滾動(dòng)高亮效果的示例講解
這篇文章主要介紹了如何利用Flutter時(shí)時(shí)渲染頁面從而達(dá)到文本滾動(dòng)高亮的效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-03-03Android自定義view實(shí)現(xiàn)太極效果實(shí)例代碼
這篇文章主要介紹了Android自定義view實(shí)現(xiàn)太極效果實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-05-05