如何实现手机缓存清理的功能

来源:互联网 发布:淘宝上怎么搜高仿手表 编辑:程序博客网 时间:2024/04/30 03:35

android手机上的杀毒软件或者是手机管家等类似应用都会有垃圾清理的功能, 那么清理的缓存文件是什么? 怎么去找出应用的缓存文件并将他们清理, 在这里我将介绍如何实现手机垃圾文件清理的功能。

  1. 缓存文件是什么,缓存文件的目录在那里?
    我们知道方法:
    getFilesDir() 的路径是 /data/data/包名/files/
    getCacheDir()的路径是 /data/data/包名/cache/
    缓存文件路径就是getCacheDir()的路径,在此路径下的文件为缓存文件,当系统内存不够,系统会去释放这个路径下的文件。

先看一下缓存清理demo的结果:

2 界面编写
(1)主界面包括一个title, 一个进度条,一个线性布局保存扫描结果(也可以是listview这里为了简便), 一个清理按钮
布局代码:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#999999"    android:orientation="vertical"    tools:context=".MainActivity" >    <TextView        android:layout_width="match_parent"        android:layout_height="40dp"        android:gravity="center"        android:text="缓存清理"        android:textColor="#ffffff"        android:textSize="22sp" />    <FrameLayout        android:layout_width="match_parent"        android:layout_height="wrap_content" >        <ProgressBar            android:id="@+id/pb"            style="@android:style/Widget.ProgressBar.Horizontal"            android:layout_width="match_parent"            android:layout_height="wrap_content" />        <TextView            android:id="@+id/scan_state"            android:layout_width="match_parent"            android:layout_height="wrap_content"            android:text="扫描状态"            android:textColor="#ffffff" />    </FrameLayout>    <LinearLayout        android:layout_weight="1000"        android:id="@+id/ll_container"        android:layout_width="match_parent"        android:layout_height="match_parent"        android:layout_marginTop="5dp"        android:orientation="vertical" >    </LinearLayout>    <Button         android:id="@+id/clear_caches"        android:layout_width="match_parent"        android:layout_height="wrap_content"        android:visibility="gone"        android:text="一键清除"/></LinearLayout>

(2)扫描到的缓存item布局文件:
包含两个textview展示应用名称与缓存大小,一个view作为分割线

<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="wrap_content" >    <TextView        android:id="@+id/app_name"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:textColor="#ffffff"        android:textSize="20sp" />    <TextView        android:id="@+id/cache_size"        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_below="@id/app_name"        android:textColor="#ffffff"        android:textSize="16sp" />    <View        android:layout_width="match_parent"        android:layout_height="1dp"        android:layout_below="@id/cache_size"        android:background="#88000000" /></RelativeLayout>

3 功能逻辑实现代码

