首页 > 代码库 > Android 清楚程序缓存

Android 清楚程序缓存

其实清除缓存是有两种的,一种是清除手机rom里面的缓存,一种是清除手机sd卡里面的缓存,我们今天主要讲的就是第一种

ps:这里来一个知识扫盲,就是手机里面的rom和ram啦,如果已经知道了的,就可以跳过啦,我们去买手机,有时候经常会被那些销售人员忽悠的,说什么8G的内存啦,什么的,其实他这里面说的极大可能就是你手机里面rom的大小啦,rom就是read only menory(只读存储器)你可以把它当成你电脑上的硬盘,不过它只能读取而已,ram就是random access menory(随机存取器)这个就相当于你电脑的内存啦,所以那个销售人员说的手机内存有多大的时候,我们一定要问清楚啦,不要被人蒙了


好啦,回归正题,我们今天讲的那个缓存是清除手机rom里面的缓存,其实也是挺简单的,只要知道了要怎么做之后,至于那个清除sd卡里面的缓存的话,这个我到时会给大家说一下是怎样清理的,具体我就不写了,好,先来看一下我们要做的效果

加载中... 加载中...


上的第一个图就是我们把我们的应用的一些信息给读取出来了,但那个界面不怎么好看,大家可以自己优化一下,当我们点击了要清理缓存的条目时,我们就会进入到系统设置里面的一个界面,因为清理rom里面的缓存是要root才行的,而我们没有root,那么就只要借助系统里面的功能啦,到时我也会教大家怎样root手机的

好啦,废话不多说,我们直接进入代码阶段

首先,我们先新建一个model类用来存放缓存的信息

com.xiaobin.security.domain.CacheInfo

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
packagecom.xiaobin.security.domain;
 
importandroid.graphics.drawable.Drawable;
 
publicclass CacheInfo
{
    privateString name;
    privateString packageName;
    privateDrawable icon;
    //应用大小
    privateString codeSize;
    //数据大小
    privateString dataSize;
    //缓存大小
    privateString cacheSize;
     
    publicString getName()
    {
        returnname;
    }
    publicvoid setName(String name)
    {
        this.name = name;
    }
    publicString getPackageName()
    {
        returnpackageName;
    }
    publicvoid setPackageName(String packageName)
    {
        this.packageName = packageName;
    }
    publicDrawable getIcon()
    {
        returnicon;
    }
    publicvoid setIcon(Drawable icon)
    {
        this.icon = icon;
    }
    publicString getCodeSize()
    {
        returncodeSize;
    }
    publicvoid setCodeSize(String codeSize)
    {
        this.codeSize = codeSize;
    }
    publicString getDataSize()
    {
        returndataSize;
    }
    publicvoid setDataSize(String dataSize)
    {
        this.dataSize = dataSize;
    }
    publicString getCacheSize()
    {
        returncacheSize;
    }
    publicvoid setCacheSize(String cacheSize)
    {
        this.cacheSize = cacheSize;
    }
 
}

写完model类之后呢,我们就要把我们的应用的信息读取出来啦,比如读取应用大小啊,缓存大小啊,数据大小啊,这几个信息,

那么,怎样去读取这些信息呢,其实PackageManagerj里面有一个私有的方法的,叫getPackageSizeInfo,

所以现在思路清楚啦,我们就是要通过反射来调用这个方法,然后,getPackageSizeInfo这个方法要传递一个IPackageStatsObserver.Stub对象的,这个对象我们一看,就知道是一个AIDL的对象啦,所以,我们就要把相应的AIDL文件给放到src目录下面啦,我们就是在它里面拿到缓存大小,这 些数据的啦,

好啦,说得有点玄,直接上代码更清晰

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
 * 通过AIDL的方法来获取到应用的缓存信息,getPackageSizeInfo是PackageManager里面的一个私有方法来的
 * 我们通过反射就可以调用到它的了,但是这个方法里面会传递一个IPackageStatsObserver.Stub的对象
 * 里面就可能通过AIDL来获取我们想要的信息了
 *
 * 因为这样的调用是异步的,所以当我们完成获取完这些信息之后,我们就通过handler来发送一个消息
 * 来通知我们的应用,通过getCacheInfos来获取到我们的Vector
 *
 * 为什么要用Vector呢,因为下面的方法是异步的,也就是有可能是多线程操作,所以我们就用了线程安全的Vector
 *
 * @param cacheInfo
 * @param position
 */
