Android中獲取應用程序(包)的信息----PackageManager


本節內容是如何獲取Android系統中應用程序的信息,主要包括packagename、label、icon、占用大小等。具體分為兩個

 部分,計划如下:

            第一部分: 獲取應用程序的packagename、label、icon等 ;

            第二部分: 獲取應用程序的占用大小,包括:緩存大小(cachsize)、數據大小(datasize)。

       每部分都為您准備了簡單豐富的實例,您一定不會錯過。

      Android系統為我們提供了很多服務管理的類,包括ActivityManager、PowerManager(電源管理)、AudioManager(音頻管理)

等。除此之外,還提供了一個PackageManger管理類,它的主要職責是管理應用程序包。 通過它,我們就可以獲取應用程序信息。

     引入: AnroidManifest.xml文件節點說明:

 

一、相關類的介紹

  PackageItemInfo類

          說明: AndroidManifest.xml文件中所有節點的基類,提供了這些節點的基本信息:a label、icon、 meta-data。它並不

     直接使用,而是由子類繼承然后調用相應方法。

          常用字段

               public int icon           獲得該資源圖片在R文件中的值 (對應於android:icon屬性)

               public int labelRes     獲得該label在R文件中的值(對應於android:label屬性)

               public String name   獲得該節點的name值 (對應於android:name屬性)

               public String packagename   獲得該應用程序的包名 (對應於android:packagename屬性)

         常用方法

              Drawable  loadIcon(PackageManager pm)               獲得當前應用程序的圖像

              CharSequence  loadLabel(PackageManager pm)     獲得當前應用程序的label

 

   ActivityInfo類  繼承自 PackageItemInfo

          說明: 獲得應用程序中<activity/>或者 <receiver />節點的信息 。我們可以通過它來獲取我們設置的任何屬性,包括  theme 、launchMode、launchmode等

          常用方法繼承至PackageItemInfo類中的loadIcon()和loadLabel() 

   ServiceInfo 類

          說明: 同ActivityInfo類似 ,同樣繼承自 PackageItemInfo,只不過它表示的是<service>節點信息。

   ApplicationInfo類 繼承自  PackageItemInfo

         說明:獲取一個特定引用程序中<application>節點的信息。

         字段說明

      flags字段: FLAG_SYSTEM 系統應用程序

                   FLAG_EXTERNAL_STORAGE 表示該應用安裝在sdcard中

         常用方法繼承至PackageItemInfo類中的loadIcon()和loadLabel()

 

  ResolveInfo類

        說明:根據<intent>節點來獲取其上一層目錄的信息,通常是<activity>、<receiver>、<service>節點信息。

       常用字段

             public  ActivityInfo  activityInfo     獲取 ActivityInfo對象,即<activity>或<receiver >節點信息

             public ServiceInfo   serviceInfo     獲取 ServiceInfo對象,即<service>節點信息

       常用方法: 

             Drawable loadIcon(PackageManager pm)             獲得當前應用程序的圖像

             CharSequence loadLabel(PackageManager pm)  獲得當前應用程序的label

 

 PackageInfo類

       說明:手動獲取AndroidManifest.xml文件的信息 。

       常用字段

           public String    packageName                   包名

           public ActivityInfo[]     activities                   所有<activity>節點信息

           public ApplicationInfo applicationInfo       <application>節點信息,只有一個

           public ActivityInfo[]    receivers                  所有<receiver>節點信息,多個

           public ServiceInfo[]    services                  所有<service>節點信息 ,多個

 