public class MainActivity extends Activity implements OnClickListener{    private ProgressBar pb; //扫描进度条    private TextView scan_state; //显示扫描的状态    private LinearLayout ll_container; //保存显示扫描结果    private PackageManager pm;   //包管理    private Button cleanCaches;  //清理手机缓存    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        pb = (ProgressBar) findViewById(R.id.pb);        scan_state = (TextView) findViewById(R.id.scan_state);        ll_container = (LinearLayout) findViewById(R.id.ll_container);        cleanCaches = (Button) findViewById(R.id.clear_caches);        cleanCaches.setOnClickListener(this);        scanCaches();    }    //扫描手机里面所有的应用程序的缓存    private void scanCaches() {        pm = getPackageManager();        //因为扫描缓存需要时间,开启线程来扫描        new Thread(){            public void run() {                Method getPackageSizeInfoMethod = null;                //getPackageSizeInfo方法在sdk中隐藏了,使用反射机制来获取此方法                //1.先获取PackageManager提供的所有方法                Method[] methods = PackageManager.class.getMethods();                //2.遍历所有方法找到getPackageSizeInfo方法                for (Method method : methods) {                    if("getPackageSizeInfo".equals(method.getName())) {                        getPackageSizeInfoMethod = method;                        break;                    }                }                //获取所有安装的包信息                List<PackageInfo> packageInfos = pm.getInstalledPackages(0);                //设置进度条大小                pb.setMax(packageInfos.size());                int progress = 0;                //遍历所有包,获取缓存信息                for (PackageInfo info : packageInfos) {                    try {                        getPackageSizeInfoMethod.invoke(pm, info.packageName,                            new MyDataObserver());                        //防止扫描过快                        Thread.sleep(100);                    } catch (Exception e) {                        e.printStackTrace();                    }                    progress++;                    pb.setProgress(progress);                }                //扫描完毕,更新显示文本内容                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        scan_state.setText("扫描完毕...");                        //扫描完成,显示清理按钮                        cleanCaches.setVisibility(View.VISIBLE);                    }                });            };        }.start();    }    private class MyDataObserver extends IPackageStatsObserver.Stub {        @Override        public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)                throws RemoteException {            final long cache = pStats.cacheSize;            final String packname = pStats.packageName;            final ApplicationInfo appInfo;            try {                appInfo = pm.getApplicationInfo(packname, 0);                runOnUiThread(new Runnable() {                    @Override                    public void run() {                        scan_state.setText("正在扫描:" + appInfo.loadLabel(pm));                        if (cache > 0) {                            View view = View.inflate(getApplicationContext(), R.layout.cache_info_layout, null);                            TextView tv_cache = (TextView) view.findViewById(R.id.cache_size);                            tv_cache.setText("缓存大小:" + Formatter.formatFileSize(getApplicationContext(), cache));                            TextView tv_name = (TextView) view.findViewById(R.id.app_name);                            tv_name.setText(appInfo.loadLabel(pm));                            ll_container.addView(view, 0);                        }                    }                });            } catch (Exception e) {                e.printStackTrace();            }        }    }    private class MyPackDataObserver extends IPackageDataObserver.Stub {        @Override        public void onRemoveCompleted(String packageName, boolean succeeded)                throws RemoteException {            runOnUiThread(new Runnable() {                @Override                public void run() {                    Toast.makeText(getApplicationContext(), "缓存删除成功", Toast.LENGTH_SHORT).show();                    ll_container.removeAllViews();                    scan_state.setText("缓存清理成功");                }            });        }    }    @Override    public void onClick(View v) {        switch (v.getId()) {        case R.id.clear_caches:            CleanAllCache();            break;        default:            break;        }    }    //清除所有缓存    private void CleanAllCache() {        Method[] methods = PackageManager.class.getMethods();        for (Method method : methods) {            if("freeStorageAndNotify".equals(method.getName())) {                    try {                        method.invoke(pm, Integer.MAX_VALUE, new MyPackDataObserver());                    } catch (InvocationTargetException e) {                        // TODO Auto-generated catch block                        e.getCause().printStackTrace();                    } catch (Exception e) {                        e.printStackTrace();                    }                return;            }        }    }}

代码中的注释已经很详细,但是这里需要说明一下,关于freeStorageAndNotify等方法的获得是使用反射机制,因为这些方法在PackageManager中是隐藏的,我们通过获取所有的method然后通过名字匹配,获得方法再通过invoke方法去使用获得的方法。具体关于获得所有应用的缓存与清理缓存的步骤方法可以参考android系统源码中的setting模块。
当你copy上面代码到你的工程中,肯定会报错,因为IPackageStatsObserver.Stub和IPackageDataObserver.Stub找不到,因为这两个类是aidl,因为读取与清理缓存需要读取其他应用程序,需要进程间数据通信。
你需要下载IPackageDataObserver.aidl, IPackageStatsObserver.aidl和PackageStats.aidl这三个文件(可以下载demo的源码,源码中包含这三个文件),在你的工程中创建一个名为android.content.pm的package,将这三个文件copy到这个包下,如图:

然后它会自动在gen目录下生成对应的java文件:

这个时候上面的代码就不会出现错误了,关于aidl这里不去介绍,不懂大家可以google一下。

注意: 应用程序需要下面两个权限:

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

将其加到清单文件AndroidManifest.xml中。

4 关于缓存清理的功能原理
缓存清理利用了android的一个bug, 调用freeStorageAndNotify的方法,向系统请求说需要一块很大的内存这里传入的值是Integer.MAX_VALUE, 系统内存不够会去自动去将应用的缓存清理来满足内存的请求, 这样就实现了缓存清理的功能。
至此实现了手机缓存清理的功能,如有任何疑问可以留言。
源码下载地址:
http://download.csdn.net/detail/lbcab/9517254

1 0
原创粉丝点击