privatevoid initDataSize(finalCacheInfo cacheInfo, finalint position)
{
    try
    {
        Method method = PackageManager.class.getMethod(
                "getPackageSizeInfo",newClass[] { String.class,
                        IPackageStatsObserver.class});
        method.invoke(packageManager,
                newObject[] { cacheInfo.getPackageName(),
                        newIPackageStatsObserver.Stub()
                        {
                            @Override
                            publicvoid onGetStatsCompleted(
                                    PackageStats pStats, booleansucceeded)
                                    throwsRemoteException
                            {
                                System.out.println("onGetStatsCompleted"+ position);
                                longcacheSize = pStats.cacheSize;
                                longcodeSize = pStats.codeSize;
                                longdataSize = pStats.dataSize;
 
                                cacheInfo.setCacheSize(TextFormater
                                        .dataSizeFormat(cacheSize));
                                cacheInfo.setCodeSize(TextFormater
                                        .dataSizeFormat(codeSize));
                                cacheInfo.setDataSize(TextFormater
                                        .dataSizeFormat(dataSize));
 
                                cacheInfos.add(cacheInfo);
 
                                if(position == (size - 1))
                                {
                                    // 当完全获取完信息之后,发送一个成功的消息
                                    // 1对应的就是CacheClearActivity里面的FINISH
                                    handler.sendEmptyMessage(1);
                                }
                            }
                        } });
    }
    catch(Exception e)
    {
        e.printStackTrace();
    }
}

有一点是要注意的,获取缓存大小这些信息的内部实现是异步的,所以我们用一个vector来存放信息,免得会出来一些特殊的情况


好啦,下面我们把完整的类粘出来,这个类写得有点复杂,主要是因为获取缓存大小这些信息的内部实现是异步的,我们要保证数据的正确性,所以可能就写得有点难理解

大家如果看不懂这个类的话,就欢迎留言

com.xiaobin.security.engine.CacheInfoProvider

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
packagecom.xiaobin.security.engine;
 
importjava.lang.reflect.Method;
importjava.util.List;
importjava.util.Vector;
 
importandroid.content.Context;
importandroid.content.pm.ApplicationInfo;
importandroid.content.pm.IPackageStatsObserver;
importandroid.content.pm.PackageInfo;
importandroid.content.pm.PackageManager;
importandroid.content.pm.PackageStats;
importandroid.graphics.drawable.Drawable;
importandroid.os.Handler;
importandroid.os.RemoteException;
 
importcom.xiaobin.security.domain.CacheInfo;
importcom.xiaobin.security.utils.TextFormater;
 
