手机卫士day13

Day13

  • 新建工程,获取缓存大小

    布局文件开发

    <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:orientation="vertical" >
    
        <EditText
            android:id="@+id/et_package"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:hint="请输入包名" >
        </EditText>
    
        <Button
            android:id="@+id/btn_ok"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="确定" />
    
        <TextView
            android:id="@+id/tv_result"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="查询结果" />
    
    </LinearLayout>
    
    • 查看系统设置源码, 查看清理缓存逻辑

      1. 导入Setting源码
      2. 查找清除缓存的逻辑

        Clear cache->clear_cache_btn_text->installed_app_details->InstalledAppDetails->cache_size_text-> mAppEntry.cacheSize->stats.cacheSize->stats->mStatsObserver->getPackageSizeInfo->查看PackageManager源码,跟踪方法getPackageSizeInfo,发现改方法隐藏
        
      3. 通过反射方式,调用PackageManager的方法

        public Method[] getMethods()返回某个类的所有公用(public)方法包括其继承类的公用方法,当然也包括它所实现接口的方法。
        
        public Method[] getDeclaredMethods()对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。当然也包括它所实现接口的方法。
        
        //需要权限:android.permission.GET_PACKAGE_SIZE
        
        btnOk.setOnClickListener(new OnClickListener() {
        
            @Override
            public void onClick(View v) {
                String packageName = etPackage.getText().toString().trim();
                if (!TextUtils.isEmpty(packageName)) {
                    PackageManager pm = getPackageManager();
                    try {
                        Method method = pm.getClass().getMethod(
                                "getPackageSizeInfo", String.class,
                                IPackageStatsObserver.class);
                        method.invoke(pm, packageName, new MyObserver());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                } else {
                    Toast.makeText(getApplicationContext(), "输入内容不能为空!",
                            Toast.LENGTH_SHORT).show();
                }
            }
        });
        
        -------------------------------------
        
        class MyObserver extends IPackageStatsObserver.Stub {
        
            // 在子线程运行
            @Override
            public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
                    throws RemoteException {
                long cacheSize = pStats.cacheSize;
                long dataSize = pStats.dataSize;
                long codeSize = pStats.codeSize;
        
                String result = "缓存:"
                        + Formatter.formatFileSize(getApplicationContext(),
                                cacheSize)
                        + "\n"
                        + "数据:"
                        + Formatter.formatFileSize(getApplicationContext(),
                                dataSize)
                        + "\n"
                        + "代码:"
                        + Formatter.formatFileSize(getApplicationContext(),
                                codeSize);
                System.out.println(result);
                Message msg = Message.obtain();
                msg.obj = result;
                mHandler.sendMessage(msg);
            }
        }
        
  • 缓存清理模块开发

    • 新建页面CleanCacheActivity
    • 布局文件开发

      <?xml version="1.0" encoding="utf-8"?>
      <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="vertical" >
          <RelativeLayout
              android:layout_width="match_parent"
              android:layout_height="50dp"
              android:background="#8866ff00" >
      
              <TextView
                  android:id="@+id/textView1"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_centerVertical="true"
                  android:layout_marginLeft="5dp"
                  android:text="缓存清理"
                  android:textColor="#000"
                  android:textSize="22sp" />
              <Button
                  android:id="@+id/button1"
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:layout_alignParentRight="true"
                  android:layout_centerVertical="true"
                  android:layout_marginRight="5dp"
                  android:onClick="cleanCache"
                  android:text="立即清理" />
          </RelativeLayout>
          <ProgressBar
              android:id="@+id/pb_progress"
              style="?android:attr/progressBarStyleHorizontal"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:progressDrawable="@drawable/custom_progress" />
          <TextView
              android:id="@+id/tv_status"
              android:layout_width="match_parent"
              android:layout_height="wrap_content"
              android:text="正在扫描:" />
          <ScrollView
              android:layout_width="match_parent"
              android:layout_height="match_parent" >
      
              <LinearLayout
                  android:id="@+id/ll_container"
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  android:orientation="vertical" >
              </LinearLayout>
          </ScrollView>
      </LinearLayout>
      
    • 缓存页面逻辑

      private Handler mHandler = new Handler() {
          public void handleMessage(android.os.Message msg) {
              switch (msg.what) {
              case SCANNING:
                  String name = (String) msg.obj;
                  tvStatus.setText("正在扫描:" + name);
                  break;
              case SHOW_CACHE_INFO:
                  CacheInfo info = (CacheInfo) msg.obj;
                  View itemView = View.inflate(getApplicationContext(),
                          R.layout.list_cacheinfo_item, null);
                  TextView tvName = (TextView) itemView
                          .findViewById(R.id.tv_name);
                  ImageView ivIcon = (ImageView) itemView
                          .findViewById(R.id.iv_icon);
                  TextView tvCache = (TextView) itemView
                          .findViewById(R.id.tv_cache_size);
                  ImageView ivDelete = (ImageView) itemView
                          .findViewById(R.id.iv_delete);
      
                  tvName.setText(info.name);
                  ivIcon.setImageDrawable(info.icon);
                  tvCache.setText("缓存大小:"
                          + Formatter.formatFileSize(getApplicationContext(),
                                  info.cacheSize));
      
                  llContainer.addView(itemView);
                  break;
              case SCANNING_FINISHED:
                  tvStatus.setText("扫描完成");
                  break;
      
              default:
                  break;
              }
          };
      };
      
      /**
       * 开始扫描
       */
      private void startScan() {
          new Thread() {
              @Override
              public void run() {
                  List<PackageInfo> packages = mPM
                          .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES);
      
                  pbProgress.setMax(packages.size());// 设置进度条最大值为安装包的数量
                  int progress = 0;
                  for (PackageInfo packageInfo : packages) {
                      try {
                          Method method = mPM.getClass().getMethod(
                                  "getPackageSizeInfo", String.class,
                                  IPackageStatsObserver.class);
                          method.invoke(mPM, packageInfo.packageName,
                                  new MyObserver());
                      } catch (Exception e) {
                          e.printStackTrace();
                      }
      
                      progress++;
                      pbProgress.setProgress(progress);
      
                      // 发送更新进度的消息
                      Message msg = Message.obtain();
                      msg.what = SCANNING;
                      msg.obj = packageInfo.applicationInfo.loadLabel(mPM)
                              .toString();
                      mHandler.sendMessage(msg);
                      try {
                          Thread.sleep(50);
                      } catch (InterruptedException e) {
                          e.printStackTrace();
                      }
                  }
      
                  // 发送扫描结束的消息
                  mHandler.sendEmptyMessage(SCANNING_FINISHED);
              }
          }.start();
      }
      
      class MyObserver extends IPackageStatsObserver.Stub {
      
          // 在子线程运行
          @Override
          public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
                  throws RemoteException {
              long cacheSize = pStats.cacheSize;// 获取缓存大小
              if (cacheSize > 0) {
                  try {
                      CacheInfo info = new CacheInfo();
                      String packageName = pStats.packageName;
                      info.packageName = packageName;
      
                      ApplicationInfo applicationInfo = mPM.getApplicationInfo(
                              packageName, 0);
                      info.name = applicationInfo.loadLabel(mPM).toString();
                      info.icon = applicationInfo.loadIcon(mPM);
                      info.cacheSize = cacheSize;
      
                      // 扫描到缓存应用时发送消息
                      Message msg = Message.obtain();
                      msg.what = SHOW_CACHE_INFO;
                      msg.obj = info;
                      mHandler.sendMessage(msg);
      
                  } catch (NameNotFoundException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
      
      // 缓存对象的封装
      class CacheInfo {
          public String name;
          public String packageName;
          public Drawable icon;
          public long cacheSize;
      }
      
      -------------------------
      
      list_cacheinfo_item.xml
      
      <?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"
          android:padding="5dp" >
      
          <ImageView
              android:id="@+id/iv_icon"
              android:layout_width="40dp"
              android:layout_height="40dp"
              android:layout_alignParentLeft="true"
              android:layout_alignParentTop="true"
              android:src="@drawable/ic_launcher" />
      
          <TextView
              android:id="@+id/tv_name"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignParentTop="true"
              android:layout_marginLeft="20dp"
              android:layout_toRightOf="@+id/iv_icon"
              android:text="应用名称"
              android:textColor="#000"
              android:textSize="16sp" />
      
          <TextView
              android:id="@+id/tv_cache_size"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_alignLeft="@+id/tv_name"
              android:layout_below="@id/tv_name"
              android:layout_marginTop="5dp"
              android:text="缓存大小:"
              android:textColor="#000"
              android:textSize="16sp" />
      
          <ImageView
              android:id="@+id/iv_delete"
              android:layout_width="45dp"
              android:layout_height="45dp"
              android:layout_alignParentRight="true"
              android:layout_centerVertical="true"
              android:src="@drawable/btn_black_number_delete_selector" />
      
      </RelativeLayout>
      
  • 一键清理缓存

    这是用的Android的一个BUG,就是你得程序去申请很大的内存,比如直接申请10G,但是你得内存总共才1G,这时候系统为了满足你得要求,会去全盘清理缓存,清理完了发现还是达不到你得要求,那么就返回失败!!!! 但是,我们的目的已经达成,就是要让他去清理全盘缓存
    
    /**
     * 一键清理
     * 
     * @param view
     */
    public void cleanAllCache(View view) {
        try {
            // 通过反射调用freeStorageAndNotify方法, 向系统申请内存
            Method method = mPM.getClass().getMethod(
                    "freeStorageAndNotify", long.class,
                    IPackageDataObserver.class);
            // 参数传Long最大值, 这样可以保证系统将所有app缓存清理掉
            method.invoke(mPM, Long.MAX_VALUE, new IPackageDataObserver.Stub() {
    
                @Override
                public void onRemoveCompleted(String packageName,
                        boolean succeeded) throws RemoteException {
                    System.out.println("flag==" + succeeded);
                    System.out.println("packageName=" + packageName);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    

-清理特定app缓存

查看Setting源码,分析清除缓存按钮的逻辑

实现代码:

/**
 * 删除单个文件的缓存 需要权限:<uses-permission
 * android:name="android.permission.DELETE_CACHE_FILES"/>
 * 
 * @param packageName
 */
private void deleteCache(String packageName) {
    try {
        Method method = mPM.getClass().getMethod(
                "deleteApplicationCacheFiles", String.class,
                IPackageDataObserver.class);
        method.invoke(mPM, packageName, new IPackageDataObserver.Stub() {
            @Override
            public void onRemoveCompleted(String packageName,
                    boolean succeeded) throws RemoteException {
                System.out.println("succeeded" + succeeded);
            }
        });
    } catch (Exception e) {
        e.printStackTrace();
    }
}

注意加权限: <uses-permission android:name="android.permission.DELETE_CACHE_FILES"/>

知识拓展:
加上权限后仍然报错
  • 跳转到某个系统应用界面清除缓存

    1. 看一下腾讯管家跳转到系统应用界面时的日志,并且对于Settings源代码说明意图;
    
    2. 代码实现:
    //启动到某个系统应用页面
    Intent intent = new Intent();
    intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
    intent.addCategory(Intent.CATEGORY_DEFAULT);//有无没影响
    intent.setData(Uri.parse("package:"+cacheInfo.packName));
    startActivity(intent);
    
  • 流量统计

    • 流量统计介绍, pc网络连接流量展示(已发送,已接受)
    • 连接真机,查看文件proc/uid_stat,发现该目录下有很多以uid命名的文件夹
    • 用户id是安装应用程序的时候 操作系统赋给应用程序的
    • 获取uid方式

      1. 进入AppInfoProvider, 
          String name = packInfo.applicationInfo.loadLabel(pm).toString()+ packInfo.applicationInfo.uid;
      2. 将应用名称和uid拼成一个字符串输出,真机查看主流应用(微信,QQ)的uid
      3. 例如 QQ:10083, 进入QQ(10083)目录命令:cd 10083
      4. 进入QQ10083:cd 10110
          下载:168251
          上传:23544
          tcp_rcv :代码下载的数据
          tcp_snd:代表上传的数据
      
    • 手机安装360, 验证流量准确性

    • 创建TrafficeManagerActivity
    • 流量统计的api介绍

      TrafficStats.getMobileRxBytes();// 3g/2g下载总流量
      TrafficStats.getMobileTxBytes();// 3g/2g上传总流量
      
      TrafficStats.getTotalRxBytes();// wifi+手机下载流量
      TrafficStats.getTotalTxBytes();// wifi+手机上传总流量
      
      TrafficStats.getUidRxBytes(10085);// 某个应用下载流量
      TrafficStats.getUidTxBytes(10085);// 某个应用上传流量
      
      这里需要注意的是,通过 TrafficStats 获取的数据在手机重启的时候会被清空,所以,如果要对流量进行持续的统计需要将数据保存到数据库中,在手机重启时将数据读出进行累加即可
      
    • 流量报警原理简介

      流量校准的工作原理就给运营商发短信
      
      A:开启超额提醒
      B:设置每月流量套餐300MB
      C:自动校准流量-流量短信设置
      D:演示发短信给运营商;
      
    • 联网防火墙简介

      在linux上有一款强大的防火墙软件iptable
      360就是把这款软件内置了
      如果手机有root权限,把防火墙软件装到手机的内部,并且开启起来。
      以后就可以拦截某个应用程序的联网了。
      
      如果允许某个软件上网就什么也不做。如果不允许某个软件上网,就把这个软件的所有的联网操作都定向到本地,这时就不会产生流量了。
      
    • Android下的开源防火墙项目droidwall

      登录code.google.com,搜索droidwall
      svn地址: https://droidwall.googlecode.com/svn/
      svn检出, 需要翻墙
      
      常用开源代码网站: github.com, code.google.com
      
  • 抽屉效果 SlidingDrawer

    • 基本实现

      <SlidingDrawer
          android:id="@+id/slidingDrawer1"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:content="@+id/content"
          android:handle="@+id/handle" >
      
          //指定抽屉把手
          <ImageView
              android:id="@id/handle"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:src="@drawable/lock" />
      
          //指定抽屉内容
          <LinearLayout
              android:id="@id/content"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#9e9e9e"
              android:gravity="center" >
      
              <TextView
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="我是小抽屉" />
          </LinearLayout>
      </SlidingDrawer>
      
    • 把抽屉做成从右向左拉

      android:orientation="horizontal"
      
    • 实现腾讯抽屉竖直方向显示一小半功能

      只需在抽屉上方增加一个空view
      
        <View
          android:layout_width="match_parent"
          android:layout_height="200dp" />
      
    • 水平方向显示一小半

        <LinearLayout
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:orientation="horizontal" >
      
      <View
          android:layout_width="100dp"
          android:layout_height="match_parent" />
      
      <SlidingDrawer
          android:id="@+id/slidingDrawer1"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:orientation="horizontal"
          android:content="@+id/content"
          android:handle="@+id/handle" >
      
          <ImageView
              android:id="@id/handle"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:src="@drawable/lock" />
      
          <LinearLayout
              android:id="@id/content"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:background="#9e9e9e"
              android:gravity="center" >
      
              <TextView
                  android:layout_width="wrap_content"
                  android:layout_height="wrap_content"
                  android:text="我是小抽屉" />
          </LinearLayout>
      </SlidingDrawer>
      

    • 小锁图片显示上面

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值