【0076】【项目实战】-【手机安全卫士】-【16】缓存清理模块
1.清理缓存信息模块的效果

2.缓存信息的源码的查找
【缓存信息的获取】借鉴系统中应用信息的源码;










【关键的动态的赋值源码】






【源码查找的总结】

3.获取缓存信息的demo
3.1 方法和类的简单分析



【传递的对象的参数】aidl文件;

3.2 demo源码的书写
【aidl文件】



【bug1】报错


【源码】

【bug2】方法不能使用,原因是此方法只存在系统应用中使用;在系统源码中存在关键字:“@hide”
解决的方法:使用反射调用系统的方法;



【运行存在的bug】系统的异常:黄色文字;



【运行结果】


3.3 onGetStatsCompleted方法运行线程
【说明】因为在更新UI中,只能使用主线程,但是现在查到的缓存是子线程还是主线程待验证!!!

【结果】两个线程的值不一致;说明获取缓冲信息的是子线程;

【源码】
1 package com.example.cachedemo; 2 3 import java.lang.reflect.Method; 4 5 import android.os.Bundle; 6 import android.os.RemoteException; 7 import android.app.Activity; 8 import android.content.pm.IPackageStatsObserver; 9 import android.content.pm.PackageManager; 10 import android.content.pm.PackageStats; 11 import android.text.format.Formatter; 12 13 public class MainActivity extends Activity { 14 15 private IPackageStatsObserver.Stub mStatsObserver; 16 17 @Override 18 protected void onCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 PackageManager mPm = getPackageManager(); 22 System.out.println("主线程id = "+Thread.currentThread().getId()); 23 mStatsObserver = new IPackageStatsObserver.Stub(){ 24 @Override 25 public void onGetStatsCompleted(PackageStats pStats, 26 boolean succeeded) throws RemoteException { 27 long cacheSize = pStats.cacheSize; 28 String str = Formatter.formatFileSize(getApplicationContext(), cacheSize); 29 System.out.println("===================str = "+str); 30 System.out.println("线程id = "+Thread.currentThread().getId()); 31 } 32 }; 33 // mPm.getPackageSizeInfo("com.android.broswer", mStatsObserver);
//使用反射 34 try { 35 Class<?> clazz = Class.forName("android.content.pm.PackageManager"); 36 Method method = clazz.getMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class); 37 method.invoke(mPm, "com.android.browser",mStatsObserver); 38 } catch (Exception e) { 39 e.printStackTrace(); 40 } 41 } 42 }
4.缓存清理布局编写
4.1 缓存布局分析
【说明】放在线性布局中;

4.2 跳转到的页面布局的编写
【开启页面的跳转】



【进度条编写临时测试】查看进度条的效果,看看进度条是否可以显示;
测试结束之后删除测试代码;


【说明】在ScrollView中包含了LinearLayout;
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <RelativeLayout 7 android:layout_width="match_parent" 8 android:layout_height="wrap_content"> 9 <TextView 10 android:text="缓存清理" 11 style="@style/TitleStyle" 12 android:gravity="left"/> 13 <Button 14 android:id="@+id/bt_clear" 15 android:text="立即清理" 16 android:layout_alignParentRight="true" 17 android:layout_centerVertical="true" 18 android:layout_width="wrap_content" 19 android:layout_height="wrap_content"/> 20 </RelativeLayout> 21 <ProgressBar 22 android:id="@+id/pb_bar" 23 android:progressDrawable="@drawable/progress_bg" 24 style="@android:style/Widget.ProgressBar.Horizontal" 25 android:layout_width="match_parent" 26 android:layout_height="wrap_content"/> 27 <TextView 28 android:text="正在清理缓存应用" 29 android:id="@+id/tv_name" 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content"/> 32 <ScrollView 33 android:layout_width="match_parent" 34 android:layout_height="wrap_content"> 35 <!-- 将所有的TextView都包裹在内部(将TextView从头部做插入),以满足scrollView有一个子节点 --> 36 <LinearLayout 37 android:id="@+id/ll_add_text" 38 android:orientation="vertical" 39 android:layout_width="wrap_content" 40 android:layout_height="wrap_content"> 41 </LinearLayout> 42 </ScrollView> 43 </LinearLayout>
5.【源码】获取有缓存的应用添加至线性布局
【说明】单个条目中存在的信息

【说明】根据包名,获取应用的缓存信息;但是:有的应用是具有缓存的,有些应用是没有缓存的;

【说明】需要拷贝aidl文件,直接复制包到该应用中;




【接收消息之后加载的布局】
1 <?xml version="1.0" encoding="utf-8"?> 2 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="wrap_content" > 5 <ImageView 6 android:id="@+id/iv_icon" 7 android:background="@drawable/ic_launcher" 8 android:layout_width="45dp" 9 android:layout_height="45dp"/> 10 <TextView 11 android:id="@+id/tv_name" 12 android:text="应用名称" 13 android:textSize="18sp" 14 android:layout_toRightOf="@id/iv_icon" 15 android:layout_width="wrap_content" 16 android:layout_height="wrap_content"/> 17 <TextView 18 android:id="@+id/tv_memory_info" 19 android:textSize="18sp" 20 android:text="占用内存大小" 21 android:layout_toRightOf="@id/iv_icon" 22 android:layout_below="@id/tv_name" 23 android:layout_width="wrap_content" 24 android:layout_height="wrap_content"/> 25 <ImageView 26 android:id="@+id/iv_delete" 27 android:background="@drawable/selector_blacknumber_delete_btn_bg" 28 android:layout_alignParentRight="true" 29 android:layout_centerVertical="true" 30 android:layout_width="wrap_content" 31 android:layout_height="wrap_content"/> 32 </RelativeLayout>

【缓存信息的添加】
1 public class CacheClearActivity extends Activity { 2 protected static final int UPDATE_CACHE_APP = 100; 3 protected static final int CHECK_CACHE_APP = 101; 4 protected static final int CHECK_FINISH = 102; 5 protected static final int CLEAR_CACHE = 103; 6 protected static final String tag = "CacheClearActivity"; 7 8 private Button bt_clear; 9 private ProgressBar pb_bar; 10 private TextView tv_name; 11 private LinearLayout ll_add_text; 12 private PackageManager mPm; 13 private int mIndex = 0; 14 15 private Handler mHandler = new Handler(){ 16 public void handleMessage(Message msg) { 17 switch (msg.what) { 18 case UPDATE_CACHE_APP: 19 //8.在线性布局中添加有缓存应用条目 20 View view = View.inflate(getApplicationContext(), R.layout.linearlayout_cache_item, null); 21 22 ImageView iv_icon = (ImageView) view.findViewById(R.id.iv_icon); 23 TextView tv_item_name = (TextView) view.findViewById(R.id.tv_name); 24 TextView tv_memory_info = (TextView)view.findViewById(R.id.tv_memory_info); 25 ImageView iv_delete = (ImageView) view.findViewById(R.id.iv_delete); 26 27 final CacheInfo cacheInfo = (CacheInfo) msg.obj; 28 iv_icon.setBackgroundDrawable(cacheInfo.icon); 29 tv_item_name.setText(cacheInfo.name); 30 tv_memory_info.setText(Formatter.formatFileSize(getApplicationContext(), cacheInfo.cacheSize)); 31 32 ll_add_text.addView(view, 0); 33 34 }); 35 break; 36 } 37 }; 38 };

【源码】
1 package com.itheima.mobilesafe74.activity; 2 3 import java.lang.reflect.Method; 4 import java.util.List; 5 import java.util.Random; 6 7 import com.itheima.mobilesafe74.R; 8 import android.app.Activity; 9 import android.content.Intent; 10 import android.content.pm.IPackageDataObserver; 11 import android.content.pm.IPackageStatsObserver; 12 import android.content.pm.PackageInfo; 13 import android.content.pm.PackageManager; 14 import android.content.pm.PackageManager.NameNotFoundException; 15 import android.content.pm.PackageStats; 16 import android.graphics.drawable.Drawable; 17 import android.net.Uri; 18 import android.os.Bundle; 19 import android.os.Handler; 20 import android.os.Message; 21 import android.os.RemoteException; 22 import android.text.format.Formatter; 23 import android.util.Log; 24 import android.view.View; 25 import android.view.View.OnClickListener; 26 import android.widget.Button; 27 import android.widget.ImageView; 28 import android.widget.LinearLayout; 29 import android.widget.ProgressBar; 30 import android.widget.TextView; 31 32 public class CacheClearActivity extends Activity { 33 protected static final int UPDATE_CACHE_APP = 100; 34 protected static final int CHECK_CACHE_APP = 101; 35 protected static final int CHECK_FINISH = 102; 36 protected static final int CLEAR_CACHE = 103; 37 protected static final String tag = "CacheClearActivity"; 38 39 private Button bt_clear; 40 private ProgressBar pb_bar; 41 private TextView tv_name; 42 private LinearLayout ll_add_text; 43 private PackageManager mPm; 44 private int mIndex = 0; 45 46 private Handler mHandler = new Handler(){ 47 public void handleMessage(Message msg) { 48 switch (msg.what) { 49 case UPDATE_CACHE_APP: 50 //8.在线性布局中添加有缓存应用条目 51 View view = View.inflate(getApplicationContext(), R.layout.linearlayout_cache_item, null); 52 53 ImageView iv_icon = (ImageView) view.findViewById(R.id.iv_icon); 54 TextView tv_item_name = (TextView) view.findViewById(R.id.tv_name); 55 TextView tv_memory_info = (TextView)view.findViewById(R.id.tv_memory_info); 56 ImageView iv_delete = (ImageView) view.findViewById(R.id.iv_delete); 57 58 final CacheInfo cacheInfo = (CacheInfo) msg.obj; 59 iv_icon.setBackgroundDrawable(cacheInfo.icon); 60 tv_item_name.setText(cacheInfo.name); 61 tv_memory_info.setText(Formatter.formatFileSize(getApplicationContext(), cacheInfo.cacheSize)); 62 63 ll_add_text.addView(view, 0); 64 65 break; 66 }; 67 }; 68 69 @Override 70 protected void onCreate(Bundle savedInstanceState) { 71 super.onCreate(savedInstanceState); 72 setContentView(R.layout.activity_cache_clear); 73 initUI(); 74 initData(); 75 } 76 77 /** 78 * 遍历手机所有的应用,获取有缓存的应用,用作显示 79 */ 80 private void initData() { 81 new Thread(){ 82 public void run() { 83 //1.获取包管理者对象 84 85 mPm = getPackageManager(); 86 87 //2.获取安装在手机上的所有的应用 88 List<PackageInfo> installedPackages = mPm.getInstalledPackages(0); 89 //3.给进度条设置最大值(手机中所有应用的总数) 90 pb_bar.setMax(installedPackages.size()); 91 //4.遍历每一个应用,获取有缓存的应用信息(应用名称,图标,缓存大小,包名) 92 for (PackageInfo packageInfo : installedPackages) { 93 //包名作为获取缓存信息的条件 94 String packageName = packageInfo.packageName; 95 getPackageCache(packageName); 96 97 try { 98 Thread.sleep(100+new Random().nextInt(50)); 99 } catch (InterruptedException e) { 100 e.printStackTrace(); 101 } 102 105 //每循环一次就将检测应用的名称发送给主线程显示 106 Message msg = Message.obtain(); 107 msg.what = CHECK_CACHE_APP; 108 String name = null; 109 try { 110 name = mPm.getApplicationInfo(packageName, 0).loadLabel(mPm).toString(); 111 } catch (NameNotFoundException e) { 112 e.printStackTrace(); 113 } 114 msg.obj = name; 115 mHandler.sendMessage(msg); 116 } 117 Message msg = Message.obtain(); 118 msg.what = CHECK_FINISH; 119 mHandler.sendMessage(msg); 120 }; 121 }.start(); 122 } 123 124 class CacheInfo{ 125 public String name; 126 public Drawable icon; 127 public String packagename; 128 public long cacheSize; 129 } 130 131 /**通过包名获取此包名指向应用的缓存信息 132 * @param packageName 应用包名 133 */ 134 protected void getPackageCache(String packageName) { 135 IPackageStatsObserver.Stub mStatsObserver = new IPackageStatsObserver.Stub() { 136 137 public void onGetStatsCompleted(PackageStats stats, 138 boolean succeeded) { 139 //子线程中方法,用到消息机制 140 141 //4.获取指定包名的缓存大小 142 long cacheSize = stats.cacheSize; 143 //5.判断缓存大小是否大于0 144 if(cacheSize>0){ 145 //6.告知主线程更新UI 146 Message msg = Message.obtain(); 147 msg.what = UPDATE_CACHE_APP; 148 CacheInfo cacheInfo = null; 149 try { 150 //7.维护有缓存应用的javabean 151 cacheInfo = new CacheInfo(); 152 cacheInfo.cacheSize = cacheSize; 153 cacheInfo.packagename = stats.packageName; 154 cacheInfo.name = mPm.getApplicationInfo(stats.packageName, 0).loadLabel(mPm).toString(); 155 cacheInfo.icon = mPm.getApplicationInfo(stats.packageName, 0).loadIcon(mPm); 156 } catch (NameNotFoundException e) { 157 e.printStackTrace(); 158 } 159 msg.obj = cacheInfo; 160 mHandler.sendMessage(msg); 161 } 162 } 163 }; 164 //1.获取指定类的字节码文件 165 try { 166 Class<?> clazz = Class.forName("android.content.pm.PackageManager"); 167 //2.获取调用方法对象 168 Method method = clazz.getMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class); 169 //3.获取对象调用方法 170 method.invoke(mPm, packageName,mStatsObserver); 171 } catch (Exception e) { 172 // TODO Auto-generated catch block 173 e.printStackTrace(); 174 } 175 } 176 177 private void initUI() { 178 bt_clear = (Button) findViewById(R.id.bt_clear); 179 pb_bar = (ProgressBar) findViewById(R.id.pb_bar); 180 tv_name = (TextView) findViewById(R.id.tv_name); 181 ll_add_text = (LinearLayout) findViewById(R.id.ll_add_text); 182 183 bt_clear.setOnClickListener(new OnClickListener() { 184 @Override 185 public void onClick(View v) { 186 //1.获取指定类的字节码文件 187 try { 188 Class<?> clazz = Class.forName("android.content.pm.PackageManager"); 189 //2.获取调用方法对象 190 Method method = clazz.getMethod("freeStorageAndNotify", long.class,IPackageDataObserver.class); 191 //3.获取对象调用方法 192 method.invoke(mPm, Long.MAX_VALUE,new IPackageDataObserver.Stub() { 193 @Override 194 public void onRemoveCompleted(String packageName, boolean succeeded) 195 throws RemoteException { 196 //清除缓存完成后调用的方法(考虑权限) 197 Message msg = Message.obtain(); 198 msg.what = CLEAR_CACHE; 199 mHandler.sendMessage(msg); 200 } 201 }); 202 } catch (Exception e) { 203 e.printStackTrace(); 204 } 205 } 206 }); 207 } 208 }
【效果】

6.获取缓存界面进度条更新
【原理】每遍历一个应用程序相应的进度条都会进行改变;



7.文字的改变
【正在扫描信息时的文字】


【扫描完成之后的信息的发送】



8.一键清理功能

【源码当中的方法】需要使用反射技术

【权限的增加】


1 private void initUI() { 2 bt_clear = (Button) findViewById(R.id.bt_clear); 3 pb_bar = (ProgressBar) findViewById(R.id.pb_bar); 4 tv_name = (TextView) findViewById(R.id.tv_name); 5 ll_add_text = (LinearLayout) findViewById(R.id.ll_add_text); 6 7 bt_clear.setOnClickListener(new OnClickListener() { 8 @Override 9 public void onClick(View v) { 10 //1.获取指定类的字节码文件 11 try { 12 Class<?> clazz = Class.forName("android.content.pm.PackageManager"); 13 //2.获取调用方法对象 14 Method method = clazz.getMethod("freeStorageAndNotify", long.class,IPackageDataObserver.class); 15 //3.获取对象调用方法 16 method.invoke(mPm, Long.MAX_VALUE,new IPackageDataObserver.Stub() { 17 @Override 18 public void onRemoveCompleted(String packageName, boolean succeeded) 19 throws RemoteException { 20 //清除缓存完成后调用的方法(考虑权限) 21 Message msg = Message.obtain(); 22 msg.what = CLEAR_CACHE; 23 mHandler.sendMessage(msg); 24 } 25 }); 26 } catch (Exception e) { 27 e.printStackTrace(); 28 } 29 } 30 }); 31 }
1 private Handler mHandler = new Handler(){ 2 public void handleMessage(Message msg) { 3 switch (msg.what) { 4 case UPDATE_CACHE_APP: 5 //8.在线性布局中添加有缓存应用条目 6 View view = View.inflate(getApplicationContext(), R.layout.linearlayout_cache_item, null); 7 8 ImageView iv_icon = (ImageView) view.findViewById(R.id.iv_icon); 9 TextView tv_item_name = (TextView) view.findViewById(R.id.tv_name); 10 TextView tv_memory_info = (TextView)view.findViewById(R.id.tv_memory_info); 11 ImageView iv_delete = (ImageView) view.findViewById(R.id.iv_delete); 12 13 final CacheInfo cacheInfo = (CacheInfo) msg.obj; 14 iv_icon.setBackgroundDrawable(cacheInfo.icon); 15 tv_item_name.setText(cacheInfo.name); 16 tv_memory_info.setText(Formatter.formatFileSize(getApplicationContext(), cacheInfo.cacheSize)); 17 18 ll_add_text.addView(view, 0); 19 51 break; 52 case CHECK_CACHE_APP: 53 tv_name.setText((String)msg.obj); 54 break; 55 case CHECK_FINISH: 56 tv_name.setText("扫描完成"); 57 break; 58 case CLEAR_CACHE: 59 //从线性布局中移除所有的条目 60 ll_add_text.removeAllViews(); 61 break; 62 } 63 };

【说明】在已经清理再次清理的时候出现的缓存为0;

9.单个应用缓存清理

【源码】清楚应用中的缓存

【说明】测试逻辑出现的问题-因为不是系统的应用,因此无法进行缓存的清理;



【想法】借助系统的中的清楚缓存的功能;

【清楚缓存信息的界面的查找】

【日志信息的分析】

【开启隐式意图的源码实现】


10.选项卡使用
【说明】实际在下面的界面中,存在3个Activity,一个大的Activity,包含了两个重叠的稍微小点的Activity,可以通过选项卡按钮进行切换显示重叠的Activity;

10.1 跳转的修改
【说明】刚开始的跳转的时候先进入的是BaseCacheClearActivity;
点击1,则进入到1对应的Activity;
点击2,则进入到2对应的Activity;


10.2【BaseCacheClearActivity】





1 <?xml version="1.0" encoding="utf-8"?> 2 <!-- 放置选项卡和选项卡指向界面的控件 --> 3 <TabHost xmlns:android="http://schemas.android.com/apk/res/android" 4 android:layout_width="match_parent" 5 android:layout_height="match_parent" 6 android:id="@android:id/tabhost"> 7 <!-- 选项卡指向内容页所在的布局 --> 8 <FrameLayout 9 android:id="@android:id/tabcontent" 10 android:layout_marginBottom="50dp" 11 android:layout_width="match_parent" 12 android:layout_height="match_parent" > 13 </FrameLayout> 14 <!-- 选项卡控件 --> 15 <TabWidget 16 android:id="@android:id/tabs" 17 android:layout_gravity="bottom" 18 android:layout_width="match_parent" 19 android:layout_height="50dp" > 20 </TabWidget> 21 </TabHost>
10.3 布局的切换




【效果】默认选中的“缓存清理选项卡”

10.4 View作为选项卡的背景
【图片为背景】


【布局为背景】

【说明】选项按钮的背景具有图片和文件的View布局;

【补充】可以使用该控件完成类似微信的底部4个按钮的效果,一个按钮对应一个Activity;

11.【sd卡缓存清理的原理】
【说明】360的做法是将所有包名文件夹下关于Cache的文件夹都抹去;
另外一种做法维护数据库,读取数据库中的内容然后根据提前整理好的表项进行删除文件;

浙公网安备 33010602011771号