Android应用的缓存

0. Thanks

Android 系统缓存扫描与清理方法分析

1. 基本知识

一般来说,我们自己程序的文件会存在两个地方:

  • /data/data/<packageName>

此路径下主要是存储,数据库数据,SharedPreference,和其他的一些数据,当然也有缓存。

  • cache:内部缓存目录

  • databases:数据库数据

  • shared_prefs:SharedPreference

  • lib:app的依赖包

  • /sdcard/Android/data/<packageName>

可以看到,在这两个目录下,又分了,cache,files等好多个目录。一般缓存都会存在cache下。

通过content的API,我们可以获取到相应的目录:

LogUtils.i("ARouterOneActivity", this.getCacheDir().getAbsolutePath());
LogUtils.i("ARouterOneActivity", this.getFilesDir().getAbsolutePath());
LogUtils.i("ARouterOneActivity", this.getObbDir().getAbsolutePath());
LogUtils.i("ARouterOneActivity", this.getExternalCacheDir().getAbsolutePath());
LogUtils.i("ARouterOneActivity", this.getExternalFilesDir(Environment.DIRECTORY_DCIM).getAbsolutePath());
复制代码
/data/data/com.chestnut.RouterArchitecture.ModulesCommon/cache
/data/data/com.chestnut.RouterArchitecture.ModulesCommon/files
/storage/emulated/0/Android/obb/com.chestnut.RouterArchitecture.ModulesCommon
/storage/emulated/0/Android/data/com.chestnut.RouterArchitecture.ModulesCommon/cache
/storage/emulated/0/Android/data/com.chestnut.RouterArchitecture.ModulesCommon/files/DCIM
复制代码

2. 清理缓存

一般app都有一个清理自身缓存的功能,我们先明确, 清理缓存,也就是清理我们存在: /data/data/<packageName>/cache /sdcard/Android/data/<packageName>/cache 这两个路径下的文件。

先得到缓存的大小:

  • 使用递归获取某个文件夹的大小:
/**
     * 递归方式 计算文件的大小
     * @param file 文件or目录
     * @return 大小
     */
    private static long getTotalSizeOfFilesInDir(final File file) {
        if (file.isFile())
            return file.length();
        final File[] children = file.listFiles();
        long total = 0;
        if (children != null)
            for (final File child : children)
                total += getTotalSizeOfFilesInDir(child);
        return total;
    }
复制代码
  • 计算大小:
File file1 = new File("/sdcard/Android/data/{pkg}/cache".replace("{pkg}", pkg));
File file2 = new File("/data/data/{pkg}/cache".replace("{pkg}", pkg));
复制代码
  • 得到的是byte的大小,我们需要转化成合适的显示。
    /**
     * Byte与Byte的倍数
     */
    public static final int BYTE = 1;
    /**
     * KB与Byte的倍数
     */
    public static final int KB = 1024;
    /**
     * MB与Byte的倍数
     */
    public static final int MB = 1048576;
    /**
     * GB与Byte的倍数
     */
    public static final int GB = 1073741824;
    /**
     * 字节数转合适大小
     * <p>保留3位小数</p>
     *
     * @param byteNum 字节数
     * @return 1...1024 unit
     */
    public static String byte2FitSize(long byteNum) {
        if (byteNum < 0) {
            return "shouldn't be less than zero!";
        } else if (byteNum < KB) {
            return String.format(Locale.getDefault(), "%.3fB", (double) byteNum);
        } else if (byteNum < MB) {
            return String.format(Locale.getDefault(), "%.3fKB", (double) byteNum / KB);
        } else if (byteNum < GB) {
            return String.format(Locale.getDefault(), "%.3fMB", (double) byteNum / MB);
        } else {
            return String.format(Locale.getDefault(), "%.3fGB", (double) byteNum / GB);
        }
    }
复制代码

当然,其实很多应用的缓存目录都不是放在这两个文件夹下,像微信都直接在sd卡上新建一个目录来存储,我们写自己app的清理缓存功能的时候,记得要把这些都考虑进去。

  • 然后直接delete吧。
    /**
     * 删除目录下的所有文件。
     *
     * @param filePath 目录
     */
    public static void deleteFolderFile(String filePath, boolean deleteThisPath) {
        if (!TextUtils.isEmpty(filePath)) {
            try {
                File file = new File(filePath);
                if (file.isDirectory()) {// 如果下面还有文件
                    File files[] = file.listFiles();
                    for (int i = 0; i < files.length; i++) {
                        deleteFolderFile(files[i].getAbsolutePath(), true);
                    }
                }
                if (deleteThisPath) {
                    if (!file.isDirectory()) {// 如果是文件,删除
                        file.delete();
                    } else {// 目录
                        if (file.listFiles().length == 0) {// 目录下没有文件或者目录,删除
                            file.delete();
                        }
                    }
                }
            } catch (Exception e) {}
        }
    }