publicclass CacheInfoProvider
{
    privateHandler handler;
    privatePackageManager packageManager;
    privateVector<cacheinfo> cacheInfos;
    privateint size = 0;
 
    publicCacheInfoProvider(Handler handler, Context context)
    {
        // 拿到一个包管理器
        packageManager = context.getPackageManager();
        this.handler = handler;
        cacheInfos = newVector<cacheinfo>();
    }
 
    publicvoid initCacheInfos()
    {
        // 获取到所有安装了的应用程序的信息,包括那些卸载了的,但没有清除数据的应用程序
        List<packageinfo> packageInfos = packageManager
                .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
        size = packageInfos.size();
        for(inti = 0; i < size; i++)
        {
            PackageInfo packageInfo = packageInfos.get(i);
            CacheInfo cacheInfo = newCacheInfo();
            // 拿到包名
            String packageName = packageInfo.packageName;
            cacheInfo.setPackageName(packageName);
            // 拿到应用程序的信息
            ApplicationInfo applicationInfo = packageInfo.applicationInfo;
            // 拿到应用程序的程序名
            String name = applicationInfo.loadLabel(packageManager).toString();
            cacheInfo.setName(name);
            // 拿到应用程序的图标
            Drawable icon = applicationInfo.loadIcon(packageManager);
            cacheInfo.setIcon(icon);
 
            initDataSize(cacheInfo, i);
        }
    }
 
    /**
     * 通过AIDL的方法来获取到应用的缓存信息,getPackageSizeInfo是PackageManager里面的一个私有方法来的
     * 我们通过反射就可以调用到它的了,但是这个方法里面会传递一个IPackageStatsObserver.Stub的对象
     * 里面就可能通过AIDL来获取我们想要的信息了
     *
     * 因为这样的调用是异步的,所以当我们完成获取完这些信息之后,我们就通过handler来发送一个消息
     * 来通知我们的应用,通过getCacheInfos来获取到我们的Vector
     *
     * 为什么要用Vector呢,因为下面的方法是异步的,也就是有可能是多线程操作,所以我们就用了线程安全的Vector
     *
     * @param cacheInfo
     * @param position
     */
    privatevoid initDataSize(finalCacheInfo cacheInfo, finalint position)
    {
        try
        {
            Method method = PackageManager.class.getMethod(
                    "getPackageSizeInfo",newClass[] { String.class,
                            IPackageStatsObserver.class});
            method.invoke(packageManager,
                    newObject[] { cacheInfo.getPackageName(),
                            newIPackageStatsObserver.Stub()
                            {
                                @Override
                                publicvoid onGetStatsCompleted(
                                        PackageStats pStats, booleansucceeded)
                                        throwsRemoteException
                                {
                                    System.out.println("onGetStatsCompleted"+ position);
                                    longcacheSize = pStats.cacheSize;
                                    longcodeSize = pStats.codeSize;
                                    longdataSize = pStats.dataSize;
 
                                    cacheInfo.setCacheSize(TextFormater
                                            .dataSizeFormat(cacheSize));
                                    cacheInfo.setCodeSize(TextFormater
                                            .dataSizeFormat(codeSize));
                                    cacheInfo.setDataSize(TextFormater
                                            .dataSizeFormat(dataSize));
 
                                    cacheInfos.add(cacheInfo);
 
                                    if(position == (size - 1))
                                    {
                                        // 当完全获取完信息之后,发送一个成功的消息
                                        // 1对应的就是CacheClearActivity里面的FINISH
                                        handler.sendEmptyMessage(1);
                                    }
                                }
                            } });
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
 
    publicVector<cacheinfo> getCacheInfos()
    {
        returncacheInfos;
    }
 
    publicvoid setCacheInfos(Vector<cacheinfo> cacheInfos)
    {
        this.cacheInfos = cacheInfos;
    }
 
}
</cacheinfo></cacheinfo></packageinfo></cacheinfo></cacheinfo>

其实主要的思想是这们的,当完全获取完所有应用的缓存大小这些信息的时候,我们就给activity发送一个消息,然后activity里面的handler处理这个消息,然后就通过getCacheInfos这个方法,拿到所有已经填充好信息的CacheInfos对象的集合啦,这样,我们就可以回到activity里面填充数据啦


上面我已经说过了,如果我们要自己删除rom的缓存的话,那就是要root权限的,但我们现在没有,所以,我们就要通过系统设置里面的一个功能来进行清除啦

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
 * Android2.3打开settings里面的那个应用的详细界面
 * 后来我又查了一个Android4.1的,也是这样写的,所有应该是2.3之后,都是这样写的了,
 * 但是这只是猜测,各位有空的可以去下载Android Settings的代码看一下
 * 这样就可以做成多个版本的适配了
 * <intent-filter>
 
 * <category android:name="android.intent.category.DEFAULT">
 * <data android:scheme="package">
 * </data></category></action></intent-filter>
 */
 
/**
 * Android2.2打开settings里面的那个应用的详细界面
 * 用这个版本来打开的话,就要加多一句把包名设置进去的
 * intent.putExtra("pkg", packageName);
 * <intent-filter>
 
 * <category android:name="android.intent.category.DEFAULT">
 * <category android:name="android.intent.category.VOICE_LAUNCH">
 * </category></category></action></intent-filter>
 */
 
Intent intent = newIntent();
intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
intent.addCategory("android.intent.category.DEFAULT");
intent.setData(Uri.parse("package:"+ cacheInfos.get(position).getPackageName()));
startActivity(intent);

上面的注释已经很详细了,我就不多说啦


下面是完整的activity代码,布局文件就不放啦,因为写得太难看了

com.xiaobin.security.ui.CacheClearActivity

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
packagecom.xiaobin.security.ui;
 
importjava.util.Vector;
 
importandroid.annotation.SuppressLint;
importandroid.app.ListActivity;
importandroid.content.Intent;
importandroid.net.Uri;
importandroid.os.Bundle;
importandroid.os.Handler;
importandroid.os.Message;
importandroid.view.View;
importandroid.view.ViewGroup;
importandroid.view.Window;
importandroid.widget.AdapterView;
importandroid.widget.AdapterView.OnItemClickListener;
importandroid.widget.BaseAdapter;
importandroid.widget.ImageView;
importandroid.widget.LinearLayout;
importandroid.widget.ListView;
importandroid.widget.TextView;
 
importcom.xiaobin.security.R;
importcom.xiaobin.security.domain.CacheInfo;
importcom.xiaobin.security.engine.CacheInfoProvider;
 
publicclass CacheClearActivity extendsListActivity
{
    privatestatic final int LOADING = 0;
    privatestatic final int FINISH = 1;
 
    privateCacheInfoProvider provider;
 
    privateListView lv_list;
    privateLinearLayout ll_load;
 
    privateVector<cacheinfo> cacheInfos;
 
    @SuppressLint("HandlerLeak")
    privateHandler handler = newHandler()
    {
        publicvoid handleMessage(Message msg)
        {
            switch(msg.what)
            {
                caseLOADING:
                    ll_load.setVisibility(View.VISIBLE);
                    break;
 
                caseFINISH:
                    ll_load.setVisibility(View.INVISIBLE);
                    // 当加载完成之后,就调用provider里面的get方法,
                    // 这样就可以得到一个加载完成后的数据了
                    cacheInfos = provider.getCacheInfos();
                    lv_list.setAdapter(newCacheAdapter());
                    break;
 
                default:
                    break;
            }
        }
    };
 
    @Override
    protectedvoid onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.cache_clear);
 
        provider = newCacheInfoProvider(handler, this);
 
        lv_list = getListView();
        ll_load = (LinearLayout) findViewById(R.id.ll_cache_clear_load);
        lv_list.setOnItemClickListener(newOnItemClickListener()
        {
            @Override
            publicvoid onItemClick(AdapterView<!--?--> parent, View view,
                    intposition, longid)
            {
                /**
                 * Android2.3打开settings里面的那个应用的详细界面
                 * 后来我又查了一个Android4.1的,也是这样写的,所有应该是2.3之后,都是这样写的了,
                 * 但是这只是猜测,各位有空的可以去下载Android Settings的代码看一下
                 * 这样就可以做成多个版本的适配了
                 * <intent-filter>
                 
                 * <category android:name="android.intent.category.DEFAULT">
                 * <data android:scheme="package">
                 * </data></category></action></intent-filter>
                 */
                 
                /**
                 * Android2.2打开settings里面的那个应用的详细界面
                 * 用这个版本来打开的话,就要加多一句把包名设置进去的
                 * intent.putExtra("pkg", packageName);
                 * <intent-filter>
                 
                 * <category android:name="android.intent.category.DEFAULT">
                 * <category android:name="android.intent.category.VOICE_LAUNCH">
                 * </category></category></action></intent-filter>
                 */
                 
                Intent intent = newIntent();
                intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
                intent.addCategory("android.intent.category.DEFAULT");
                intent.setData(Uri.parse("package:"+ cacheInfos.get(position).getPackageName()));
                startActivity(intent);
            }
        });
 
        loadData();
    }
     
    privatevoid loadData()
    {
        ll_load.setVisibility(View.VISIBLE);
        newThread(newRunnable()
        {
            @Override
            publicvoid run()
            {
                provider.initCacheInfos();
            }
        }).start();
    }
 
    // =======================================================================
 
    privateclass CacheAdapter extendsBaseAdapter
    {
 
        @Override
        publicint getCount()
        {
            returncacheInfos.size();
        }
 
        @Override
        publicObject getItem(intposition)
        {
            returncacheInfos.get(position);
        }
 
        @Override
        publiclong getItemId(intposition)
        {
            returnposition;
        }
 
        @Override
        publicView getView(intposition, View convertView, ViewGroup parent)
        {
            View view;
            ViewHolder holder;
            CacheInfo info = cacheInfos.get(position);
            if(convertView == null)
            {
                view = View.inflate(CacheClearActivity.this,
                        R.layout.cache_clear_item,null);
                holder = newViewHolder();
                holder.iv_icon = (ImageView) view
                        .findViewById(R.id.iv_cache_icon);
                holder.tv_name = (TextView) view
                        .findViewById(R.id.tv_cache_name);
                holder.tv_code = (TextView) view
                        .findViewById(R.id.tv_cache_code);
                holder.tv_data = http://www.mamicode.com/(TextView) view
                        .findViewById(R.id.tv_cache_data);
                holder.tv_cache = (TextView) view
                        .findViewById(R.id.tv_cache_cache);
                view.setTag(holder);
            }
            else
            {
                view = convertView;
                holder = (ViewHolder) view.getTag();
            }
            holder.iv_icon.setImageDrawable(info.getIcon());
            holder.tv_name.setText(info.getName());
            holder.tv_code.setText("应用大小:"+ info.getCodeSize());
            holder.tv_data.setText("数据大小:"+ info.getDataSize());
            holder.tv_cache.setText("缓存大小:"+ info.getCacheSize());
            returnview;
        }
 
    }
 
    privateclass ViewHolder
    {
        ImageView iv_icon;
        TextView tv_name;
        TextView tv_cache;
        TextView tv_code;
        TextView tv_data;
 
    }
 
}
</cacheinfo>

好啦,到这里为止,我们的清除rom里面的缓存,就已经是完成的啦,最后,我给大家说一下清除sd卡里面的缓存是怎样的

大家都知道,我们装的大部分应用,都会有sd卡里面建一个目录,然后装一些应用的信息的,而这些,就是这些应用对应存放缓存的目录啦,

要清除sd卡里面的缓存,其实就是要有一个数据库啦,它专门收录市面上一些常用的应用,在sd卡上建立的目录名称,然后再通过这个数据库,然后对sd卡里面的目录清除的而已,这个方法是比较的麻烦的,还要有数据库的支持才行,所以大家可以自己试试


Android 清楚程序缓存