android 获取其他应用程序的缓存大小以及清理应用缓存

来源:互联网 发布:java字符串比较大小 编辑:程序博客网 时间:2024/05/23 15:44

最近在做appStore时,涉及到一个第三方app下载视频后将车机存储撑爆的问题,从而影响到我们车机自带的app使用,问题很是严重,于是就需要提供缓存清理以及垃圾清理的功能,当用户使用第三方app时,存储空间达到一定量的时候会提示用户去清理,否则不允许使用第三方app。

缓存获取

获取各个应用程序的缓存大小,可以通过使用PackageManager.getPackageSizeInfo方法来获取,但是它被隐藏了,所以我们只能通过反射来调用该方法

隐藏的getPackageSizeInfo

一、首先我们需要获取到系统中所有已安装app的基本信息

List<PackageInfo> installedPackages = mPackageManager.getInstalledPackages(0);        for (PackageInfo packageInfo : installedPackages) {            getCacheSize(packageInfo);//反射调用getPackageSizeInfo        }

二、反射调用getPackageSizeInfo

/**     * 获取到缓存的大小     *     * @param packageInfo     */    private void getCacheSize(PackageInfo packageInfo) {        try {            //通过反射获取到当前的方法            Method method = PackageManager.class.getDeclaredMethod("getPackageSizeInfo", String.class, IPackageStatsObserver.class);            /**             * 第一个参数表示当前的这个方法由谁调用的             * 第二个参数表示包名             */            method.invoke(mPackageManager, packageInfo.applicationInfo.packageName, new MyIPackageStatsObserver(packageInfo));        } catch (Exception e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }

三、调用getPackageSizeInfo需要两个参数,第一个参数是应用包名,通过packageInfo可以获取到,第二个参数是一个IPackageStatsObserver类型的回调,所有查询的结果都是从IPackageStatsObserver里面的onGetStatsCompleted方法里面回调回来的。onGetStatsCompleted是异步调用的,所以我们需要通过handler将结果更新到UI上.

public static final int HANDLER_UPDATE_CACHE_MSG = 0XF0F1;    private Handler mHandler = new Handler() {        @Override        public void handleMessage(Message msg) {            if (HANDLER_UPDATE_CACHE_MSG == msg.what) {                if (msg.obj != null && msg.obj instanceof CacheInfo) {                    CacheInfo info = (CacheInfo) msg.obj;                    mCleanCacheAdapter.addDataAndRefresh(info);                }            }        }    };    private class MyIPackageStatsObserver extends IPackageStatsObserver.Stub {        private PackageInfo packageInfo;        public MyIPackageStatsObserver(PackageInfo packageInfo) {            this.packageInfo = packageInfo;        }        @Override        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) throws RemoteException {            //获取到当前手机应用的缓存大小            long cacheSize = pStats.cacheSize;// 缓存大小            long dataSize = pStats.dataSize; // 数据大小            //如果当前的缓存大小大于0的话,则表示有缓存            if (cacheSize > 0) {                CacheInfo cacheInfo = new CacheInfo();                Drawable icon = packageInfo.applicationInfo.loadIcon(mPackageManager);                String appName = packageInfo.applicationInfo.loadLabel(mPackageManager).toString();                String packageName = packageInfo.packageName;                cacheInfo.setAppName(appName);                cacheInfo.setPackageName(packageName);                cacheInfo.setIcon(icon);                cacheInfo.setCacheSize(cacheSize);                Message.obtain(mHandler, HANDLER_UPDATE_CACHE_MSG, cacheInfo).sendToTarget();                LogUtils.d(mTAG,"---读取缓存中------>" + cacheSize + "---cacheInfos.size()--" + mCacheInfos.size());            }        }    }

四、补充:注意点: IPackageStatsObserver.aidl和PackageStats.aidl文件都是从系统中拿出来的,需要放到指定的文件夹下(android.content.pm),否则会出现找不到的错误。上面的CacheInfo只是一个简单的javaBean用来存放每个应用所查询到的数据。
这里写图片描述

五、前面四步已经成功的将所有的app缓存大小都获取到了,接下来就是如何清理这些缓存,首先说说一键清理,就是一次性清理所有的缓存,可以调用PackageManager的freeStorageAndNotify的方法,同样还是@hide,所以我们依旧要通过反射来调用,直接前几步骤差不多直接看代码
这里写图片描述

public void cleanAll() {        //获取到当前应用程序里面所有的方法        try {            StatFs stat = new StatFs(Environment.getDataDirectory().getAbsolutePath());            Method mFreeStorageAndNotifyMethod = mPackageManager.getClass().getMethod(                    "freeStorageAndNotify", long.class, IPackageDataObserver.class);            mFreeStorageAndNotifyMethod.invoke(mPackageManager,                    (long) stat.getBlockCount() * (long) stat.getBlockSize(),                    new MyIPackageDataObserver()            );        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        }    }    class MyIPackageDataObserver extends IPackageDataObserver.Stub {        public MyIPackageDataObserver() {        }        @Override        public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException {            LogUtils.e(mTAG,"当前清理的包名:"+packageName);            if (succeeded){                LogUtils.e(mTAG,"清理成功!");            }else {                LogUtils.e(mTAG,"清理失败!");            }        }    }

前面那些操作所需要的权限:

<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />    <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />

六、到此为止,我所查询到的资料基本都是这些步骤,如果需要单独清理的应用数据的话,大都是直接跳到系统清理界面,通过系统操作清理。不过我们车机很显然不可能跳到系统界面然后清理,所以只能另寻他路,后来查到ActivityManager:clearApplicationUserData这个方法,是用于应用清除用户数据,相当于在设置中清除应用数据,同样也是隐藏的所以我们还是通过反射来调用,具体代码就不提供了,跟上面方式是一样的。
这里写图片描述

七、然后第六步操作之后运行会直接挂掉,提示缺少android.permission.CLEAR_APP_USER_DATA权限,然而加上之后还是会挂掉,还是提示缺少这个权限,也就是说普通的app我们是无法获取到这个权限的,所以我们还需要在AndroidManifest.xml里面配置android:sharedUserId=”android.uid.system”,这句配置的意思就是获取系统的进程权限,然后我们的app还需要调用系统平台的签名,这样就能单独的清理指定应用的缓存数据了。其实这个有很大的缺陷,由于应用和系统签名是绑定在一起的,所以这个应用只能在指定的系统上安装,其他的系统是安装不了的,我们车机系统是自己定制的,所以这个方式,对我这个应用来说是没问题的。

原创粉丝点击