复制代码

3. 清理其他APP的缓存

在某些项目中,我们可能接到这样的需求,清理其他APP的缓存。 在上面的Thanks链接中,我们可以知道,可以使用反射系统API+系统权限去做。

  • 再总结一下应用设置页面中的缓存:

  • 缓存:29.54MB,是统计了:/data/data/<packageName>/cache /sdcard/Android/data/<packageName>/cache的大小

  • 清理缓存其实是系统调用了方法:android.content.pm.PackageManager.deleteApplicationCacheFiles 清理以上的目录。

    /**
     * 清理具体应用的缓存
     * @param context 上下文
     * @param pkg 包名
     * @param removeCallback 回调
     */
    public static void cleanAppInternalCache(Context context, String pkg, CommonContract.Function2<String,Boolean> removeCallback) {
        File file = new File("/data/data/<packageName>/cache".replace("<packageName>", pkg));
        if (file.exists()) {
            try {
                PackageManager mPackageManager = context.getPackageManager();
                if (mPackageManager!=null) {
                    Method mFreeStorageAndNotifyMethod = mPackageManager.getClass().getMethod("deleteApplicationCacheFiles", String.class, IPackageDataObserver.class);
                    mFreeStorageAndNotifyMethod.invoke(mPackageManager, pkg, new IPackageDataObserver.Stub() {
                        @Override
                        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
                            if (removeCallback!=null) {
                                removeCallback.onAction(packageName, succeeded);
                            }
                        }
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
                if (removeCallback!=null) {
                    removeCallback.onAction(pkg, false);
                }
            }
        }
        else {
            if (removeCallback!=null) {
                removeCallback.onAction(pkg, true);
            }
        }
    }
复制代码
  • 获取缓存大小的方法是调用了系统的:android.content.pm.PackageManager.getPackageSizeInfo,得到一个PackageStats对象,里面就包含了缓存的基本信息。
    /**
     * 获取到缓存的大小
     *  1.  /data/data/<packageName>
     *  2.  /sdcard/Android/data/<packageName>
     * @param context context
     * @param pkg pkg
     * @param getCallback getCallback
     */
    public static void getAppSizeInfo(Context context, String pkg, CommonContract.Function1<PackageStats> getCallback) {
        try {
            Method method = PackageManager.class.getDeclaredMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);
            method.invoke(context.getPackageManager(), pkg, new IPackageStatsObserver.Stub() {
                @Override
                public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {
                    if (getCallback!=null) {
                        if (succeeded)
                            getCallback.onAction(pStats);
                        else
                            getCallback.onAction(null);
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            if (getCallback!=null) {
                getCallback.onAction(null);
            }
        }
    }
复制代码
  • 数据清理是系统调用了方法:android.content.pm.PackageManager.clearApplicationUserData
   /**
    * 清理具体应用的数据+缓存
    *  1.  /data/data/<packageName>
    *  2.  /sdcard/Android/data/<packageName>
    * @param context 上下文
    * @param pkg 包名
    * @param removeCallback 回调
    */
   public static void cleanAppDataAndCache(Context context, String pkg, CommonContract.Function2<String,Boolean> removeCallback) {
       try {
           ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
           if (activityManager!=null) {
               Method mFreeStorageAndNotifyMethod = activityManager.getClass().getMethod("clearApplicationUserData", String.class, IPackageDataObserver.class);
               mFreeStorageAndNotifyMethod.invoke(activityManager, pkg, new IPackageDataObserver.Stub() {
                   @Override
                   public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {
                       if (removeCallback!=null) {
                           removeCallback.onAction(packageName, succeeded);
                       }
                   }
               });
           }
       } catch (Exception e) {
           e.printStackTrace();
           if (removeCallback!=null) {
               removeCallback.onAction(pkg, false);
           }
       }
   }
复制代码

要使用上面写好的方法,你还有做这些:

  • 首先我们要准备好系统的两个AIDL:android.content.pm.IPackageStatsObserver android.content.pm.IPackageDataObserver,一个是获取缓存的监听器,一个是清理缓存的监听器

  • 你的应用要打上系统的签名,或者是想方设法得到root权限

  • 需要声明一些系统权限:

    <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
    <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA"/>
    <uses-permission android:name="android.permission.DELETE_CACHE_FILES"/>
复制代码
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值