Android中获取应用程序(包)的信息-----PackageManager的使用
等。除此之外,还提供了一个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属性)
publicString 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 StringpackageName 包名
public ActivityInfo[] activities 所有<activity>节点信息
public ApplicationInfo applicationInfo<application>节点信息,只有一个
publicActivityInfo[] receivers 所有<receiver>节点信息,多个
public ServiceInfo[] services 所有<service>节点信息 ,多个
PackageManger 类
说明: 获得已安装的应用程序信息 。可以通过getPackageManager()方法获得。
常用方法:
public abstract PackageManager getPackageManager()
功能:获得一个PackageManger对象
public abstrac tDrawable getApplicationIcon(StringpackageName)
参数: packageName 包名
功能:返回给定包名的图标,否则返回null
public abstractApplicationInfogetApplicationInfo(StringpackageName, int flags)
参数:packagename 包名
flags 该ApplicationInfo是此flags标记,通常可以直接赋予常数0即可
功能:返回该ApplicationInfo对象
public abstractList<ApplicationInfo> getInstalledApplications(int flags)
参数:flag为一般为GET_UNINSTALLED_PACKAGES,那么此时会返回所有ApplicationInfo。我们可以对ApplicationInfo
的flags过滤,得到我们需要的。
功能:返回给定条件的所有PackageInfo
public abstractList<PackageInfo> getInstalledPackages(int flags)
参数如上
功能:返回给定条件的所有PackageInfo
publicabstractResolveInfo resolveActivity(Intentintent, 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 abstractList<ResolveInfo> queryIntentActivities(Intentintent, int flags)
参数同上
功能 :返回给定条件的所有ResolveInfo对象(本质上是Activity),集合对象
public abstractResolveInfo resolveService(Intentintent, int flags)
参数同上
功能 :返回给定条件的ResolveInfo对象(本质上是Service)
public abstractList<ResolveInfo>queryIntentServices(Intentintent, 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 :
图:
1 、布局文件: 主要有两个:带listview的browse_app_list.xml文件 ;listview的项browse_app_item.xml
browse_app_list.xml
view plain print ?- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="fill_parent"
- android:layout_height="fill_parent">>
- <ListViewandroid:id="@+id/listviewApp"android:layout_width="fill_parent"
- android:layout_height="fill_parent"></ListView>
- </LinearLayout>
browse_app_item.xmlbrowse_app_item.xml
- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"android:layout_height="50dip">
- <ImageViewandroid:id="@+id/imgApp"android:layout_width="wrap_content"
- android:layout_height="fill_parent"></ImageView>
- <RelativeLayoutandroid:layout_width="fill_parent"android:layout_marginLeft="10dip"
- android:layout_height="40dip">
- <TextViewandroid:id="@+id/tvLabel"android:layout_width="wrap_content"
- android:layout_height="wrap_content"android:text="AppLable:"></TextView>
- <TextViewandroid:id="@+id/tvAppLabel"android:layout_width="wrap_content"
- android:layout_toRightOf="@id/tvLabel"android:layout_height="wrap_content"
- android:layout_marginLeft="3dip"android:text="Label"android:textColor="#FFD700"></TextView>
- <TextViewandroid:id="@+id/tvName"android:layout_width="wrap_content"
- android:layout_height="wrap_content"android:layout_below="@id/tvLabel"
- android:text="包名:"></TextView>
- <TextViewandroid:id="@+id/tvPkgName"android:layout_width="wrap_content"
- android:layout_height="wrap_content"android:layout_below="@id/tvAppLabel"
- android:layout_alignLeft="@id/tvAppLabel"android:textColor="#FFD700"></TextView>
- </RelativeLayout>
- </LinearLayout>
2 、AppInfo.java : 保存应用程序信息的Model类
view plain print ?- /Model类,用来存储应用程序信息
- publicclassAppInfo{
- privateStringappLabel;//应用程序标签
- privateDrawableappIcon;//应用程序图像
- privateIntentintent;//启动应用程序的Intent,一般是Action为Main和Category为Lancher的Activity
- privateStringpkgName;//应用程序所对应的包名
- publicAppInfo(){}
- publicStringgetAppLabel(){
- returnappLabel;
- }
- publicvoidsetAppLabel(StringappName){
- this.appLabel=appName;
- }
- publicDrawablegetAppIcon(){
- returnappIcon;
- }
- publicvoidsetAppIcon(DrawableappIcon){
- this.appIcon=appIcon;
- }
- publicIntentgetIntent(){
- returnintent;
- }
- publicvoidsetIntent(Intentintent){
- this.intent=intent;
- }
- publicStringgetPkgName(){
- returnpkgName;
- }
- publicvoidsetPkgName(StringpkgName){
- this.pkgName=pkgName;
- }
- }
3、 BrowseApplicationInfoAdapter.java : 自定义适配器类,为ListView提供视图
view plain print ?- //自定义适配器类,提供给listView的自定义view
- publicclassBrowseApplicationInfoAdapterextendsBaseAdapter{
- privateList<AppInfo>mlistAppInfo=null;
- LayoutInflaterinfater=null;
- publicBrowseApplicationInfoAdapter(Contextcontext,List<AppInfo>apps){
- infater=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- mlistAppInfo=apps;
- }
- @Override
- publicintgetCount(){
- //TODOAuto-generatedmethodstub
- System.out.println("size"+mlistAppInfo.size());
- returnmlistAppInfo.size();
- }
- @Override
- publicObjectgetItem(intposition){
- //TODOAuto-generatedmethodstub
- returnmlistAppInfo.get(position);
- }
- @Override
- publiclonggetItemId(intposition){
- //TODOAuto-generatedmethodstub
- return0;
- }
- @Override
- publicViewgetView(intposition,Viewconvertview,ViewGrouparg2){
- System.out.println("getViewat"+position);
- Viewview=null;
- ViewHolderholder=null;
- if(convertview==null||convertview.getTag()==null){
- view=infater.inflate(R.layout.browse_app_item,null);
- holder=newViewHolder(view);
- view.setTag(holder);
- }
- else{
- view=convertview;
- holder=(ViewHolder)convertview.getTag();
- }
- AppInfoappInfo=(AppInfo)getItem(position);
- holder.appIcon.setImageDrawable(appInfo.getAppIcon());
- holder.tvAppLabel.setText(appInfo.getAppLabel());
- holder.tvPkgName.setText(appInfo.getPkgName());
- returnview;
- }
- classViewHolder{
- ImageViewappIcon;
- TextViewtvAppLabel;
- TextViewtvPkgName;
- publicViewHolder(Viewview){
- this.appIcon=(ImageView)view.findViewById(R.id.imgApp);
- this.tvAppLabel=(TextView)view.findViewById(R.id.tvAppLabel);
- this.tvPkgName=(TextView)view.findViewById(R.id.tvPkgName);
- }
- }
- }
4 、MainActivity.java 主工程逻辑
请仔细体会queryIntentActivities()方法,并且注意到排序,它很重要。
view plain print ?- <spanstyle="font-size:13px;">publicclassMainActivityextendsActivityimplementsOnItemClickListener{
- privateListViewlistview=null;
- privateList<AppInfo>mlistAppInfo=null;
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.browse_app_list);
- listview=(ListView)findViewById(R.id.listviewApp);
- mlistAppInfo=newArrayList<AppInfo>();
- queryAppInfo();//查询所有应用程序信息
- BrowseApplicationInfoAdapterbrowseAppAdapter=newBrowseApplicationInfoAdapter(
- this,mlistAppInfo);
- listview.setAdapter(browseAppAdapter);
- listview.setOnItemClickListener(this);
- }
- //点击跳转至该应用程序
- publicvoidonItemClick(AdapterView<?>arg0,Viewview,intposition,
- longarg3){
- //TODOAuto-generatedmethodstub
- Intentintent=mlistAppInfo.get(position).getIntent();
- startActivity(intent);
- }
- //获得所有启动Activity的信息,类似于Launch界面
- publicvoidqueryAppInfo(){
- PackageManagerpm=this.getPackageManager();//获得PackageManager对象
- IntentmainIntent=newIntent(Intent.ACTION_MAIN,null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- //通过查询,获得所有ResolveInfo对象.
- List<ResolveInfo>resolveInfos=pm
- .queryIntentActivities(mainIntent,PackageManager.MATCH_DEFAULT_ONLY);
- //调用系统排序,根据name排序
- //该排序很重要,否则只能显示系统应用,而不能列出第三方应用程序
- Collections.sort(resolveInfos,newResolveInfo.DisplayNameComparator(pm));
- if(mlistAppInfo!=null){
- mlistAppInfo.clear();
- for(ResolveInforeInfo:resolveInfos){
- StringactivityName=reInfo.activityInfo.name;//获得该应用程序的启动Activity的name
- StringpkgName=reInfo.activityInfo.packageName;//获得应用程序的包名
- StringappLabel=(String)reInfo.loadLabel(pm);//获得应用程序的Label
- Drawableicon=reInfo.loadIcon(pm);//获得应用程序图标
- //为应用程序的启动Activity准备Intent
- IntentlaunchIntent=newIntent();
- launchIntent.setComponent(newComponentName(pkgName,
- activityName));
- //创建一个AppInfo对象,并赋值
- AppInfoappInfo=newAppInfo();
- appInfo.setAppLabel(appLabel);
- appInfo.setPkgName(pkgName);
- appInfo.setAppIcon(icon);
- appInfo.setIntent(launchIntent);
- mlistAppInfo.add(appInfo);//添加至列表中
- System.out.println(appLabel+"activityName---"+activityName
- +"pkgName---"+pkgName);
- }
- }
- }
- }</span>
好了,第一个Demo完成 。。
Demo 2:
demo2在布局、适配器方面和Demo1一样。只是利用了getInstalledApplications()方法,继而通过ApplicationInfo.flags来挑选
我们希望的ApplicationInfo对象。
图:
过滤应用程序如下:
view plain print ?- packagecom.qiner.appinfo;
- importjava.util.ArrayList;
- importjava.util.Collections;
- importjava.util.List;
- importcom.qiner.appinfo.R;
- importandroid.app.Activity;
- importandroid.app.Application;
- importandroid.content.pm.ApplicationInfo;
- importandroid.content.pm.PackageManager;
- importandroid.os.Bundle;
- importandroid.view.View;
- importandroid.view.View.OnClickListener;
- importandroid.widget.Button;
- importandroid.widget.ListView;
- publicclassMainActivityextendsActivity{
- publicstaticfinalintFILTER_ALL_APP=0;//所有应用程序
- publicstaticfinalintFILTER_SYSTEM_APP=1;//系统程序
- publicstaticfinalintFILTER_THIRD_APP=2;//第三方应用程序
- publicstaticfinalintFILTER_SDCARD_APP=3;//安装在SDCard的应用程序
- privateListViewlistview=null;
- privatePackageManagerpm;
- privateintfilter=FILTER_ALL_APP;
- privateList<AppInfo>mlistAppInfo;
- privateBrowseApplicationInfoAdapterbrowseAppAdapter=null;
- /**Calledwhentheactivityisfirstcreated.*/
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.browse_app_list);
- listview=(ListView)findViewById(R.id.listviewApp);
- if(getIntent()!=null){
- filter=getIntent().getIntExtra("filter",0);
- }
- mlistAppInfo=queryFilterAppInfo(filter);//查询所有应用程序信息
- //构建适配器,并且注册到listView
- browseAppAdapter=newBrowseApplicationInfoAdapter(this,mlistAppInfo);
- listview.setAdapter(browseAppAdapter);
- }
- //根据查询条件,查询特定的ApplicationInfo
- privateList<AppInfo>queryFilterAppInfo(intfilter){
- pm=this.getPackageManager();
- //查询所有已经安装的应用程序
- List<ApplicationInfo>listAppcations=pm
- .getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES);
- Collections.sort(listAppcations,
- newApplicationInfo.DisplayNameComparator(pm));//排序
- List<AppInfo>appInfos=newArrayList<AppInfo>();//保存过滤查到的AppInfo
- //根据条件来过滤
- switch(filter){
- caseFILTER_ALL_APP://所有应用程序
- appInfos.clear();
- for(ApplicationInfoapp:listAppcations){
- appInfos.add(getAppInfo(app));
- }
- returnappInfos;
- caseFILTER_SYSTEM_APP://系统程序
- appInfos.clear();
- for(ApplicationInfoapp:listAppcations){
- if((app.flags&ApplicationInfo.FLAG_SYSTEM)!=0){
- appInfos.add(getAppInfo(app));
- }
- }
- returnappInfos;
- caseFILTER_THIRD_APP://第三方应用程序
- appInfos.clear();
- for(ApplicationInfoapp:listAppcations){
- //非系统程序
- if((app.flags&ApplicationInfo.FLAG_SYSTEM)<=0){
- appInfos.add(getAppInfo(app));
- }
- //本来是系统程序,被用户手动更新后,该系统程序也成为第三方应用程序了
- elseif((app.flags&ApplicationInfo.FLAG_UPDATED_SYSTEM_APP)!=0){
- appInfos.add(getAppInfo(app));
- }
- }
- break;
- caseFILTER_SDCARD_APP://安装在SDCard的应用程序
- appInfos.clear();
- for(ApplicationInfoapp:listAppcations){
- if((app.flags&ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0){
- appInfos.add(getAppInfo(app));
- }
- }
- returnappInfos;
- default:
- returnnull;
- }
- returnappInfos;
- }
- //构造一个AppInfo对象,并赋值
- privateAppInfogetAppInfo(ApplicationInfoapp){
- AppInfoappInfo=newAppInfo();
- appInfo.setAppLabel((String)app.loadLabel(pm));
- appInfo.setAppIcon(app.loadIcon(pm));
- appInfo.setPkgName(app.packageName);
- returnappInfo;
- }
- }
你可以在此基础上,构建更多丰富的应用。比说说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 ?- /*@parampackageName应用程序包名
- *@paramobserver当查询包得信息大小操作完成后,将回调给IPackageStatsObserver类中的onGetStatsCompleted()方法,
- *,并且我们需要的PackageStats对象也封装在其参数里.
- *@hide//隐藏函数的标记
- */
- publicabstractvoidgetPackageSizeInfo(StringpackageName,IPackageStatsObserverobserver);{
- //
- }
/*@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 ?- packageandroid.content.pm;
- importandroid.content.pm.PackageStats;
- /**
- *APIforpackagedatachangerelatedcallbacksfromthePackageManager.
- *Someusagescenariosincludedeletionofcachedirectory,generate
- *statisticsrelatedtocode,data,cacheusage(TODO)
- *{@hide}
- */
- onewayinterfaceIPackageStatsObserver{
- voidonGetStatsCompleted(inPackageStatspStats,booleansucceeded);
- }
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 ?- packageandroid.content.pm;
- parcelablePackageStats;
package android.content.pm; parcelable PackageStats;
第三步、 创建一个类继承至IPackageStatsObserver.Stub (桩,)它本质上实现了Binder机制。当我们把该类的一个实例通过getPackageSizeInfo()调用时,并该函数继而启动了启动中间流程去获取相关包得信息大小,当扫描完成后,最后将查询信息回调至该类的onGetStatsCompleted(in PackageStats pStats, boolean succeeded)方法,信息大小封装在此实例上。例如:
view plain copy to clipboard print ?- //aidl文件形成的Bindler机制服务类
- publicclassPkgSizeObserverextendsIPackageStatsObserver.Stub{
- /***回调函数,
- *@parampStatus,返回数据封装在PackageStats对象中
- *@paramsucceeded代表回调成功
- */
- @Override
- publicvoidonGetStatsCompleted(PackageStatspStats,booleansucceeded)
- throwsRemoteException{
- //TODOAuto-generatedmethodstub
- cachesize=pStats.cacheSize;//缓存大小
- datasize=pStats.codeSize;//数据大小
- codesize=pStats.codeSize;//应用程序大小
- }
- }
//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 ?- <uses-permissionandroid:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>
<uses-permission android:name="android.permission.GET_PACKAGE_SIZE"></uses-permission>
流程图如下:
Demo说明:
在第一部分应用得基础上,我们添加了一个新功能,点击任何一个应用后后,弹出显示该应用的包信息大小的对话框。
截图如下:
工程图: 程序效果图:
1、dialg_app_size.xml 文件
view plain copy to clipboard print ?- <?xmlversion="1.0"encoding="utf-8"?>
- <LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"android:layout_width="wrap_content"
- android:layout_height="wrap_content">
- <LinearLayoutandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:orientation="horizontal">
- <TextViewandroid:layout_width="100dip"
- android:layout_height="wrap_content"android:text="缓存大小:"></TextView>
- <TextViewandroid:layout_width="100dip"android:id="@+id/tvcachesize"
- android:layout_height="wrap_content"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:orientation="horizontal">
- <TextViewandroid:layout_width="100dip"
- android:layout_height="wrap_content"android:text="数据大小:"></TextView>
- <TextViewandroid:layout_width="100dip"android:id="@+id/tvdatasize"
- android:layout_height="wrap_content"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:orientation="horizontal">
- <TextViewandroid:layout_width="100dip"
- android:layout_height="wrap_content"android:text="应用程序大小:"></TextView>
- <TextViewandroid:layout_width="100dip"android:id="@+id/tvcodesize"
- android:layout_height="wrap_content"></TextView>
- </LinearLayout>
- <LinearLayoutandroid:layout_width="wrap_content"
- android:layout_height="wrap_content"android:orientation="horizontal">
- <TextViewandroid:layout_width="100dip"
- android:layout_height="wrap_content"android:text="总大小:"></TextView>
- <TextViewandroid:layout_width="100dip"android:id="@+id/tvtotalsize"
- android:layout_height="wrap_content"></TextView>
- </LinearLayout>
- </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 ?
- packagecom.qin.appsize;
- importjava.lang.reflect.Method;
- importjava.util.ArrayList;
- importjava.util.Collections;
- importjava.util.List;
- importcom.qin.appsize.AppInfo;
- importandroid.app.Activity;
- importandroid.app.AlertDialog;
- importandroid.content.ComponentName;
- importandroid.content.Context;
- importandroid.content.DialogInterface;
- importandroid.content.Intent;
- importandroid.content.pm.IPackageStatsObserver;
- importandroid.content.pm.PackageManager;
- importandroid.content.pm.PackageStats;
- importandroid.content.pm.ResolveInfo;
- importandroid.graphics.drawable.Drawable;
- importandroid.os.Bundle;
- importandroid.os.RemoteException;
- importandroid.text.format.Formatter;
- importandroid.util.Log;
- importandroid.view.LayoutInflater;
- importandroid.view.View;
- importandroid.widget.AdapterView;
- importandroid.widget.ListView;
- importandroid.widget.TextView;
- importandroid.widget.AdapterView.OnItemClickListener;
- publicclassMainActivityextendsActivityimplementsOnItemClickListener{
- privatestaticStringTAG="APP_SIZE";
- privateListViewlistview=null;
- privateList<AppInfo>mlistAppInfo=null;
- LayoutInflaterinfater=null;
- //全局变量,保存当前查询包得信息
- privatelongcachesize;//缓存大小
- privatelongdatasize;//数据大小
- privatelongcodesize;//应用程序大小
- privatelongtotalsize;//总大小
- @Override
- publicvoidonCreate(BundlesavedInstanceState){
- super.onCreate(savedInstanceState);
- setContentView(R.layout.browse_app_list);
- listview=(ListView)findViewById(R.id.listviewApp);
- mlistAppInfo=newArrayList<AppInfo>();
- queryAppInfo();//查询所有应用程序信息
- BrowseApplicationInfoAdapterbrowseAppAdapter=newBrowseApplicationInfoAdapter(
- this,mlistAppInfo);
- listview.setAdapter(browseAppAdapter);
- listview.setOnItemClickListener(this);
- }
- //点击弹出对话框,显示该包得大小
- publicvoidonItemClick(AdapterView<?>arg0,Viewview,intposition,longarg3){
- //更新显示当前包得大小信息
- queryPacakgeSize(mlistAppInfo.get(position).getPkgName());
- infater=(LayoutInflater)MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- Viewdialog=infater.inflate(R.layout.dialog_app_size,null);
- TextViewtvcachesize=(TextView)dialog.findViewById(R.id.tvcachesize);//缓存大小
- TextViewtvdatasize=(TextView)dialog.findViewById(R.id.tvdatasize);//数据大小
- TextViewtvcodesize=(TextView)dialog.findViewById(R.id.tvcodesize);//应用程序大小
- TextViewtvtotalsize=(TextView)dialog.findViewById(R.id.tvtotalsize);//总大小
- //类型转换并赋值
- tvcachesize.setText(formateFileSize(cachesize));
- tvdatasize.setText(formateFileSize(datasize));
- tvcodesize.setText(formateFileSize(codesize));
- tvtotalsize.setText(formateFileSize(totalsize));
- //显示自定义对话框
- AlertDialog.Builderbuilder=newAlertDialog.Builder(MainActivity.this);
- builder.setView(dialog);
- builder.setTitle(mlistAppInfo.get(position).getAppLabel()+"的大小信息为:");
- builder.setPositiveButton("确定",newDialogInterface.OnClickListener(){
- @Override
- publicvoidonClick(DialogInterfacedialog,intwhich){
- //TODOAuto-generatedmethodstub
- dialog.cancel();//取消显示对话框
- }
- });
- builder.create().show();
- }
- publicvoidqueryPacakgeSize(StringpkgName)throwsException{
- if(pkgName!=null){
- //使用放射机制得到PackageManager类的隐藏函数getPackageSizeInfo
- PackageManagerpm=getPackageManager();//得到pm对象
- try{
- //通过反射机制获得该隐藏函数
- MethodgetPackageSizeInfo=pm.getClass().getDeclaredMethod("getPackageSizeInfo",String.class,IPackageStatsObserver.class);
- //调用该函数,并且给其分配参数,待调用流程完成后会回调PkgSizeObserver类的函数
- getPackageSizeInfo.invoke(pm,pkgName,newPkgSizeObserver());
- }
- catch(Exceptionex){
- Log.e(TAG,"NoSuchMethodException");
- ex.printStackTrace();
- throwex;//抛出异常
- }
- }
- }
- //aidl文件形成的Bindler机制服务类
- publicclassPkgSizeObserverextendsIPackageStatsObserver.Stub{
- /***回调函数,
- *@parampStatus,返回数据封装在PackageStats对象中
- *@paramsucceeded代表回调成功
- */
- @Override
- publicvoidonGetStatsCompleted(PackageStatspStats,booleansucceeded)
- throwsRemoteException{
- //TODOAuto-generatedmethodstub
- 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)
- privateStringformateFileSize(longsize){
- returnFormatter.formatFileSize(MainActivity.this,size);
- }
- //获得所有启动Activity的信息,类似于Launch界面
- publicvoidqueryAppInfo(){
- PackageManagerpm=this.getPackageManager();//获得PackageManager对象
- IntentmainIntent=newIntent(Intent.ACTION_MAIN,null);
- mainIntent.addCategory(Intent.CATEGORY_LAUNCHER);
- //通过查询,获得所有ResolveInfo对象.
- List<ResolveInfo>resolveInfos=pm.queryIntentActivities(mainIntent,0);
- //调用系统排序,根据name排序
- //该排序很重要,否则只能显示系统应用,而不能列出第三方应用程序
- Collections.sort(resolveInfos,newResolveInfo.DisplayNameComparator(pm));
- if(mlistAppInfo!=null){
- mlistAppInfo.clear();
- for(ResolveInforeInfo:resolveInfos){
- StringactivityName=reInfo.activityInfo.name;//获得该应用程序的启动Activity的name
- StringpkgName=reInfo.activityInfo.packageName;//获得应用程序的包名
- StringappLabel=(String)reInfo.loadLabel(pm);//获得应用程序的Label
- Drawableicon=reInfo.loadIcon(pm);//获得应用程序图标
- //为应用程序的启动Activity准备Intent
- IntentlaunchIntent=newIntent();
- launchIntent.setComponent(newComponentName(pkgName,activityName));
- //创建一个AppInfo对象,并赋值
- AppInfoappInfo=newAppInfo();
- appInfo.setAppLabel(appLabel);
- appInfo.setPkgName(pkgName);
- appInfo.setAppIcon(icon);
- appInfo.setIntent(launchIntent);
- mlistAppInfo.add(appInfo);//添加至列表中
- }
- }
- }
- }
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 应用程序 常见问题 FAQ
- Android:销毁所有的Activity退出应用程序几种方式
- android项目打包成apk应用程序后部署到虚拟机上测试
- Android应用程序获得root权限
- android app -- Picasso 二级缓存加载图片,可控制加载图片大小(附
- 第三部分:Android 应用程序接口指南---第四节:动画和图形---第五章
- Android开发之应用程序基础及组件