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

http://blog.csdn.net/qinjuning/article/details/6892054

 

通过第一部分 << 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()  方法原型为:              

/*@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 文件

 

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

package android.content.pm;
parcelable PackageStats;

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

 //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为计量单位的字符串。

 

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

       

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


 

     流程图如下:

Demo说明

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

        截图如下:

 

1、dialg_app_size.xml 文件
<?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如下:
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文件的使用和回调函数的处理。

仔细研究后,才有所理解

  

 

       关于PackageManager的使用的源代码已上传,下载地址:http://download.csdn.net/detail/qinjuning/3775856

 

    PS: 源码中的AIDL所在包名错误,导致报错,应为:android.content.pm。请大家修改后运行

 

 

把 getDeclaredMethod() 改成 getMethod()

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/293816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

eclipse创建maven多模块项目(单个类似)

2019独角兽企业重金招聘Python工程师标准>>> 1、下载安装maven 1.1、下载 注意&#xff1a;maven的版本&#xff0c;要根据你的jdk版本来下载。要不会安装失败&#xff0c;提示版本问题哦 Jdk 对应的maven版本如图:&#xff08;官网地址&#xff1a;http://maven.ap…

web服务器的基本应用

WEB服务器也称为WWW(WORLD WIDE WEB)即是所谓的万维网服务器&#xff0c;主要功能是提供网上信息浏览服务。 最常用的大型Web服务器是Apache和微软的Internet信息服务器&#xff08;Internet Information Server&#xff0c;所谓的IIS服务器&#xff09;、IBM WebSphere以及BE…

Android 之PackageManager框架

http://blog.csdn.net/stonecao/article/details/6591454 1.接着前面讲的ActivityManager框架&#xff0c;继续说一下系统另一个重要的框架&#xff0c;PackagerManager 同样先看一下静态类结构图&#xff1a; 大部分情况我们是在Activity中使用getPackageManager方法获取一个…

有一个会泰勒级数的八岁表妹是怎样一种体验?

全世界只有3.14 % 的人关注了爆炸吧知识上一篇文章超模君给大家介绍了欧拉公式&#xff0c;很多粉丝问我&#xff1a;八岁表妹明明还是小学生&#xff0c;是怎么知道泰勒级数的意思的?答案其实很简单&#xff0c;这当然和我们全家优秀的基因...不&#xff01;优良的家教有关&a…

限流中间件IpRateLimitMiddleware的使用

前言IpRateLimitMiddleware&#xff08;Github: AspNetCoreRateLimit&#xff09; 是ASPNETCore的一个限流的中间件&#xff0c;用于控制客户端调用API的频次&#xff0c; 如果客户端频繁访问服务器&#xff0c;可以限制它的频率&#xff0c;已降低访问服务器端的压力。或者如果…

Activity之launchMode:singleTop,singleTask与singleInstance

相关内容&#xff0c;可以参见官方网址&#xff1a; http://developer.android.com/guide/components/tasks-and-back-stack.html 如图所示&#xff0c;如果ABC三个Activity的launchMode都是standard&#xff0c;那么按照图示顺序调用后&#xff0c;堆栈为ABCBB&#xff1b; …

傅立叶变换是如何改变我们生活的? ——四个角度告诉你答案

全世界只有3.14 % 的人关注了爆炸吧知识引子&#xff1a;尽管没有微积分那样如雷贯耳的名声&#xff0c;也没有相对论那般独辟蹊径的创新&#xff0c;傅立叶变换却悄悄地潜藏在我们生活中的方方面面&#xff0c;默默地改变着这个世界。对于工科出身的读者而言&#xff0c;傅立叶…

Win11新版右键菜单用不惯?一键切换回Win10经典版!

在 Windows 11 操作系统中&#xff0c;微软对文件资源管理器和应用程序的上下文菜单&#xff08;Context Menu&#xff0c;俗称“右键菜单”&#xff09;进行了现代化改造。Windows 11 新版右键菜单更加简约&#xff0c;并且融入圆角设计&#xff0c;将常用的命令剪切、复制、粘…

MySQL使用详解--根据个人学习总结

1.安装配置 2.启动mysql服务并配置 mysql> \s&#xff08;status也行&#xff09;查看当前服务器状态查看编码状态Server characterset : utf8Db characterset: utf8Client characterset: gbkConn. characterset: gbk修改&#xff1a;---进入配置文件my.ini客户端&#xff1…

送什么给女朋友最致命?

1 啊&#xff0c;原来里面有说明书&#xff08;via.豆瓣哈组&#xff0c;侵删&#xff09;▼2 网友给女朋友准备的惊喜&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 这个泰国小哥的创意真棒&#xff08;via.阿森不是妖怪&#xff0c;侵删&#xff09;▼4 老婆的…

SWF反编译神器ASV2013功能展示(下)

动作脚本菜单动作脚本-查看元件类动作脚本-编辑AS3常量池动作脚本-ASV内部ABC数据浏览器窗口菜单 选项菜单-帧视图选项 选项菜单-预览窗口选项选项菜单-时间线视图选项选项菜单-库视图选项 选项菜单-动作脚本视图选项实用工具菜单 关于对话框 转载于:https://blog.51cto.com/as…

【项目 报错】 项目启动,内存溢出 可能出现的各种报错

内存溢出可能有如下的错误&#xff1a; 错误1&#xff1a; java.lang.OutOfMemoryError: PermGen space 错误2&#xff1a; Exception in thread "http-apr-8080-exec-2" 出现如上的错误&#xff0c;解决方法如下&#xff1a; 1.双击Tomcat 2.点击open launch config…

2021,如何找到适合自己的圈子?

全世界只有3.14 % 的人关注了爆炸吧知识蔡康永分享过这样一段话&#xff1a;“小S的个性本身就是很乐天&#xff0c;很有活力&#xff0c;她这个朋友让我觉得活着是一件很值得、很舒服、很有趣的事。而有的人会让我觉得活着很没劲&#xff0c;碰到他会把我的能量都吸走”。你和…

I/O多路转接之poll——基于TCP协议

1. 函数a. 参数&#xff1a;&#xff08;1&#xff09;fds:是一个struct pollfd结构类型的指针&#xff0c;指向用于存放需要检测状态的Socket描述符&#xff1b;每当调用这个函数之后&#xff0c;系统不会清空这个数组&#xff0c;操作起来比较方便&#xff1b;特别是对于sock…

C# 日志管理框架:Common.Logging和log4net

01—DLL引用‍common logging是一个通用日志接口框架&#xff0c;log4net是一个强大的具体实现框架. common logging可以把输出连接到其他非log类上, 如EntLib的日志、NLog等‍‍‍‍‍‍‍‍‍‍‍‍‍‍项目中需要引入的DLL:Common.Logging.dllCommon.Logging.Core.dllCommon…

我开发了一个对.NET程序进行瘦身的工具

我开发了一个对.Net程序瘦身的工具&#xff0c;可以把被引用但是没有被使用的程序集删除。我用它把一个.Net core程序从147兆瘦身到59.5兆。.NET中发布程序的时候有对程序集进行剪裁的功能&#xff0c;但是那个功能只能做静态检查。比如我们的项目使用了A程序集&#xff0c;A程…

三联竟出了这么赞的杂志!各领域佼佼者畅所欲言,为少年建立思维判断体系!

▲点击查看很多中国小孩的成长是断层的。10岁前被视作可爱稚子&#xff0c;被大人护着走&#xff1b;18岁猛然被定义为成年人&#xff0c;要选择大学、专业&#xff0c;开始面对感情。中间的人生呢&#xff1f;“你是个学生&#xff0c;学习是本职&#xff0c;现在谈什么人生&a…

C# WPF中添加调试信息查看窗体

第一步&#xff1a;添加wpf窗口&#xff1b;第二步&#xff1a;在主窗体image的MouseLeftButtonUp事件中调用调试窗口&#xff1b;StatusViewWindow svWindow new StatusViewWindow();svWindow.Show();第三步&#xff1a;在主窗体中开个线程通过udp接收光电广开的数据&#xf…

杨振宁追求的物理美学,居然在这里实现,物理学史上颜值最高的组合,看完后跪了……

全世界只有3.14 % 的人关注了爆炸吧知识一沙见世界 一花窥天堂手心握无限 须臾纳永恒杨振宁曾说读上面的四句诗可以感受到物理的美但物理的美不止于此物理还有一种庄严美一种神秘美一种初窥宇宙奥秘的畏惧美物理就是如此的迷人任何语言在它的面前都很贫瘠数学让人摆脱了愚昧而…