Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> android 卸載程序、清除數據、停止服務使用方法

android 卸載程序、清除數據、停止服務使用方法

編輯:關於Android編程

要實現卸載程序、清除數據、停止正在運行的服務這幾大模塊,現在將代碼粗略總結如下:
  主要運用到的類有
  PackageManager
  ActivityManager
  ApplicationInfo
  RunningServiceInfo
  Method
  還有兩個android.pm下的源文件用於生成樁,IPackageStatsObserver.java 和 IPackageDataObserver.java,由名字可以看出,他們是跟包的狀態和大小有關的,在網上找到這兩個文件的源碼後,把他們放在工程src目錄下的android.pm包下,自己建包。
  首先要獲得系統中已經裝了的apk,apk分為兩類第一是系統的apk,第二是第三方的apk,所以在獲取apk時可以指定一個過濾器,見如下代碼:
  java代碼

  1. // 添加過濾 ,得到全部程序,系統程序,用戶自己安裝的程序

  2.   private List queryFilterAppInfo(int filter) {
  3.   // 查詢所有已經安裝的應用程序
  4.   List listAppcations =
  5. pm.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
  6.   Collections.sort(listAppcations,new
  7. ApplicationInfo.DisplayNameComparator(pm));// 排序
  8.   List appInfos = new ArrayList(); // 保存過濾查到的AppInfo
  9.   // 根據條件來過濾
  10.   switch (filter) {
  11.   case FILTER_ALL_APP: // 所有應用程序
  12.   appInfos.clear();
  13.   for (ApplicationInfo app : listAppcations) {
  14.   if (app.packageName.equals("com.android.appmanager")) { // 過濾自己
  15.   continue;
  16.   }
  17.   appInfos.add(getAppInfo(app));
  18.   }
  19.   return appInfos;
  20.   case FILTER_SYSTEM_APP: // 系統程序
  21.   appInfos.clear();
  22.   for (ApplicationInfo app : listAppcations) {
  23.   if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
  24.   if (app.packageName.equals("com.android.appmanager""font-family:Arial,
  25. Helvetica, sans-serif;">)// wifi { // 過濾自己
  26.   continue;
  27.   }
  28.   appInfos.add(getAppInfo(app));
  29.   }
  30.   }
  31.   return appInfos;
  32.   case FILTER_THIRD_APP: // 第三方應用程序
  33.   appInfos.clear();
  34.   for (ApplicationInfo app : listAppcations) {
  35.   // 非系統程序
  36.   if ((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {
  37.   if (app.packageName.equals("com.android.appmanager"))
  38.   continue;
  39.   }
  40.   appInfos.add(getAppInfo(app));
  41.   }
  42.   // 本來是系統程序,被用戶手動更新後,該系統程序也成為第三方應用程序了
  43.   else if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0)
  44. {
  45.   if (app.packageName.equals("geeya.android.appmanage")) { // 過濾自己
  46.   continue;
  47.   }
  48.   appInfos.add(getAppInfo(app));
  49.   }
  50.   }
  51.   break;
  52.   default:
  53.   return null;
  54.   }
  55.   return appInfos;
  56.   } 復制代碼
      AppInfo是我自己定義的一個類,裡面包含了應用程序的包名、數據區大小、代碼區大小、等等一些屬性。
      好,現在我們來獲取app包的數據區大小、緩存區大小、代碼區大小,這裡要用反射的機制去獲取PackageManager類的隱藏方法getPackageSizeInfo(),這個方法的具體實現是通過回調函數來實現的,這裡要用到IPackageStatsObserver這個類生成的樁。
      java代碼

    1. // aidl文件形成的Bindler機制服務類

    2.   public class PkgSizeObserver extends IPackageStatsObserver.Stub {
    3.   /***
    4.   * 回調函數,
    5.   *
    6.   * @param pStatus
    7.   * ,返回數據封裝在PackageStats對象中
    8.   * @param succeeded
    9.   * 代表回調成功
    10.   */
    11.   @Override
    12.   public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
    13. throws RemoteException {
    14.   long cachesize; // 緩存大小
    15.   long datasize; // 數據大小
    16.   long codesize; // 應用程序大小
    17.   long totalsize; // 總大小
    18.   // System.out.println("data start init!");
    19.   synchronized (Integer.class) {
    20.   cachesize = pStats.cacheSize; // 緩存大小
    21.   datasize = pStats.dataSize; // 數據大小
    22.   codesize = pStats.codeSize; // 應用程序大小
    23.   totalsize = cachesize + datasize + codesize;
    24.   Message msg = mHandler.obtainMessage();
    25.   msg.what = MSG_SIZE_CHANGE;
    26.   Bundle bundle = new Bundle();
    27.   bundle.putLong("cachesize", cachesize);
    28.   bundle.putLong("datasize", datasize);
    29.   bundle.putLong("codesize", codesize);
    30.   bundle.putLong("totalsize", totalsize);
    31.   bundle.putString("packageName", pStats.packageName);
    32.   msg.obj = bundle;
    33.   mHandler.sendMessage(msg);
    34.   }
    35.   }
    36.   }
    37.   //獲取每個apk的大小信息,包括數據區、代碼區、緩存區
    38.   // 查詢包的大小信息
    39.   public void queryPacakgeSize(String pkgName) throws Exception {
    40.   if (pkgName != null) {
    41.   // 使用放射機制得到PackageManager類的隱藏函數getPackageSizeInfo
    42.   PackageManager pm = getPackageManager(); // 得到pm對象
    43.   try {
    44.   // 通過反射機制獲得該隱藏函數
    45.   Method getPackageSizeInfo =
    46. pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class,
    47.   IPackageStatsObserver.class);
    48.   getPackageSizeInfo.invoke(pm, pkgName, new PkgSizeObserver());
    49.   } catch (Exception ex) {
    50.   // Log.e(TAG, "NoSuchMethodException");
    51.   ex.printStackTrace();
    52.   throw ex; // 拋出異常
    53.   }
    54.   }
    55.   } 復制代碼
        或得到app的大小數據後,封裝成消息發送出去,這是最好的方法!!
        這裡也介紹一個將long型數據轉換成文件大小格式的數據。
        java代碼

      1. // 系統函數,字符串轉換 long -String (kb)

      2.   private String formateFileSize(long size) {
      3.   return Formatter.formatFileSize(MainActivity.this, size);
      4.   } 復制代碼
          好,現在我們來清除用戶數據,這裡要用到之前下載的那個文件IPackageDataObserver,跟獲取app大小一樣的,通過回調來實現。
          java代碼

        1. // 清除用戶數據的操作

        2.   class ClearUserDataObserver extends IPackageDataObserver.Stub {
        3.   public void onRemoveCompleted(final String packageName,final boolean
        4. succeeded) {
        5.   final Message msg = mHandler.obtainMessage();
        6.   if (succeeded) {
        7.   msg.what = CLEAR_USER_DATA;
        8.   } else {
        9.   msg.what = NOT_CLEAR_USER_DATA;
        10.   }
        11.   mHandler2.sendMessage(msg);
        12.   }
        13.   }
        14.   // 清除apk的數據
        15.   public void clearAppUserData(String pkgname){
        16.   // 經測試,該方法不能用反射得到,沒辦法,我只好這樣寫,只能在源碼下編譯。
        17.   pm.clearApplicationUserData(pkgname, new ClearUserDataObserver());
        18.   } 復制代碼
            好,現在到卸載程序的時候了,看代碼
            java代碼

          1. // 卸載apk

          2.   ublic void unInstallApp(String pkgname) {
          3.   Log.e("unInstallApp(String pkgname)","pkgname is"+ pkgname);
          4.   Intent intent = new Intent();
          5.   // 該動作是我在android框架層自己定義的一個動作,DELETE.HIDE,表明直接就卸載了。不經過系統原生的那一個對話。
          6.   intent.setAction("android.intent.action.DELETE.HIDE"); //
          7. 自己定義的動作,DELETE.HIDE,不需要經過系統的確認卸載界面。直接卸載!
          8.   Uri packageURI = Uri.parse("package:" + pkgname);
          9.   intent.setData(packageURI);
          10.   startActivity(intent); 復制代碼
              關於apk的管理就差不多了,現在來看看正在運行的服務的管理
              首先,獲取正在運行的服務:
              這裡我的RunningInfo是我自己定義的一個類,主要服務的一些屬性,比如包名、uid、pid等等那些
              java代碼

            1. // 得到正在運行的服務

            2.   public List getRunningService() {
            3.   List runServiceList = am.getRunningServices(30);
            4.   List Services_List = new ArrayList(); //
            5. 保存過濾查到的AppInfo
            6.   Log.e("getRunningService.size = ",
            7.   new Integer(runServiceList.size()).toString());
            8.   String pkgname = "";
            9.   ApplicationInfo appByPkgName = null;
            10.   for (RunningServiceInfo info : runServiceList) {
            11.   pkgname = info.service.getPackageName();
            12.   // System.out.println("service package is :" + pkgname +
            13.   // " pid = "+ info.pid); // 程序的ID號
            14.   // 過濾掉這些系統本身的服務。只顯示用戶安裝的服務
            15.   if (pkgname.equals("com.android.appmanager") ) { // 過濾自己
            16.   continue;
            17.   }
            18.   try {
            19.   appByPkgName = pm.getApplicationInfo(pkgname,
            20.   PackageManager.GET_UNINSTALLED_PACKAGES); // 最後一個參數一般為0
            21.   // 就好。
            22.   } catch (NameNotFoundException e) {
            23.   // Log.e("MainActivity 841 line","appByPkgName =
            24. pm.getApplicationInfo(pkgname, PackageManager.GET_UNINSTALLED_PACKAGES)
            25. Exception !");
            26.   e.printStackTrace();
            27.   }
            28.   Services_List.add(getRunningInfo(appByPkgName)); //
            29. 裡面含有相同的包的服務。這裡哦我們只要求顯示一個即可。
            30.   }
            31.   // 放入set中過濾相同包名的, 這裡我復寫了RunningInfo 的compareTo方法你 規則是
            32. pkgName相等兩個對象就算相等!
            33.   Set set = new HashSet();
            34.   for (RunningInfo x : Services_List) {
            35.   set.add(x);
            36.   }
            37.   for (RunningInfo y : set) {
            38.   Services_List.add(y);
            39.   }
            40.   return Services_List;
            41.   } 復制代碼
                好,獲取到了正在運行的服務之後,就可以隨意停止服務了,停止服務的代碼是:
                java代碼

              1. // 強行停止一個app

              2.   ublic boolean stopApp(String pkgname) {
              3.   boolean flag = false;
              4.   ActivityManager am = (ActivityManager)
              5. mContext.getSystemService(Context.ACTIVITY_SERVICE);
              6.   try {
              7.   Method forceStopPackage;
              8.   forceStopPackage = am.getClass().getDeclaredMethod("forceStopPackage",
              9. String.class); // 反射得到隱藏方法(hide)
              10.   forceStopPackage.setAccessible(true);//獲取私有成員變量的值
              11.   forceStopPackage.invoke(am, pkgname);
              12.   flag = true;
              13.   } catch (IllegalArgumentException e) {
              14.   e.printStackTrace();
              15.   flag = false;
              16.   } catch (IllegalAccessException e) {
              17.   e.printStackTrace();
              18.   flag = false;
              19.   } catch (InvocationTargetException e) {
              20.   e.printStackTrace();
              21.   flag = false;
              22.   } catch (SecurityException e) {
              23.   e.printStackTrace();
              24.   flag = false;
              25.   } catch (NoSuchMethodException e) {
              26.   e.printStackTrace();
              27.   flag = false;
              28.   }
              29.   return flag; 復制代碼
                  同樣也是用反射的機制來得到隱藏類。
                  到這裡,應用程序管理的功能就差不多了,
                  剩下就只是界面上的事情和程序的處理流程上的事情,應該還好!
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved