Android中获取应用程序(包)的信息-----PackageManager的使用

  Android系统为我们提供了很多服务管理的类,包括ActivityManager、PowerManager(电源管理)、AudioManager(音频管理)

等。除此之外,还提供了一个PackageManger管理类,它的主要职责是管理应用程序包。 通过它,我们就可以获取应用程序信息。

 

     引入: AnroidManifest.xml文件节点说明:

     Android中获取应用程序(包)的信息-----PackageManager的使用_第1张图片

一、相关类的介绍

 

    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对象,即<activity>节点信息

       常用方法 

             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<ResolveInfoqueryIntentServices(Intent intent, int flags)

          参数同上

          功能 :返回给定条件的所有ResolveInfo对象(本质上是Service),集合对象

 

二、DEMO讲解

 

            通过前面的介绍,相信您一定很了解了,本质上来讲,这些XXXInfo类不过是我们在AndroidManifest.XML文件中定义的信息,

知道到这点了,理解起来就不是很难了。

         下面我透过两个简答的DEMO,来学以致用。

           Demo 1: 通过queryIntentActivities()方法,查询Android系统的所有具备ACTION_MAIN和CATEGORY_LAUNCHER

      的Intent的应用程序,点击后,能启动该应用,说白了就是做一个类似Home程序的简易Launcher 。

           Demo 2 :通过getInstalledApplications()方法获取应用,然后对其过滤,查找出我们需要的第三方应用,系统应用,安装在sdcard的应用。

 

      Demo1  :

         图:

               Android中获取应用程序(包)的信息-----PackageManager的使用_第2张图片

  1 、布局文件: 主要有两个:带listview的browse_app_list.xml文件 ;listview的项browse_app_item.xml

browse_app_list.xml

view plain print ?
  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>  


browse_app_item.xmlbrowse_app_item.xml

view plain print ?
  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类

view plain print ?
  1. /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提供视图

view plain print ?
  1. //自定义适配器类,提供给listView的自定义view  
  2. public class BrowseApplicationInfoAdapter extends BaseAdapter {  
  3.       
  4.     private List<AppInfo> mlistAppInfo = null;  
  5.       
  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()方法,并且注意到排序,它很重要。

view plain print ?
  1. <span style="font-size:13px;">public class MainActivity extends Activity implements OnItemClickListener {  
  2.   
  3.     private ListView listview = null;  
  4.   
  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(  
  16.                 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. }</span>  


 好了,第一个Demo完成 。。 

 

 Demo 2:

        demo2在布局、适配器方面和Demo1一样。只是利用了getInstalledApplications()方法,继而通过ApplicationInfo.flags来挑选

  我们希望的ApplicationInfo对象。

       图:

              Android中获取应用程序(包)的信息-----PackageManager的使用_第3张图片         Android中获取应用程序(包)的信息-----PackageManager的使用_第4张图片

 

 过滤应用程序如下:

view plain print ?
  1. package com.qiner.appinfo;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.Collections;  
  5. import java.util.List;  
  6.   
  7. import com.qiner.appinfo.R;  
  8.   
  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. }  



    你可以在此基础上,构建更多丰富的应用。比说说Settings模块中的卸载安装应用程序等。 


 本部分的内容是如何获取安装包得大小,包括缓存大小(cachesize)、数据大小(datasize)、应用程序大小(codesize)。

本部分的知识点涉及到AIDL、Java反射机制。理解起来也不是很难。

   

      关于安装包得大小信息封装在PackageStats类中,该类很简单,只有几个字段:

                PackageStats类:

                 常用字段:

                             public long cachesize           缓存大小

                             public long codesize             应用程序大小

                             public long datasize              数据大小

                             public String packageName  包名

 

         PS:应用程序的总大小 = cachesize  + codesize  + datasize

 

        也就是说只要获得了安装包所对应的PackageStats对象,就可以获得信息了。但是在AndroidSDK中并没有显示提供方法来

获得该对象,是不是很苦恼呢?但是,我们可以通过放射机制来调用系统中隐藏的函数(@hide)来获得每个安装包得信息。

具体方法如下:

 

        第一步、  通过放射机制调用getPackageSizeInfo()  方法原型为:              

view plain copy to clipboard print ?
  1. /*@param packageName 应用程序包名 
  2.      *@param observer    当查询包得信息大小操作完成后,将回调给IPackageStatsObserver类中的onGetStatsCompleted()方法, 
  3.      *      ,并且我们需要的PackageStats对象也封装在其参数里. 
  4.      * @hide //隐藏函数的标记 
  5.      */  
  6.        public abstract void getPackageSizeInfo(String packageName,IPackageStatsObserver observer);{  
  7.           //   
  8.        }  

/*@param packageName 应用程序包名
     *@param observer    当查询包得信息大小操作完成后,将回调给IPackageStatsObserver类中的onGetStatsCompleted()方法,
     *      ,并且我们需要的PackageStats对象也封装在其参数里.
     * @hide //隐藏函数的标记
     */
       public abstract void getPackageSizeInfo(String packageName,IPackageStatsObserver observer);{
     	  //
       }

        内部调用流程如下,这个知识点较为复杂,知道即可,

         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 文件

 

view plain copy to clipboard print ?
  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. }  

