【工作总结】一键清理总结
16lz
2021-01-25
一键清理流程图
一键清理流程图.png系统缓存分析
Android 已安装 app /data/data/packagename/cache 文件夹和 /sdcard/Android/data/packagename/cache 文件夹组成
原生设置(Settings) - 已安装应用 - 详情页
Paste_Image.pngSettings APP 使用了 PackageManager.getPackageSizeInfo 方法来做此事,难道 so easy?屁颠屁颠去查了一下 Android API,发现 PacakgeManager 的文档中压根就没有出现 getPackageSizeInfo 的身影,好吧这是一个不对外公开的 API.
Settings 计算缓存大小方法:
@Override public void handleMessage(Message msg) { ...... switch (msg.what) { ...... case MSG_LOAD_SIZES: { synchronized (mEntriesMap) { ...... mPm.getPackageSizeInfo(mCurComputingSizePkg, mStatsObserver); ...... } } break; } } ......
使用 getPackageSizeInfo 需要解决的问题:
Paste_Image.png
- getPackageSizeInfo 方法是一个 @hide 方法,需要通过反射来调用;
- 使用getPackageSizeInfo 需要在AndroidManiFest.xml 文件中申明权限GET_PACKAGE_SIZE
- 传给 getPackageSizeInfo 方法的第二个参数类型 IPackageStatsObserver 是在 android.content.pm 包下,需要自已通过 aidl 方式定义
计算缓存大小的实现:
实现流程:
- 工程的 src/main 目录下创建包目录结构 aidl/android/content/pm
- Android 源码 frameworks/base/core/java/android/content/pm 目录下的 IPackageStatsObserver.aidl 与其依赖的 PackageStats.aidl 拷贝到上面一步创建的目录里;
- AndroidManifest.xml 里声明需要 GET_PACKAGE_SIZE 权限
- 获取缓存大小实现
PackageManager pm = mContext.getPackageManager();List installedPackages = pm.getInstalledApplications(PackageManager.MATCH_UNINSTALLED_PACKAGES);mScanTotalCount = installedPackages.size();for (int i = 0; i < mScanTotalCount; i++) { ApplicationInfo appInfo = installedPackages.get(i); getAppCacheSize(appInfo.packageName,observer ); }public void getAppCacheSize(String packageName, IPackageStatsObserver.Stub observer) { try { PackageManager pm = ContextUtil.applicationContext.getPackageManager(); Method getPackageSizeInfo = pm.getClass() .getMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class); getPackageSizeInfo.invoke(pm, packageName, observer); } catch (NoSuchMethodException e ) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); }}private class PackageSizeObserver extends IPackageStatsObserver.Stub { @Override public void onGetStatsCompleted(PackageStats packageStats, boolean succeeded) throws RemoteException { if (packageStats == null || !succeeded) { } else { AppEntry entry = new AppEntry(); entry.packageName = packageStats.packagename; entry.cacheSize = packageStats.cacheSize + packageStats.externalCacheSize; // do something else,比如把 entry 通过消息发送给需要的地方,或者添加到你的列表里 } }}
系统缓存清理
借鉴系统Settings清理缓存方案
public void onClick(View v) { ...... } else if (v == mClearCacheButton) { // Lazy initialization of observer if (mClearCacheObserver == null) { mClearCacheObserver = new ClearCacheObserver(); } mPm.deleteApplicationCacheFiles(packageName, mClearCacheObserver); } ...... }
系统缓存清理实现
- AndroidManiFest.xml 中添加权限:
- 将 Android 源码 frameworks/base/core/java/android/content/pm 目录下的 IPackageDataObserver.aidl copy到工程pm目录下面;
- 删除缓存实现
private void deleteCacheFile(String packageName) { Log.d(TAG, "deleteCacheFile: "); try { Method deleteApplicationCacheFiles = PackageManager.class.getDeclaredMethod("deleteApplicationCacheFiles", String.class, IPackageDataObserver.class); deleteApplicationCacheFiles.invoke(pm, packageName, new PackageDataObserver()); } catch (NoSuchMethodException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }public class PackageDataObserver extends IPackageDataObserver.Stub { @Override public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { Log.d(TAG, "onRemoveCompleted: "+packageName); } @Override public IBinder asBinder() { return null; }}
4.app 使用DELETE_CACHE_FILES权限 需要系统签名;
扫描其他文件
//获取SDCard 文件目录 File externalDir = Environment.getExternalStorageDirectory(); if (externalDir != null) { traverPath(externalDir, 0); } private void traverPath(File root, int level) { if (root == null || !root.exists() || level > SCAN_LEVEL) { return; } File[] listFiles = root.listFiles(); for (File file : listFiles) { mInfProgress.setPath(file.getAbsolutePath()); if (file.isFile()) { String fileName = file.getName(); if (fileName.endsWith(".apk") || fileName.endsWith(".log") || fileName.endsWith(".tmp") || fileName.endsWith(".temp")) { mDataSize += file.length(); CleanDataInfo cleanInfo = new CleanDataInfo();// List filePath = new ArrayList<>(); cleanInfo.setPath(file.getAbsolutePath()); cleanInfo.setSize(mDataSize); listsInfo.add(cleanInfo); Log.d(MyApplication.TAG, "traverPath: " + cleanInfo.getPath()); } if (mInfProgress != null) { mScanListener.onProgress(mInfProgress); } } else { if (level < SCAN_LEVEL) { traverPath(file, level + 1); } } } }
更多相关文章
- Nginx系列教程(六)| 手把手教你搭建 LNMP 架构并部署天空网络电影
- android AIDL简单步骤
- Android(安卓)百分比布局详解及实例代码
- Android(安卓)利用soap协议与服务端进行通信
- Android在标准linux基础上对休眠唤醒的实现(一)(二)(三)【转】
- 采用Scroller实现任意布局的上下左右弹性效果
- android 常用系统信息获取总结
- S3C6410 移植Android(安卓)内核
- 【Android(安卓)开发教程】Spinner