PackageManger 類

      說明: 獲得已安裝的應用程序信息 。可以通過getPackageManager()方法獲得。

      常用方法

       public abstract PackageManager  getPackageManager()   

               功能:獲得一個PackageManger對象

       public abstrac  tDrawable    getApplicationIcon(StringpackageName)

               參數: packageName 包名

               功能:返回給定包名的圖標,否則返回null

       public abstract ApplicationInfo   getApplicationInfo(String packageName, int flags)

               參數:packagename 包名

                           flags 該ApplicationInfo是此flags標記,通常可以直接賦予常數0即可

               功能:返回該ApplicationInfo對象

          public abstract List<ApplicationInfo>  getInstalledApplications(int flags)

               參數:flag為一般為GET_UNINSTALLED_PACKAGES,那么此時會返回所有ApplicationInfo。

                  我們  可以對ApplicationInfo的flags過濾,得到我們需要的。

               功能:返回給定條件的所有PackageInfo

          public abstract List<PackageInfo>  getInstalledPackages(int flags) 

             參數如上

             功能:返回給定條件的所有PackageInfo

       public abstractResolveInfo  resolveActivity(Intent intent, int flags)

            參數:  intent 查尋條件,Activity所配置的action和category

             flags: MATCH_DEFAULT_ONLY    :Category必須帶有CATEGORY_DEFAULT的Activity,才匹配

                       GET_INTENT_FILTERS         :匹配Intent條件即可

                      GET_RESOLVED_FILTER    :匹配Intent條件即可

            功能 :返回給定條件的ResolveInfo對象(本質上是Activity) 

       public abstract  List<ResolveInfo>  queryIntentActivities(Intent intent, int flags)

            參數同上

            功能 :返回給定條件的所有ResolveInfo對象(本質上是Activity),集合對象

       public abstract ResolveInfo  resolveService(Intent intent, int flags)

           參數同上

           功能 :返回給定條件的ResolveInfo對象(本質上是Service)

       public abstract List<ResolveInfo> queryIntentServices(Intent intent, int flags)

          參數同上

          功能 :返回給定條件的所有ResolveInfo對象(本質上是Service),集合對象

二、DEMO講解

            通過前面的介紹,相信您一定很了解了,本質上來講,這些XXXInfo類不過是我們在AndroidManifest.XML文件中定義的信息,

知道到這點了,理解起來就不是很難了。

         下面我透過兩個簡答的DEMO,來學以致用。

           Demo 1: 通過queryIntentActivities()方法,查詢Android系統的所有具備ACTION_MAIN和CATEGORY_LAUNCHER

      的Intent的應用程序,點擊后,能啟動該應用,說白了就是做一個類似Home程序的簡易Launcher 。

1 、布局文件: 主要有兩個:帶listview的browse_app_list.xml文件 ;listview的項browse_app_item.xml

1 <?xml version="1.0" encoding="utf-8"?>
2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3     android:orientation="vertical" android:layout_width="fill_parent"
4     android:layout_height="fill_parent">>
5     <ListView android:id="@+id/listviewApp" android:layout_width="fill_parent"
6         android:layout_height="fill_parent" ></ListView>
7 </LinearLayout>
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3     android:layout_width="fill_parent" android:layout_height="50dip">
 4 
 5     <ImageView android:id="@+id/imgApp" android:layout_width="wrap_content"
 6         android:layout_height="fill_parent" ></ImageView>
 7     <RelativeLayout android:layout_width="fill_parent"  android:layout_marginLeft="10dip"
 8         android:layout_height="40dip">
 9         <TextView android:id="@+id/tvLabel" android:layout_width="wrap_content"
10             android:layout_height="wrap_content" android:text="AppLable : "></TextView>
11         <TextView android:id="@+id/tvAppLabel" android:layout_width="wrap_content"
12             android:layout_toRightOf="@id/tvLabel" android:layout_height="wrap_content"
13             android:layout_marginLeft="3dip" android:text="Label" android:textColor="#FFD700"></TextView>
14         <TextView android:id="@+id/tvName" android:layout_width="wrap_content"
15             android:layout_height="wrap_content" android:layout_below="@id/tvLabel" 
16             android:text="包名:"></TextView>
17         <TextView android:id="@+id/tvPkgName" android:layout_width="wrap_content"
18             android:layout_height="wrap_content" android:layout_below="@id/tvAppLabel"
19             android:layout_alignLeft="@id/tvAppLabel" android:textColor="#FFD700"></TextView>
20     </RelativeLayout>
21 </LinearLayout>

 

