首页 > 代码库 > 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 | package com.xiaobin.security.domain; import android.graphics.drawable.Drawable; public class CacheInfo { private String name; private String packageName; private Drawable icon; //应用大小 private String codeSize; //数据大小 private String dataSize; //缓存大小 private String cacheSize; public String getName() { return name; } public void setName(String name) { this .name = name; } public String getPackageName() { return packageName; } public void setPackageName(String packageName) { this .packageName = packageName; } public Drawable getIcon() { return icon; } public void setIcon(Drawable icon) { this .icon = icon; } public String getCodeSize() { return codeSize; } public void setCodeSize(String codeSize) { this .codeSize = codeSize; } public String getDataSize() { return dataSize; } public void setDataSize(String dataSize) { this .dataSize = dataSize; } public String getCacheSize() { return cacheSize; } public void 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 */ private void initDataSize( final CacheInfo cacheInfo, final int position) { try { Method method = PackageManager. class .getMethod( "getPackageSizeInfo" , new Class[] { String. class , IPackageStatsObserver. class }); method.invoke(packageManager, new Object[] { cacheInfo.getPackageName(), new IPackageStatsObserver.Stub() { @Override public void onGetStatsCompleted( PackageStats pStats, boolean succeeded) throws RemoteException { System.out.println( "onGetStatsCompleted" + position); long cacheSize = pStats.cacheSize; long codeSize = pStats.codeSize; long dataSize = 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 | package com.xiaobin.security.engine; import java.lang.reflect.Method; import java.util.List; import java.util.Vector; import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.IPackageStatsObserver; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PackageStats; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.RemoteException; import com.xiaobin.security.domain.CacheInfo; import com.xiaobin.security.utils.TextFormater; public class CacheInfoProvider { private Handler handler; private PackageManager packageManager; private Vector<cacheinfo> cacheInfos; private int size = 0 ; public CacheInfoProvider(Handler handler, Context context) { // 拿到一个包管理器 packageManager = context.getPackageManager(); this .handler = handler; cacheInfos = new Vector<cacheinfo>(); } public void initCacheInfos() { // 获取到所有安装了的应用程序的信息,包括那些卸载了的,但没有清除数据的应用程序 List<packageinfo> packageInfos = packageManager .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); size = packageInfos.size(); for ( int i = 0 ; i < size; i++) { PackageInfo packageInfo = packageInfos.get(i); CacheInfo cacheInfo = new CacheInfo(); // 拿到包名 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 */ private void initDataSize( final CacheInfo cacheInfo, final int position) { try { Method method = PackageManager. class .getMethod( "getPackageSizeInfo" , new Class[] { String. class , IPackageStatsObserver. class }); method.invoke(packageManager, new Object[] { cacheInfo.getPackageName(), new IPackageStatsObserver.Stub() { @Override public void onGetStatsCompleted( PackageStats pStats, boolean succeeded) throws RemoteException { System.out.println( "onGetStatsCompleted" + position); long cacheSize = pStats.cacheSize; long codeSize = pStats.codeSize; long dataSize = 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(); } } public Vector<cacheinfo> getCacheInfos() { return cacheInfos; } public void 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 = new Intent(); 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 | package com.xiaobin.security.ui; import java.util.Vector; import android.annotation.SuppressLint; import android.app.ListActivity; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import com.xiaobin.security.R; import com.xiaobin.security.domain.CacheInfo; import com.xiaobin.security.engine.CacheInfoProvider; public class CacheClearActivity extends ListActivity { private static final int LOADING = 0 ; private static final int FINISH = 1 ; private CacheInfoProvider provider; private ListView lv_list; private LinearLayout ll_load; private Vector<cacheinfo> cacheInfos; @SuppressLint ( "HandlerLeak" ) private Handler handler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case LOADING: ll_load.setVisibility(View.VISIBLE); break ; case FINISH: ll_load.setVisibility(View.INVISIBLE); // 当加载完成之后,就调用provider里面的get方法, // 这样就可以得到一个加载完成后的数据了 cacheInfos = provider.getCacheInfos(); lv_list.setAdapter( new CacheAdapter()); break ; default : break ; } } }; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.cache_clear); provider = new CacheInfoProvider(handler, this ); lv_list = getListView(); ll_load = (LinearLayout) findViewById(R.id.ll_cache_clear_load); lv_list.setOnItemClickListener( new OnItemClickListener() { @Override public void onItemClick(AdapterView<!--?--> parent, View view, int position, long id) { /** * 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 = new Intent(); 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(); } private void loadData() { ll_load.setVisibility(View.VISIBLE); new Thread( new Runnable() { @Override public void run() { provider.initCacheInfos(); } }).start(); } // ======================================================================= private class CacheAdapter extends BaseAdapter { @Override public int getCount() { return cacheInfos.size(); } @Override public Object getItem( int position) { return cacheInfos.get(position); } @Override public long getItemId( int position) { return position; } @Override public View getView( int position, 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 = new ViewHolder(); 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()); return view; } } private class ViewHolder { ImageView iv_icon; TextView tv_name; TextView tv_cache; TextView tv_code; TextView tv_data; } } </cacheinfo> |
好啦,到这里为止,我们的清除rom里面的缓存,就已经是完成的啦,最后,我给大家说一下清除sd卡里面的缓存是怎样的
大家都知道,我们装的大部分应用,都会有sd卡里面建一个目录,然后装一些应用的信息的,而这些,就是这些应用对应存放缓存的目录啦,
要清除sd卡里面的缓存,其实就是要有一个数据库啦,它专门收录市面上一些常用的应用,在sd卡上建立的目录名称,然后再通过这个数据库,然后对sd卡里面的目录清除的而已,这个方法是比较的麻烦的,还要有数据库的支持才行,所以大家可以自己试试
Android 清楚程序缓存