package android.content.pm;

import android.content.pm.PackageStats;
/**
 * API for package data change related callbacks from the Package Manager.
 * Some usage scenarios include deletion of cache directory, generate
 * statistics related to code, data, cache usage(TODO)
 * {@hide}
 */
oneway interface IPackageStatsObserver {
    
    void onGetStatsCompleted(in PackageStats pStats, boolean succeeded);
}

 

PackageStats.aidl文件

view plain copy to clipboard print ?
  1. package android.content.pm;  
  2.   
  3. parcelable PackageStats;  

package android.content.pm;

parcelable PackageStats;

 

       第三步、  创建一个类继承至IPackageStatsObserver.Stub (桩,)它本质上实现了Binder机制。当我们把该类的一个实例通过getPackageSizeInfo()调用时,并该函数继而启动了启动中间流程去获取相关包得信息大小,当扫描完成后,最后将查询信息回调至该类的onGetStatsCompleted(in PackageStats pStats, boolean succeeded)方法,信息大小封装在此实例上。例如:

view plain copy to clipboard print ?
  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 succeeded)  
  9.         throws RemoteException {  
  10.    // TODO Auto-generated method stub   
  11.    cachesize = pStats.cacheSize  ; //缓存大小   
  12.           datasize = pStats.codeSize  ;  //数据大小    
  13.           codesize =    pStats.codeSize  ;  //应用程序大小   
  14.      }  
  15.   }  

//aidl文件形成的Bindler机制服务类
    public class PkgSizeObserver extends IPackageStatsObserver.Stub{
        /*** 回调函数,
         * @param pStatus ,返回数据封装在PackageStats对象中
         * @param succeeded  代表回调成功
         */ 
	@Override
	public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
			throws RemoteException {
	   // TODO Auto-generated method stub
	   cachesize = pStats.cacheSize  ; //缓存大小
           datasize = pStats.codeSize  ;  //数据大小 
           codesize =	pStats.codeSize  ;  //应用程序大小
      }
   }

       

       第四步、  最后我们可以获取 pStats的属性,获得它们的属性值,通过调用系统函数Formatter.formateFileSize(long size)转换

对应的以kb/mb为计量单位的字符串。

 

     很重要的一点:为了能够通过反射获取应用程序大小,我们必须加入以下权限,否则,会出现警告并且得不到实际值。

       

view plain copy to clipboard print ?
  1. <uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>  

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


 

     流程图如下:

            Android中获取应用程序(包)的信息-----PackageManager的使用_第5张图片

 

Demo说明

              在第一部分应用得基础上,我们添加了一个新功能,点击任何一个应用后后,弹出显示该应用的包信息大小的对话框。

        截图如下:

                 工程图:                                                                                  程序效果图:

               Android中获取应用程序(包)的信息-----PackageManager的使用_第6张图片           Android中获取应用程序(包)的信息-----PackageManager的使用_第7张图片

 

1、dialg_app_size.xml 文件

view plain copy to clipboard print ?
  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>  

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="wrap_content"
	android:layout_height="wrap_content">
	<LinearLayout android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:orientation="horizontal">
		<TextView android:layout_width="100dip"
			android:layout_height="wrap_content" android:text="缓存大小:"></TextView>
		<TextView android:layout_width="100dip" android:id="@+id/tvcachesize"
			android:layout_height="wrap_content"></TextView>
	</LinearLayout>
	<LinearLayout android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:orientation="horizontal">
		<TextView android:layout_width="100dip"
			android:layout_height="wrap_content" android:text="数据大小:"></TextView>
		<TextView android:layout_width="100dip" android:id="@+id/tvdatasize"
			android:layout_height="wrap_content"></TextView>
	</LinearLayout>
	<LinearLayout android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:orientation="horizontal">
		<TextView android:layout_width="100dip"
			android:layout_height="wrap_content" android:text="应用程序大小:"></TextView>
		<TextView android:layout_width="100dip" android:id="@+id/tvcodesize"
			android:layout_height="wrap_content"></TextView>
	</LinearLayout>
	<LinearLayout android:layout_width="wrap_content"
		android:layout_height="wrap_content" android:orientation="horizontal">
		<TextView android:layout_width="100dip"
			android:layout_height="wrap_content" android:text="总大小:"></TextView>
		<TextView android:layout_width="100dip" android:id="@+id/tvtotalsize"
			android:layout_height="wrap_content"></TextView>
	</LinearLayout>
</LinearLayout>

 

  2、另外的资源文件或自定义适配器复用了第一部分,请知悉。

  3、添加AIDL文件,如上。

  4、主文件MainActivity.java如下:

 

view plain copy to clipboard print ?
  1. package com.qin.appsize;  
  2.   
  3.   
  4. import java.lang.reflect.Method;  
  5. import java.util.ArrayList;  
  6. import java.util.Collections;  
  7. import java.util.List;  
  8.   
  9. import com.qin.appsize.AppInfo;  
  10.   
  11. import android.app.Activity;  
  12. import android.app.AlertDialog;  
  13. import android.content.ComponentName;  
  14. import android.content.Context;  
  15. import android.content.DialogInterface;  
  16. import android.content.Intent;  
  17. import android.content.pm.IPackageStatsObserver;  
  18. import android.content.pm.PackageManager;  
  19. import android.content.pm.PackageStats;  
  20. import android.content.pm.ResolveInfo;  
  21. import android.graphics.drawable.Drawable;  
  22. import android.os.Bundle;  
  23. import android.os.RemoteException;  
  24. import android.text.format.Formatter;  
  25. import android.util.Log;  
  26. import android.view.LayoutInflater;  
  27. import android.view.View;  
  28. import android.widget.AdapterView;  
  29. import android.widget.ListView;  
  30. import android.widget.TextView;  
  31. import android.widget.AdapterView.OnItemClickListener;  
  32.   
  33. public class MainActivity extends Activity implements OnItemClickListener{  
  34.     private static String TAG = "APP_SIZE";  
  35.   
  36.     private ListView listview = null;  
  37.     private List<AppInfo> mlistAppInfo = null;  
  38.     LayoutInflater infater = null ;   
  39.     //全局变量,保存当前查询包得信息   
  40.     private long cachesize ; //缓存大小   
  41.     private long datasize  ;  //数据大小    
  42.     private long codesize  ;  //应用程序大小   
  43.     private long totalsize ; //总大小   
  44.     @Override  
  45.     public void onCreate(Bundle savedInstanceState) {  
  46.         super.onCreate(savedInstanceState);  
  47.         setContentView(R.layout.browse_app_list);  
  48.         listview = (ListView) findViewById(R.id.listviewApp);  
  49.         mlistAppInfo = new ArrayList<AppInfo>();  
  50.         queryAppInfo(); // 查询所有应用程序信息   
  51.         BrowseApplicationInfoAdapter browseAppAdapter = new BrowseApplicationInfoAdapter(  
  52.                 this, mlistAppInfo);  
  53.         listview.setAdapter(browseAppAdapter);  
  54.         listview.setOnItemClickListener(this);  
  55.     }  
  56.      // 点击弹出对话框,显示该包得大小   
  57.     public void onItemClick(AdapterView<?> arg0, View view, int position,long arg3) {  
  58.         //更新显示当前包得大小信息   
  59.         queryPacakgeSize(mlistAppInfo.get(position).getPkgName());   
  60.           
  61.         infater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  62.         View dialog = infater.inflate(R.layout.dialog_app_size, null) ;  
  63.         TextView tvcachesize =(TextView) dialog.findViewById(R.id.tvcachesize) ; //缓存大小   
  64.         TextView tvdatasize = (TextView) dialog.findViewById(R.id.tvdatasize)  ; //数据大小   
  65.         TextView tvcodesize = (TextView) dialog.findViewById(R.id.tvcodesize) ; // 应用程序大小   
  66.         TextView tvtotalsize = (TextView) dialog.findViewById(R.id.tvtotalsize) ; //总大小   
  67.         //类型转换并赋值   
  68.         tvcachesize.setText(formateFileSize(cachesize));  
  69.         tvdatasize.setText(formateFileSize(datasize)) ;  
  70.         tvcodesize.setText(formateFileSize(codesize)) ;  
  71.         tvtotalsize.setText(formateFileSize(totalsize)) ;  
  72.         //显示自定义对话框   
  73.         AlertDialog.Builder builder =new AlertDialog.Builder(MainActivity.this) ;  
  74.         builder.setView(dialog) ;  
  75.         builder.setTitle(mlistAppInfo.get(position).getAppLabel()+"的大小信息为:") ;  
  76.         builder.setPositiveButton("确定"new DialogInterface.OnClickListener() {  
  77.   
  78.             @Override  
  79.             public void onClick(DialogInterface dialog, int which) {  
  80.                 // TODO Auto-generated method stub   
  81.                 dialog.cancel() ;  // 取消显示对话框   
  82.             }  
  83.               
  84.         });  
  85.         builder.create().show() ;  
  86.     }  
  87.     public void  queryPacakgeSize(String pkgName) throws Exception{  
  88.         if ( pkgName != null){  
  89.             //使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo   
  90.             PackageManager pm = getPackageManager();  //得到pm对象   
  91.             try {  
  92.                 //通过反射机制获得该隐藏函数   
  93.                 Method getPackageSizeInfo = pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class);  
  94.                 //调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数   
  95.                 getPackageSizeInfo.invoke(pm, pkgName,new PkgSizeObserver());  
  96.             }   
  97.             catch(Exception ex){  
  98.                 Log.e(TAG, "NoSuchMethodException") ;  
  99.                 ex.printStackTrace() ;  
  100.                 throw ex ;  // 抛出异常   
  101.             }   
  102.         }  
  103.     }  
  104.      
  105.     //aidl文件形成的Bindler机制服务类   
  106.     public class PkgSizeObserver extends IPackageStatsObserver.Stub{  
  107.         /*** 回调函数, 
  108.          * @param pStatus ,返回数据封装在PackageStats对象中 
  109.          * @param succeeded  代表回调成功 
  110.          */   
  111.         @Override  
  112.         public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)  
  113.                 throws RemoteException {  
  114.             // TODO Auto-generated method stub   
  115.            cachesize = pStats.cacheSize  ; //缓存大小   
  116.             datasize = pStats.dataSize  ;  //数据大小    
  117.             codesize = pStats.codeSize  ;  //应用程序大小   
  118.             totalsize = cachesize + datasize + codesize ;  
  119.             Log.i(TAG, "cachesize--->"+cachesize+" datasize---->"+datasize+ " codeSize---->"+codesize)  ;  
  120.         }  
  121.     }  
  122.     //系统函数,字符串转换 long -String (kb)   
  123.     private String formateFileSize(long size){  
  124.         return Formatter.formatFileSize(MainActivity.this, size);   
  125.     }  
  126.    // 获得所有启动Activity的信息,类似于Launch界面   
  127.     public void queryAppInfo() {  
  128.         PackageManager pm = this.getPackageManager(); // 获得PackageManager对象   
  129.         Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);  
  130.         mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);  
  131.         // 通过查询,获得所有ResolveInfo对象.   
  132.         List<ResolveInfo> resolveInfos = pm.queryIntentActivities(mainIntent, 0);  
  133.         // 调用系统排序 , 根据name排序   
  134.         // 该排序很重要,否则只能显示系统应用,而不能列出第三方应用程序   
  135.         Collections.sort(resolveInfos,new ResolveInfo.DisplayNameComparator(pm));  
  136.         if (mlistAppInfo != null) {  
  137.             mlistAppInfo.clear();  
  138.             for (ResolveInfo reInfo : resolveInfos) {  
  139.                 String activityName = reInfo.activityInfo.name; // 获得该应用程序的启动Activity的name   
  140.                 String pkgName = reInfo.activityInfo.packageName; // 获得应用程序的包名   
  141.                 String appLabel = (String) reInfo.loadLabel(pm); // 获得应用程序的Label   
  142.                 Drawable icon = reInfo.loadIcon(pm); // 获得应用程序图标   
  143.                 // 为应用程序的启动Activity 准备Intent   
  144.                 Intent launchIntent = new Intent();  
  145.                 launchIntent.setComponent(new ComponentName(pkgName,activityName));  
  146.                 // 创建一个AppInfo对象,并赋值   
  147.                 AppInfo appInfo = new AppInfo();  
  148.                 appInfo.setAppLabel(appLabel);  
  149.                 appInfo.setPkgName(pkgName);  
  150.                 appInfo.setAppIcon(icon);  
  151.                 appInfo.setIntent(launchIntent);  
  152.                 mlistAppInfo.add(appInfo); // 添加至列表中   
  153.             }  
  154.         }  
  155.     }  
  156. }  

package com.qin.appsize;


import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.qin.appsize.AppInfo;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.IPackageStatsObserver;
import android.content.pm.PackageManager;
import android.content.pm.PackageStats;
import android.content.pm.ResolveInfo;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.RemoteException;
import android.text.format.Formatter;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;

public class MainActivity extends Activity implements OnItemClickListener{
    private static String TAG = "APP_SIZE";

	private ListView listview = null;
	private List<AppInfo> mlistAppInfo = null;
	LayoutInflater infater = null ; 
	//全局变量,保存当前查询包得信息
	private long cachesize ; //缓存大小
	private long datasize  ;  //数据大小 
	private long codesize  ;  //应用程序大小
	private long totalsize ; //总大小
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.browse_app_list);
        listview = (ListView) findViewById(R.id.listviewApp);
		mlistAppInfo = new ArrayList<AppInfo>();
		queryAppInfo(); // 查询所有应用程序信息
		BrowseApplicationInfoAdapter browseAppAdapter = new BrowseApplicationInfoAdapter(
				this, mlistAppInfo);
		listview.setAdapter(browseAppAdapter);
		listview.setOnItemClickListener(this);
    }
     // 点击弹出对话框,显示该包得大小
	public void onItemClick(AdapterView<?> arg0, View view, int position,long arg3) {
        //更新显示当前包得大小信息
		queryPacakgeSize(mlistAppInfo.get(position).getPkgName()); 
        
		infater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		View dialog = infater.inflate(R.layout.dialog_app_size, null) ;
		TextView tvcachesize =(TextView) dialog.findViewById(R.id.tvcachesize) ; //缓存大小
		TextView tvdatasize = (TextView) dialog.findViewById(R.id.tvdatasize)  ; //数据大小
		TextView tvcodesize = (TextView) dialog.findViewById(R.id.tvcodesize) ; // 应用程序大小
		TextView tvtotalsize = (TextView) dialog.findViewById(R.id.tvtotalsize) ; //总大小
		//类型转换并赋值
		tvcachesize.setText(formateFileSize(cachesize));
		tvdatasize.setText(formateFileSize(datasize)) ;
		tvcodesize.setText(formateFileSize(codesize)) ;
		tvtotalsize.setText(formateFileSize(totalsize)) ;
		//显示自定义对话框
		AlertDialog.Builder builder =new AlertDialog.Builder(MainActivity.this) ;
		builder.setView(dialog) ;
		builder.setTitle(mlistAppInfo.get(position).getAppLabel()+"的大小信息为:") ;
		builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {

			@Override
			public void onClick(DialogInterface dialog, int which) {
				// TODO Auto-generated method stub
				dialog.cancel() ;  // 取消显示对话框
			}
			
		});
		builder.create().show() ;
	}
    public void  queryPacakgeSize(String pkgName) throws Exception{
    	if ( pkgName != null){
    		//使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
    		PackageManager pm = getPackageManager();  //得到pm对象
    		try {
    			//通过反射机制获得该隐藏函数
				Method getPackageSizeInfo = pm.getClass().getDeclaredMethod("getPackageSizeInfo", String.class,IPackageStatsObserver.class);
			    //调用该函数,并且给其分配参数 ,待调用流程完成后会回调PkgSizeObserver类的函数
			    getPackageSizeInfo.invoke(pm, pkgName,new PkgSizeObserver());
			} 
        	catch(Exception ex){
        		Log.e(TAG, "NoSuchMethodException") ;
        		ex.printStackTrace() ;
        		throw ex ;  // 抛出异常
        	} 
    	}
    }
   
    //aidl文件形成的Bindler机制服务类
    public class PkgSizeObserver extends IPackageStatsObserver.Stub{
        /*** 回调函数,
         * @param pStatus ,返回数据封装在PackageStats对象中
         * @param succeeded  代表回调成功
         */ 
		@Override
		public void onGetStatsCompleted(PackageStats pStats, boolean succeeded)
				throws RemoteException {
			// TODO Auto-generated method stub
		   cachesize = pStats.cacheSize  ; //缓存大小
		    datasize = pStats.dataSize  ;  //数据大小 
		    codesize = pStats.codeSize  ;  //应用程序大小
		    totalsize = cachesize + datasize + codesize ;
			Log.i(TAG, "cachesize--->"+cachesize+" datasize---->"+datasize+ " codeSize---->"+codesize)  ;
		}
    }
    //系统函数,字符串转换 long -String (kb)
    private String formateFileSize(long size){
    	return Formatter.formatFileSize(MainActivity.this, size); 
    }
   // 获得所有启动Activity的信息,类似于Launch界面
	public void queryAppInfo() {
		PackageManager pm = this.getPackageManager(); // 获得PackageManager对象
		Intent mainIntent = new Intent(Intent.ACTION_MAIN, null);
		mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
		// 通过查询,获得所有ResolveInfo对象.
		List<ResolveInfo> resolveInfos = pm.queryIntentActivities(mainIntent, 0);
		// 调用系统排序 , 根据name排序
		// 该排序很重要,否则只能显示系统应用,而不能列出第三方应用程序
		Collections.sort(resolveInfos,new ResolveInfo.DisplayNameComparator(pm));
		if (mlistAppInfo != null) {
			mlistAppInfo.clear();
			for (ResolveInfo reInfo : resolveInfos) {
				String activityName = reInfo.activityInfo.name; // 获得该应用程序的启动Activity的name
				String pkgName = reInfo.activityInfo.packageName; // 获得应用程序的包名
				String appLabel = (String) reInfo.loadLabel(pm); // 获得应用程序的Label
				Drawable icon = reInfo.loadIcon(pm); // 获得应用程序图标
				// 为应用程序的启动Activity 准备Intent
				Intent launchIntent = new Intent();
				launchIntent.setComponent(new ComponentName(pkgName,activityName));
				// 创建一个AppInfo对象,并赋值
				AppInfo appInfo = new AppInfo();
				appInfo.setAppLabel(appLabel);
				appInfo.setPkgName(pkgName);
				appInfo.setAppIcon(icon);
				appInfo.setIntent(launchIntent);
				mlistAppInfo.add(appInfo); // 添加至列表中
			}
		}
	}
}


      获取应用程序信息大小就是这么来的,整个过程相对而言还是挺简单的,比较难理解的是AIDL文件的使用和回调函数的处理。

仔细研究后,才有所理解



你可能感兴趣的:(android,android)