目錄
一、前言
二、效果預(yù)覽
三、實現(xiàn)步驟
(1)開啟權(quán)限
(2)AIDL文件導(dǎo)入
(3)引用工具類
(4)使用方式
四、功能分解
(1)單例模式
(2)設(shè)置監(jiān)聽數(shù)據(jù)獲取回調(diào)
(3)開始獲取數(shù)據(jù)
五、Demo地址
六、參考文檔
七、內(nèi)容推薦
一、前言
最近仿微信存儲空間做了個demo,其中最麻煩的地方就是獲取APP應(yīng)用大小了。做完之后自己總結(jié)把獲取方式封裝成了工具,方便以后再次使用。期望大家喜歡。如果感覺還不錯的話,不妨頂一個,收藏一下...。如果有什么不妥的地方也可以留言指出,相互學(xué)習(xí),共同進(jìn)步
二、效果預(yù)覽
先看看Demo、不滿意請使勁懟作者、不要懟我哈
三、實現(xiàn)步驟
- 開啟權(quán)限
- AIDL文件導(dǎo)入
- 引用工具類
- 使用方式
(1)開啟權(quán)限
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
(2)AIDL文件導(dǎo)入
Android8.0之前沒有對應(yīng)的API提供,需要引入兩個AIDL文件。
IPackageStatsObserver.aidl
package android.content.pm;
import android.content.pm.PackageStats;
interface IPackageStatsObserver {
oneway void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
}
PackageStats.aidl
package android.content.pm;
parcelable PackageStats;
導(dǎo)入AIDL文件后需要編譯一下,系統(tǒng)自動生成java文件,不清楚AIDL是什么的可以百度一下..
這里就不解釋了。長話短說也解釋不清楚,讓大家自己學(xué)習(xí),還可能獲得更多成就感
(3)引用工具類
AppSizeUtils.class
import android.app.usage.StorageStats;
import android.app.usage.StorageStatsManager;
import android.content.Context;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.os.Build;
import android.os.storage.StorageManager;
import android.os.storage.StorageVolume;
import android.support.annotation.RequiresApi;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.List;
import java.util.UUID;
/**
* TODO 獲取APP應(yīng)用 緩存大小 數(shù)據(jù)大小 應(yīng)用大小
*/
public class AppSizeUtils {
private static AppSizeUtils mApiUrl;
private AppSizeUtils() { }
public static AppSizeUtils getInstance() {
if (mApiUrl == null) {
synchronized (AppSizeUtils.class) {
if (mApiUrl == null) {
mApiUrl = new AppSizeUtils();
}
}
}
return mApiUrl;
}
/**
* TODO 獲取應(yīng)用總大小
*/
public void init(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getAppSizeO(context);
} else {
getAppsize(context);
}
}
/**
* 獲取應(yīng)用的大小
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public void getAppSizeO(Context context) {
StorageStatsManager storageStatsManager = (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
//獲取所有應(yīng)用的StorageVolume列表
List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
for (StorageVolume item : storageVolumes) {
String uuidStr = item.getUuid();
UUID uuid;
if (uuidStr == null) {
uuid = StorageManager.UUID_DEFAULT;
} else {
uuid = UUID.fromString(uuidStr);
}
int uid = getUid(context, context.getPackageName());
//通過包名獲取uid
StorageStats storageStats = null;
try {
storageStats = storageStatsManager.queryStatsForUid(uuid, uid);
} catch (IOException e) {
e.printStackTrace();
}
if(onBackListent!=null){
onBackListent.backData(storageStats.getCacheBytes(), storageStats.getDataBytes(), storageStats.getAppBytes());
}
}
}
/**
* 根據(jù)應(yīng)用包名獲取對應(yīng)uid
*/
public int getUid(Context context, String pakName) {
try {
return context.getPackageManager().getApplicationInfo(pakName, PackageManager.GET_META_DATA).uid;
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return -1;
}
/**
* 獲取應(yīng)用大小8.0以下
*/
public void getAppsize(Context context) {
try {
Method method = PackageManager.class.getMethod("getPackageSizeInfo", new Class[]{String.class, IPackageStatsObserver.class});
// 調(diào)用 getPackageSizeInfo 方法,需要兩個參數(shù):1、需要檢測的應(yīng)用包名;2、回調(diào)
method.invoke(context.getPackageManager(), context.getPackageName(), new IPackageStatsObserver.Stub() {
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) {
if(onBackListent!=null){
onBackListent.backData(pStats.cacheSize, pStats.dataSize, pStats.codeSize);
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
public OnBackListent onBackListent;
public interface OnBackListent {
void backData(long cacheSize, long dataSize, long codeSize);
}
public AppSizeUtils setDatasListent(OnBackListent listent) {
onBackListent = listent;
return this;
}
}
(4)使用方式
AppSizeUtils.getInstance().setDatasListent(new AppSizeUtils.OnBackListent() {
@Override
public void backData(long cacheSize, long dataSize, long codeSize) {
Log.e(TAG, "緩存大小: "+cacheSize + " 數(shù)據(jù)大小: " + dataSize + " 應(yīng)用大小: " + codeSize );
}
}).init(MyApplication.getContext());
/**
* 將文件大小顯示為GB,MB等形式
*/
public static String size(long size)
{
if (size / (1024 * 1024 * 1024) > 0)
{
float tmpSize = (float) (size) / (float) (1024 * 1024 * 1024);
DecimalFormat df = new DecimalFormat("#.##");
return "" + df.format(tmpSize) + "GB";
}
else if (size / (1024 * 1024) > 0)
{
float tmpSize = (float) (size) / (float) (1024 * 1024);
DecimalFormat df = new DecimalFormat("#.##");
return "" + df.format(tmpSize) + "MB";
}
else if (size / 1024 > 0)
{
return "" + (size / (1024)) + "KB";
}
else
return "" + size + "B";
}
順便提供一下轉(zhuǎn)化方法,省的自己寫麻煩..
這里就不貼Demo源碼了,主要功能代碼已經(jīng)貼出來。大家可以根據(jù)需求隨便更改,想要源碼的也可以在底部鏈接下載。。
四、功能分解
(1)單例模式
private static AppSizeUtils mApiUrl;
private AppSizeUtils() { }
public static AppSizeUtils getInstance() {
if (mApiUrl == null) {
synchronized (AppSizeUtils.class) {
if (mApiUrl == null) {
mApiUrl = new AppSizeUtils();
}
}
}
return mApiUrl;
}
這個就不解釋了,不了解的可以看看《JAVA 設(shè)計模式——單例模式》
(2)設(shè)置監(jiān)聽數(shù)據(jù)獲取回調(diào)
為什么要寫這個回調(diào)呢?
在獲取App大小的時候有延遲(有耗時操作),所以不能立馬得到數(shù)據(jù)。所以當(dāng)時寫了個廣播用來通知什么時候獲取到數(shù)據(jù),不過那樣的話寫起來有點(diǎn)麻煩,所以寫了個回調(diào)。
public OnBackListent onBackListent;
public interface OnBackListent {
void backData(long cacheSize, long dataSize, long codeSize);
}
public AppSizeUtils setDatasListent(OnBackListent listent) {
onBackListent = listent;
return this;
}
具體調(diào)用方法時機(jī)看下面↓↓↓
(3)開始獲取數(shù)據(jù)
只需調(diào)用init(Context context)
/**
* TODO 獲取應(yīng)用總大小
*/
public void init(Context context) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
getAppSizeO(context, context.getPackageName());
} else {
getAppsize(context);
}
}
因為android8.0之后有提供新的API用來獲取應(yīng)用大小
所以8.0之前和8.0之后獲取方式不一樣
Android8.0之前
/**
* 獲取應(yīng)用大小8.0以下
*/
public void getAppsize(Context context) {
try {
Method method = PackageManager.class.getMethod("getPackageSizeInfo", new Class[]{String.class, IPackageStatsObserver.class});
// 調(diào)用 getPackageSizeInfo 方法,需要兩個參數(shù):1、需要檢測的應(yīng)用包名;2、回調(diào)
method.invoke(context.getPackageManager(), context.getPackageName(), new IPackageStatsObserver.Stub() {
@Override
public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) {
//數(shù)據(jù)獲取時機(jī) 使用回調(diào)
onBackListent.backData(pStats.cacheSize, pStats.dataSize, pStats.codeSize);
}
});
} catch (Exception e) {
e.printStackTrace();
}
}
Android8.0之后
/**
* 8.0獲取應(yīng)用的大小
*/
@RequiresApi(api = Build.VERSION_CODES.O)
public void getAppSizeO(Context context) {
StorageStatsManager storageStatsManager = (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);
StorageManager storageManager = (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);
//獲取所有應(yīng)用的StorageVolume列表
List<StorageVolume> storageVolumes = storageManager.getStorageVolumes();
for (StorageVolume item : storageVolumes) {
String uuidStr = item.getUuid();
UUID uuid;
if (uuidStr == null) {
uuid = StorageManager.UUID_DEFAULT;
} else {
uuid = UUID.fromString(uuidStr);
}
int uid = getUid(context, context.getPackageName());
//通過包名獲取uid
StorageStats storageStats = null;
try {
storageStats = storageStatsManager.queryStatsForUid(uuid, uid);
} catch (IOException e) {
e.printStackTrace();
}
onBackListent.backData(storageStats.getCacheBytes(), storageStats.getDataBytes(), storageStats.getAppBytes());
}
}
文采不好,就不多廢話了。不過寫了這么多,大家記得捧捧場哈
五、Demo地址
六、參考文檔
七、內(nèi)容推薦
《Android Rxjava+Retrofit網(wǎng)絡(luò)請求框架封裝(一)》
如果你覺得我寫的不錯或者對您有所幫助的話
不妨頂一個【微笑】,別忘了點(diǎn)贊、收藏、加關(guān)注哈
看在我花了這么多時間整理寫成文章分享給大家的份上,記得手下留情哈
您的每個舉動都是對我莫大的支持