美文网首页
【工作总结】一键清理总结

【工作总结】一键清理总结

作者: dongbingliu | 来源:发表于2017-05-12 10:12 被阅读147次

    一键清理流程图

    一键清理流程图.png

    系统缓存分析

    Android 已安装 app /data/data/packagename/cache 文件夹和 /sdcard/Android/data/packagename/cache 文件夹组成

    原生设置(Settings) - 已安装应用 - 详情页

    Paste_Image.png

    Settings 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
    1. getPackageSizeInfo 方法是一个 @hide 方法,需要通过反射来调用;
    2. 使用getPackageSizeInfo 需要在AndroidManiFest.xml 文件中申明权限GET_PACKAGE_SIZE
    3. 传给 getPackageSizeInfo 方法的第二个参数类型 IPackageStatsObserver 是在 android.content.pm 包下,需要自已通过 aidl 方式定义

    计算缓存大小的实现:

    实现流程:

    1. 工程的 src/main 目录下创建包目录结构 aidl/android/content/pm
    2. Android 源码 frameworks/base/core/java/android/content/pm 目录下的 IPackageStatsObserver.aidl 与其依赖的 PackageStats.aidl 拷贝到上面一步创建的目录里;
    3. AndroidManifest.xml 里声明需要 GET_PACKAGE_SIZE 权限
      <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>
    4. 获取缓存大小实现
    PackageManager pm = mContext.getPackageManager();
    List<ApplicationInfo> 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);
            }
            ......
        }
    

    系统缓存清理实现

    1. AndroidManiFest.xml 中添加权限:
    <uses-permission android:name="android.permission.DELETE_CACHE_FILES"/>
    
    1. 将 Android 源码 frameworks/base/core/java/android/content/pm 目录下的 IPackageDataObserver.aidl copy到工程pm目录下面;
    2. 删除缓存实现
    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<String> 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);
                    }
                }
    
            }
        }
    

    相关文章

      网友评论

          本文标题:【工作总结】一键清理总结

          本文链接:https://www.haomeiwen.com/subject/qtdztxtx.html