2 、AppInfo.java : 保存應用程序信息的Model類

 2 public class AppInfo {  3  4 private String appLabel; //應用程序標簽  5 private Drawable appIcon ; //應用程序圖像  6 private Intent intent ; //啟動應用程序的Intent ,一般是Action為Main和Category為Lancher的Activity  7 private String pkgName ; //應用程序所對應的包名  8  9 public AppInfo(){} 10 11 public String getAppLabel() { 12 return appLabel; 13  } 14 public void setAppLabel(String appName) { 15 this.appLabel = appName; 16  } 17 public Drawable getAppIcon() { 18 return appIcon; 19  } 20 public void setAppIcon(Drawable appIcon) { 21 this.appIcon = appIcon; 22  } 23 public Intent getIntent() { 24 return intent; 25  } 26 public void setIntent(Intent intent) { 27 this.intent = intent; 28  } 29 public String getPkgName(){ 30 return pkgName ; 31  } 32 public void setPkgName(String pkgName){ 33 this.pkgName=pkgName ; 34  } 35 }

 

3、 BrowseApplicationInfoAdapter.java : 自定義適配器類,為ListView提供視圖

 1 //自定義適配器類,提供給listView的自定義view  2 public class BrowseApplicationInfoAdapter extends BaseAdapter {  3  4 private List<AppInfo> mlistAppInfo = null;  6 LayoutInflater infater = null;  7  8 public BrowseApplicationInfoAdapter(Context context, List<AppInfo> apps) {  9 infater = (LayoutInflater) context.getSystemService(
Context.LAYOUT_INFLATER_SERVICE);
10 mlistAppInfo = apps ; 11 } 12 @Override 13 public int getCount() { 14 // TODO Auto-generated method stub 15 System.out.println("size" + mlistAppInfo.size()); 16 return mlistAppInfo.size(); 17 } 18 @Override 19 public Object getItem(int position) { 20 // TODO Auto-generated method stub 21 return mlistAppInfo.get(position); 22 } 23 @Override 24 public long getItemId(int position) { 25 // TODO Auto-generated method stub 26 return 0; 27 } 28 @Override 29 public View getView(int position, View convertview, ViewGroup arg2) { 30 System.out.println("getView at " + position); 31 View view = null; 32 ViewHolder holder = null; 33 if (convertview == null || convertview.getTag() == null) { 34 view = infater.inflate(R.layout.browse_app_item, null); 35 holder = new ViewHolder(view); 36 view.setTag(holder); 37 } 38 else{ 39 view = convertview ; 40 holder = (ViewHolder) convertview.getTag() ; 41 } 42 AppInfo appInfo = (AppInfo) getItem(position); 43 holder.appIcon.setImageDrawable(appInfo.getAppIcon()); 44 holder.tvAppLabel.setText(appInfo.getAppLabel()); 45 holder.tvPkgName.setText(appInfo.getPkgName()); 46 return view; 47 } 48 49 class ViewHolder { 50 ImageView appIcon; 51 TextView tvAppLabel; 52 TextView tvPkgName; 53 54 public ViewHolder(View view) { 55 this.appIcon = (ImageView) view.findViewById(R.id.imgApp); 56 this.tvAppLabel = (TextView) view.findViewById(R.id.tvAppLabel); 57 this.tvPkgName = (TextView) view.findViewById(R.id.tvPkgName); 58 } 59 } 60 }

4 、MainActivity.java 主工程邏輯 , 請仔細體會queryIntentActivities()方法,並且注意到排序,它很重要。

 1 public class MainActivity extends Activity implements OnItemClickListener {  3 private ListView listview = null;  5 private List<AppInfo> mlistAppInfo = null;  6  7  @Override  8 public void onCreate(Bundle savedInstanceState) {  9 super.onCreate(savedInstanceState); 10  setContentView(R.layout.browse_app_list); 11 12 listview = (ListView) findViewById(R.id.listviewApp); 13 mlistAppInfo = new ArrayList<AppInfo>(); 14 queryAppInfo(); // 查詢所有應用程序信息 15 BrowseApplicationInfoAdapter browseAppAdapter 
= new BrowseApplicationInfoAdapter(this, mlistAppInfo); 17 listview.setAdapter(browseAppAdapter); 18 listview.setOnItemClickListener(this); 19 } 20 // 點擊跳轉至該應用程序 21 public void onItemClick(AdapterView<?> arg0, View view, int position, 22 long arg3) { 23 // TODO Auto-generated method stub 24 Intent intent = mlistAppInfo.get(position).getIntent(); 25 startActivity(intent); 26 } 27 // 獲得所有啟動Activity的信息,類似於Launch界面 28 public void queryAppInfo() { 29 PackageManager pm = this.getPackageManager(); // 獲得PackageManager對象 30 Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 31 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 32 // 通過查詢,獲得所有ResolveInfo對象. 33 List<ResolveInfo> resolveInfos = pm 34 .queryIntentActivities(mainIntent, PackageManager.MATCH_DEFAULT_ONLY); 35 // 調用系統排序 , 根據name排序 36 // 該排序很重要,否則只能顯示系統應用,而不能列出第三方應用程序 37 Collections.sort(resolveInfos,new ResolveInfo.DisplayNameComparator(pm)); 38 if (mlistAppInfo != null) { 39 mlistAppInfo.clear(); 40 for (ResolveInfo reInfo : resolveInfos) { 41 String activityName = reInfo.activityInfo.name; // 獲得該應用程序的啟動Activity的name 42 String pkgName = reInfo.activityInfo.packageName; // 獲得應用程序的包名 43 String appLabel = (String) reInfo.loadLabel(pm); // 獲得應用程序的Label 44 Drawable icon = reInfo.loadIcon(pm); // 獲得應用程序圖標 45 // 為應用程序的啟動Activity 准備Intent 46 Intent launchIntent = new Intent(); 47 launchIntent.setComponent(new ComponentName(pkgName, 48 activityName)); 49 // 創建一個AppInfo對象,並賦值 50 AppInfo appInfo = new AppInfo(); 51 appInfo.setAppLabel(appLabel); 52 appInfo.setPkgName(pkgName); 53 appInfo.setAppIcon(icon); 54 appInfo.setIntent(launchIntent); 55 mlistAppInfo.add(appInfo); // 添加至列表中 56 System.out.println(appLabel + " activityName---" + activityName 57 + " pkgName---" + pkgName); 58 } 59 } 60 } 61 }

 

           Demo 2 :通過getInstalledApplications()方法獲取應用,繼而通過ApplicationInfo.flags來挑選查找出我們需要的第三方應用,系統應用,安裝在sdcard的應用。

import java.util.ArrayList;  4 import java.util.Collections;  5 import java.util.List;  7 import com.qiner.appinfo.R;  9 import android.app.Activity;  10 import android.app.Application;  11 import android.content.pm.ApplicationInfo;  12 import android.content.pm.PackageManager;  13 import android.os.Bundle;  14 import android.view.View;  15 import android.view.View.OnClickListener;  16 import android.widget.Button;  17 import android.widget.ListView;  18  19 public class MainActivity extends Activity {  20  21 public static final int FILTER_ALL_APP = 0; // 所有應用程序  22 public static final int FILTER_SYSTEM_APP = 1; // 系統程序  23 public static final int FILTER_THIRD_APP = 2; // 第三方應用程序  24 public static final int FILTER_SDCARD_APP = 3; // 安裝在SDCard的應用程序  25  26 private ListView listview = null;  27  28 private PackageManager pm;  29 private int filter = FILTER_ALL_APP;  30 private List<AppInfo> mlistAppInfo ;  31 private BrowseApplicationInfoAdapter browseAppAdapter = null ;  32 /** Called when the activity is first created. */  33  @Override  34 public void onCreate(Bundle savedInstanceState) {  35 super.onCreate(savedInstanceState);  36  setContentView(R.layout.browse_app_list);  37 listview = (ListView) findViewById(R.id.listviewApp);  38 if(getIntent()!=null){  39 filter = getIntent().getIntExtra("filter", 0) ;  40  }  41 mlistAppInfo = queryFilterAppInfo(filter); // 查詢所有應用程序信息  42 // 構建適配器,並且注冊到listView  43 browseAppAdapter = new BrowseApplicationInfoAdapter(this, mlistAppInfo);  44  listview.setAdapter(browseAppAdapter);  45  }  46 // 根據查詢條件,查詢特定的ApplicationInfo  47 private List<AppInfo> queryFilterAppInfo(int filter) {  48 pm = this.getPackageManager();  49 // 查詢所有已經安裝的應用程序  50 List<ApplicationInfo> listAppcations = pm  51  .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);  52  Collections.sort(listAppcations,  53 new ApplicationInfo.DisplayNameComparator(pm));// 排序  54 List<AppInfo> appInfos = new ArrayList<AppInfo>(); // 保存過濾查到的AppInfo  55 // 根據條件來過濾  56 switch (filter) {  57 case FILTER_ALL_APP: // 所有應用程序  58  appInfos.clear();  59 for (ApplicationInfo app : listAppcations) {  60  appInfos.add(getAppInfo(app));  61  }  62 return appInfos;  63 case FILTER_SYSTEM_APP: // 系統程序  64  appInfos.clear();  65 for (ApplicationInfo app : listAppcations) {  66 if ((app.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {  67  appInfos.add(getAppInfo(app));  68  }  69  }  70 return appInfos;  71 case FILTER_THIRD_APP: // 第三方應用程序  72  appInfos.clear();  73 for (ApplicationInfo app : listAppcations) {  74 //非系統程序  75 if ((app.flags & ApplicationInfo.FLAG_SYSTEM) <= 0) {  76  appInfos.add(getAppInfo(app));  77  }  78 //本來是系統程序,被用戶手動更新后,該系統程序也成為第三方應用程序了  79 else if ((app.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0){  80  appInfos.add(getAppInfo(app));  81  }  82  }  83 break;  84 case FILTER_SDCARD_APP: // 安裝在SDCard的應用程序  85  appInfos.clear();  86 for (ApplicationInfo app : listAppcations) {  87 if ((app.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {  88  appInfos.add(getAppInfo(app));  89  }  90  }  91 return appInfos;  92 default:  93 return null;  94  }  95 return appInfos;  96  }  97 // 構造一個AppInfo對象 ,並賦值  98 private AppInfo getAppInfo(ApplicationInfo app) {  99 AppInfo appInfo = new AppInfo(); 100  appInfo.setAppLabel((String) app.loadLabel(pm)); 101  appInfo.setAppIcon(app.loadIcon(pm)); 102  appInfo.setPkgName(app.packageName); 103 return appInfo; 104  } 105 }

 

         以下部分的內容是如何獲取安裝包得大小,包括緩存大小(cachesize)、數據大小(datasize)、應用程序大小(codesize)。

      關於安裝包得大小信息封裝在PackageStats類中,該類很簡單,只有幾個字段:

                PackageStats類

                 常用字段:

                             public long cachesize           緩存大小

                             public long codesize             應用程序大小

                             public long datasize              數據大小

                             public String packageName  包名

 

         PS:應用程序的總大小 = cachesize  + codesize  + datasize

 

        也就是說只要獲得了安裝包所對應的PackageStats對象,就可以獲得信息了。但是在AndroidSDK中並沒有顯示提供方法來

獲得該對象,是不是很苦惱呢?但是,我們可以通過放射機制來調用系統中隱藏的函數(@hide)來獲得每個安裝包得信息。

 

具體方法如下:

        第一步、  通過放射機制調用getPackageSizeInfo()  方法原型為:

 

1 /*@param packageName 應用程序包名 2  *@param observer 當查詢包得信息大小操作完成后,將回調給IPackageStatsObserver類中的onGetStatsCompleted()方法, 3  * ,並且我們需要的PackageStats對象也封裝在其參數里. 4  * @hide //隱藏函數的標記 5 */ 6 public abstract void getPackageSizeInfo(
String packageName,IPackageStatsObserver observer);{
7 // 8 }

 

內部調用流程如下,這個知識點較為復雜,知道即可,

   getPackageSizeInfo方法內部調用getPackageSizeInfoLI(packageName, pStats)方法來完成包狀態獲取。

getPackageSizeInfoLI方法內部調用Installer.getSizeInfo(String pkgName, String apkPath,String fwdLockApkPath,   PackageStats

pStats),繼而將包狀態信息返回給參數pStats。getSizeInfo這個方法內部是以本機Socket方式連接到Server,

   然后向server發送一個文本字符串命令,格式:getsize apkPath fwdLockApkPath 給server。Server將結果返回,並解析到pStats中。掌握這個調用知識鏈即可。

 

第二步、  由於需要獲得系統級的服務或類,我們必須加入Android系統形成的AIDL文件,共兩個:

     IPackageStatsObserver.aidl 和 PackageStats.aidl文件。並將其放置在android.pm.content包路徑下。

     IPackageStatsObserver.aidl 文件

 1 package android.content.pm;  2  3 import android.content.pm.PackageStats;  4 /**  5  * API for package data change related callbacks from the Package Manager.  6  * Some usage scenarios include deletion of cache directory, generate  7  * statistics related to code, data, cache usage(TODO)  8  * {@hide}  9 */ 10 oneway interface IPackageStatsObserver { 11 12 void onGetStatsCompleted(in PackageStats pStats, boolean succeeded); 13 }

PackageStats.aidl文件

 

 

1 package android.content.pm; 2 3 parcelable PackageStats;

 

 

第三步、  創建一個類繼承至IPackageStatsObserver.Stub (樁,)它本質上實現了Binder機制。當我們把該類的一個實例通過getPackageSizeInfo()調用時,並該函數繼而啟動了啟動中間流程去獲取相關包得信息大小,當掃描完成后,最后將查詢信息回調至該類的onGetStatsCompleted(in PackageStats pStats, boolean succeeded)方法,信息大小封裝在此實例上。例如

 

 

 1 //aidl文件形成的Bindler機制服務類  2 public class PkgSizeObserver extends IPackageStatsObserver.Stub{  3 /*** 回調函數,  4  * @param pStatus ,返回數據封裝在PackageStats對象中  5  * @param succeeded 代表回調成功  6 */  7  @Override  8 public void onGetStatsCompleted(PackageStats pStats, boolean succeede d)throws RemoteException { 10 // TODO Auto-generated method stub 11 cachesize = pStats.cacheSize ; //緩存大小 12 datasize = pStats.codeSize ; //數據大小  13 codesize = pStats.codeSize ; //應用程序大小 14  } 15 }

 

 

第四步、  最后我們可以獲取 pStats的屬性,獲得它們的屬性值,通過調用系統函數Formatter.formateFileSize(long size)轉換

為對應的以kb/mb為計量單位的字符串。 

     很重要的一點:為了能夠通過反射獲取應用程序大小,我們必須加入以下權限,否則,會出現警告並且得不到實際值。

 

 

 <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>

 

 流程圖如下:

 

Demo說明

      在第一部分應用得基礎上,我們添加了一個新功能,點擊任何一個應用后后,彈出顯示該應用的包信息大小的對話框。

        截圖如下:

1、dialg_app_size.xml 文件

 

 1 <?xml version="1.0" encoding="utf-8"?>  2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  3  android:orientation="vertical" android:layout_width="wrap_content"  4  android:layout_height="wrap_content">  5 <LinearLayout android:layout_width="wrap_content"  6  android:layout_height="wrap_content" android:orientation="horizontal">  7 <TextView android:layout_width="100dip"  8  android:layout_height="wrap_content" android:text="緩存大小:"></TextView>  9 <TextView android:layout_width="100dip" android:id="@+id/tvcachesize" 10  android:layout_height="wrap_content"></TextView> 11 </LinearLayout> 12 <LinearLayout android:layout_width="wrap_content" 13  android:layout_height="wrap_content" android:orientation="horizontal"> 14 <TextView android:layout_width="100dip" 15  android:layout_height="wrap_content" android:text="數據大小:"></TextView> 16 <TextView android:layout_width="100dip" android:id="@+id/tvdatasize" 17  android:layout_height="wrap_content"></TextView> 18 </LinearLayout> 19 <LinearLayout android:layout_width="wrap_content" 20  android:layout_height="wrap_content" android:orientation="horizontal"> 21 <TextView android:layout_width="100dip" 22  android:layout_height="wrap_content" android:text="應用程序大小:"></TextView> 23 <TextView android:layout_width="100dip" android:id="@+id/tvcodesize" 24  android:layout_height="wrap_content"></TextView> 25 </LinearLayout> 26 <LinearLayout android:layout_width="wrap_content" 27  android:layout_height="wrap_content" android:orientation="horizontal"> 28 <TextView android:layout_width="100dip" 29  android:layout_height="wrap_content" android:text="總大小:"></TextView> 30 <TextView android:layout_width="100dip" android:id="@+id/tvtotalsize" 31  android:layout_height="wrap_content"></TextView> 32 </LinearLayout> 33 </LinearLayout>

 

  2、另外的資源文件或自定義適配器復用了第一部分,請知悉。

  3、添加AIDL文件,如上。

  4、主文件MainActivity.java如下:  1 import java.lang.reflect.Method;

 2 import java.util.ArrayList;  3 import java.util.Collections;  4 import java.util.List;  5 import com.qin.appsize.AppInfo;  6 import android.app.Activity;  7 import android.app.AlertDialog;  8 import android.content.ComponentName;  9 import android.content.Context;  10 import android.content.DialogInterface;  11 import android.content.Intent;  12 import android.content.pm.IPackageStatsObserver;  13 import android.content.pm.PackageManager;  14 import android.content.pm.PackageStats;  15 import android.content.pm.ResolveInfo;  16 import android.graphics.drawable.Drawable;  17 import android.os.Bundle;  18 import android.os.RemoteException;  19 import android.text.format.Formatter;  20 import android.util.Log;  21 import android.view.LayoutInflater;  22 import android.view.View;  23 import android.widget.AdapterView;  24 import android.widget.ListView;  25 import android.widget.TextView;  26 import android.widget.AdapterView.OnItemClickListener;  27  28 public class MainActivity extends Activity implements OnItemClickListener{  29 private static String TAG = "APP_SIZE";  30  31 private ListView listview = null;  32 private List<AppInfo> mlistAppInfo = null;  33 LayoutInflater infater = null ;  34 //全局變量,保存當前查詢包得信息  35 private long cachesize ; //緩存大小  36 private long datasize ; //數據大小   37 private long codesize ; //應用程序大小  38 private long totalsize ; //總大小  39  @Override  40 public void onCreate(Bundle savedInstanceState) {  41 super.onCreate(savedInstanceState);  42  setContentView(R.layout.browse_app_list);  43 listview = (ListView) findViewById(R.id.listviewApp);  44 mlistAppInfo = new ArrayList<AppInfo>();  45 queryAppInfo(); // 查詢所有應用程序信息  46 BrowseApplicationInfoAdapter browseAppAdapter = new BrowseApplicationInfoAdapter(  47 this, mlistAppInfo);  48  listview.setAdapter(browseAppAdapter);  49 listview.setOnItemClickListener(this);  50  }  51 // 點擊彈出對話框,顯示該包得大小  52 public void onItemClick(AdapterView<?> arg0, View view, int position,long arg3) {  53 //更新顯示當前包得大小信息  54 try {  55  queryPacakgeSize(mlistAppInfo.get(position).getPkgName());  56 } catch (Exception e) {  57  e.printStackTrace();  58  }  59  60 infater = (LayoutInflater) MainActivity.this.getSystemService(  61  Context.LAYOUT_INFLATER_SERVICE);  62 View dialog = infater.inflate(R.layout.dialog_app_size, null) ;  63 //緩存大小  64 TextView tvcachesize =(TextView) dialog.findViewById(R.id.tvcachesize) ;  65 //數據大小  66 TextView tvdatasize = (TextView) dialog.findViewById(R.id.tvdatasize) ;  67 // 應用程序大小  68 TextView tvcodesize = (TextView) dialog.findViewById(R.id.tvcodesize) ;  69 //總大小  70 TextView tvtotalsize = (TextView) dialog.findViewById(R.id.tvtotalsize) ;  71 //類型轉換並賦值  72  tvcachesize.setText(formateFileSize(cachesize));  73  tvdatasize.setText(formateFileSize(datasize)) ;  74  tvcodesize.setText(formateFileSize(codesize)) ;  75  tvtotalsize.setText(formateFileSize(totalsize)) ;  76 //顯示自定義對話框  77 AlertDialog.Builder builder =new AlertDialog.Builder(
MainActivity.this) ; 78 builder.setView(dialog) ; 79 builder.setTitle(mlistAppInfo.get(position).getAppLabel()
+"的大小信息為:") ; 80 builder.setPositiveButton("確定",
new DialogInterface.OnClickListener() { 82 @Override 83 public void onClick(DialogInterface dialog, int which) { 84 // TODO Auto-generated method stub 85 dialog.cancel() ; // 取消顯示對話框 86 } 88 }); 89 builder.create().show() ; 90 } 91 public void queryPacakgeSize(String pkgName) throws Exception{ 92 if ( pkgName != null){ 93 //使用放射機制得到PackageManager類的隱藏函數getPackageSizeInfo 94 PackageManager pm = getPackageManager(); //得到pm對象 95 try { 96 //通過反射機制獲得該隱藏函數 97 Method getPackageSizeInfo = pm.getClass()
.getDeclaredMethod(
"getPackageSizeInfo",
String.class,IPackageStatsObserver.class); 99 //調用該函數,並且給其分配參數 ,待調用流程完成后會回調PkgSizeObserver類的函數 100 getPackageSizeInfo.invoke(pm, pkgName,new PkgSizeObserver()); 101 } 102 catch(Exception ex){ 103 Log.e(TAG, "NoSuchMethodException") ; 104 ex.printStackTrace() ; 105 throw ex ; // 拋出異常 106 } 107 } 108 } 109 110 //aidl文件形成的Bindler機制服務類 111 public class PkgSizeObserver extends IPackageStatsObserver.Stub{ 112 /*** 回調函數, 113 * @param pStatus ,返回數據封裝在PackageStats對象中 114 * @param succeeded 代表回調成功 115 */ 116 @Override 117 public void onGetStatsCompleted(PackageStats pStats, boolean succeeded) 118 throws RemoteException { 119 // TODO Auto-generated method stub 120 cachesize = pStats.cacheSize ; //緩存大小 121 datasize = pStats.dataSize ; //數據大小 122 codesize = pStats.codeSize ; //應用程序大小 123 totalsize = cachesize + datasize + codesize ; 124 Log.i(TAG, "cachesize--->"+cachesize+" datasize---->"+datasize+ " codeSize---->"+codesize) ; 125 } 126 } 127 //系統函數,字符串轉換 long -String (kb) 128 private String formateFileSize(long size){ 129 return Formatter.formatFileSize(MainActivity.this, size); 130 } 131 // 獲得所有啟動Activity的信息,類似於Launch界面 132 public void queryAppInfo() { 133 // 獲得PackageManager對象 134 PackageManager pm = this.getPackageManager(); 135 Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); 136 mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); 137 // 通過查詢,獲得所有ResolveInfo對象. 138 List<ResolveInfo> resolveInfos = pm.queryIntentActivities(mainIntent, 0); 139 // 調用系統排序 , 根據name排序 140 // 該排序很重要,否則只能顯示系統應用,而不能列出第三方應用程序 141 Collections.sort(resolveInfos,new ResolveInfo.DisplayNameComparator(pm)); 142 if (mlistAppInfo != null) { 143 mlistAppInfo.clear(); 144 for (ResolveInfo reInfo : resolveInfos) { 145 // 獲得該應用程序的啟動Activity的name 146 String activityName = reInfo.activityInfo.name; 147 // 獲得應用程序的包名 148 String pkgName = reInfo.activityInfo.packageName; 149 // 獲得應用程序的Label 150 String appLabel = (String) reInfo.loadLabel(pm); 151 // 獲得應用程序圖標 152 Drawable icon = reInfo.loadIcon(pm); 153 // 為應用程序的啟動Activity 准備Intent 154 Intent launchIntent = new Intent(); 155 launchIntent.setComponent(new ComponentName(pkgName,activityName)); 156 // 創建一個AppInfo對象,並賦值 157 AppInfo appInfo = new AppInfo(); 158 appInfo.setAppLabel(appLabel); 159 appInfo.setPkgName(pkgName); 160 appInfo.setAppIcon(icon); 161 appInfo.setIntent(launchIntent); 162 // 添加至列表中 163 mlistAppInfo.add(appInfo); 164 } 165 } 166 } 167 }

 

 

 

DEMO下載地址:http://download.csdn.net/detail/androidsj/7955821

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM