通过第一部分<<Android中获取应用程序(包)的信息-----PackageManager的使用(一)>>的介绍,对PackageManager以及

AndroidManife.xml定义的节点信息类XXXInfo类都有了一定的认识。

本部分的内容是如何获取安装包得大小,包括缓存大小(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. /*@parampackageName应用程序包名
  2. *@paramobserver当查询包得信息大小操作完成后,将回调给IPackageStatsObserver类中的onGetStatsCompleted()方法,
  3. *,并且我们需要的PackageStats对象也封装在其参数里.
  4. *@hide//隐藏函数的标记
  5. */
  6. publicabstractvoidgetPackageSizeInfo(StringpackageName,IPackageStatsObserverobserver);{
  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 文件

view plain copy to clipboard print ?
  1. packageandroid.content.pm;
  2. importandroid.content.pm.PackageStats;
  3. /**
  4. *APIforpackagedatachangerelatedcallbacksfromthePackageManager.
  5. *Someusagescenariosincludedeletionofcachedirectory,generate
  6. *statisticsrelatedtocode,data,cacheusage(TODO)
  7. *{@hide}
  8. */
  9. onewayinterfaceIPackageStatsObserver{
  10. voidonGetStatsCompleted(inPackageStatspStats,booleansucceeded);
  11. }

PackageStats.aidl文件

view plain copy to clipboard print ?
  1. packageandroid.content.pm;
  2. parcelablePackageStats;

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

view plain copy to clipboard print ?
  1. //aidl文件形成的Bindler机制服务类
  2. publicclassPkgSizeObserverextendsIPackageStatsObserver.Stub{
  3. /***回调函数,
  4. *@parampStatus,返回数据封装在PackageStats对象中
  5. *@paramsucceeded代表回调成功
  6. */
  7. @Override
  8. publicvoidonGetStatsCompleted(PackageStatspStats,booleansucceeded)
  9. throwsRemoteException{
  10. //TODOAuto-generatedmethodstub
  11. cachesize=pStats.cacheSize;//缓存大小
  12. datasize=pStats.codeSize;//数据大小
  13. codesize=pStats.codeSize;//应用程序大小
  14. }
  15. }

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

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

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

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


流程图如下:

Android中获取应用程序(包)的大小-----PackageManager的使用(二) .

Demo说明

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

截图如下:

工程图: 程序效果图:

Android中获取应用程序(包)的大小-----PackageManager的使用(二) .Android中获取应用程序(包)的大小-----PackageManager的使用(二) .

1、dialg_app_size.xml 文件

view plain copy to clipboard print ?
  1. <?xmlversion="1.0"encoding="utf-8"?>
  2. <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
  3. android:orientation="vertical"android:layout_width="wrap_content"
  4. android:layout_height="wrap_content">
  5. <LinearLayoutandroid:layout_width="wrap_content"
  6. android:layout_height="wrap_content"android:orientation="horizontal">
  7. <TextViewandroid:layout_width="100dip"
  8. android:layout_height="wrap_content"android:text="缓存大小:"></TextView>
  9. <TextViewandroid:layout_width="100dip"android:id="@+id/tvcachesize"
  10. android:layout_height="wrap_content"></TextView>
  11. </LinearLayout>
  12. <LinearLayoutandroid:layout_width="wrap_content"
  13. android:layout_height="wrap_content"android:orientation="horizontal">
  14. <TextViewandroid:layout_width="100dip"
  15. android:layout_height="wrap_content"android:text="数据大小:"></TextView>
  16. <TextViewandroid:layout_width="100dip"android:id="@+id/tvdatasize"
  17. android:layout_height="wrap_content"></TextView>
  18. </LinearLayout>
  19. <LinearLayoutandroid:layout_width="wrap_content"
  20. android:layout_height="wrap_content"android:orientation="horizontal">
  21. <TextViewandroid:layout_width="100dip"
  22. android:layout_height="wrap_content"android:text="应用程序大小:"></TextView>
  23. <TextViewandroid:layout_width="100dip"android:id="@+id/tvcodesize"
  24. android:layout_height="wrap_content"></TextView>
  25. </LinearLayout>
  26. <LinearLayoutandroid:layout_width="wrap_content"
  27. android:layout_height="wrap_content"android:orientation="horizontal">
  28. <TextViewandroid:layout_width="100dip"
  29. android:layout_height="wrap_content"android:text="总大小:"></TextView>
  30. <TextViewandroid:layout_width="100dip"android:id="@+id/tvtotalsize"
  31. android:layout_height="wrap_content"></TextView>
  32. </LinearLayout>
  33. </LinearLayout>

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

3、添加AIDL文件,如上。

4、主文件MainActivity.java如下:

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


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

仔细研究后,才有所理解

更多相关文章

  1. Google将推出Android手机版Voice应用程序
  2. android中完全退出当前应用程序的四种方法
  3. (转载)关于android应用程序的入口Activity
  4. Android Studio如何使用快捷键生成get,set,tostring,构造函数
  5. android 机器人:应用程序Manifest介绍
  6. Android图片左右切换和拖动大小
  7. android图片透明度跟缩放大小动画事件
  8. Android 取得手机屏幕大小

随机推荐

  1. 怎样在Eclipse中安装Android的ADT插件
  2. Android(安卓)上 Https 双向通信— 深入
  3. Rockie's Android(安卓)Porting Guide(2)—
  4. Android中Activity的四种启动模式
  5. 系出名门Android(7) - 控件(View)之ZoomC
  6. android 如何调用选择文件模块
  7. android背景选择器selector用法汇总
  8. android的selector,背景选择器
  9. Android中圆角显示EditText,并且只能显示
  10. [Android]新功能引导高亮显示遮罩层View