【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的文件夹都抹去;

            另外一种做法维护数据库,读取数据库中的内容然后根据提前整理好的表项进行删除文件;

 

posted @ 2018-02-17 17:26  OzTaking  阅读(387)  评论(0)    收藏  举报