概述
最近做一个功能时有这样一个需求,就是要扫描本地所有已安装的App,来判断是否安装了某个App,如果没有安装,点击按钮就下载,如果已经安装,点击按钮就打开该App。这个里面主要的功能就是获取当前安装的所有APP的信息。所以我就写了一个demo,展示所有已安装App的图标和包名。
进入正题,先看效果图:
上面是扫描到的App的图标和包名。这个demo主要分两块,一块是扫描的到App信息列表,一块是用ListView展示出来。
在展示的时候,我们只用到了两个应用信息,一个是应用的图标,一个是应用的包名。所以我们先定义一个类来代表我们扫描到的App。
public class MyAppInfo {
private Drawable image;
private String appName;
public MyAppInfo(Drawable image, String appName) {
this.image = image;
this.appName = appName;
}
public MyAppInfo() {
}
public Drawable getImage() {
return image;
}
public void setImage(Drawable image) {
this.image = image;
}
public String getAppName() {
return appName;
}
public void setAppName(String appName) {
this.appName = appName;
}
}
只有两个属性,两个构造方法,和系统生成的get ,set方法,没什么好说的,image放置图标,appName放置包名。定义好了放置应用信息的类,接下来再定义一个ApkTool的工具类,用来帮助我们获取当前所安装的App。
/**
* Created by gray_dog3 on 16/3/3.
* 扫描本地安装的应用,工具类
*/
public class ApkTool {
static String TAG = "ApkTool";
public static List<MyAppInfo> mLocalInstallApps = null;
public static List<MyAppInfo> scanLocalInstallAppList(PackageManager packageManager) {
List<MyAppInfo> myAppInfos = new ArrayList<MyAppInfo>();
try {
List<PackageInfo> packageInfos = packageManager.getInstalledPackages(0);
for (int i = 0; i < packageInfos.size(); i++) {
PackageInfo packageInfo = packageInfos.get(i);
//过滤掉系统app
// if ((ApplicationInfo.FLAG_SYSTEM & packageInfo.applicationInfo.flags) != 0) {
// continue;
// }
MyAppInfo myAppInfo = new MyAppInfo();
myAppInfo.setAppName(packageInfo.packageName);
if (packageInfo.applicationInfo.loadIcon(packageManager) == null) {
continue;
}
myAppInfo.setImage(packageInfo.applicationInfo.loadIcon(packageManager));
myAppInfos.add(myAppInfo);
}
}catch (Exception e){
Log.e(TAG,"===============获取应用包信息失败");
}
return myAppInfos;
}
}
里面就只有一个方法,根据所传的packageManager获得所有已安装的应用的包信息。然后遍历,去除没有图标的包信息,把所有图标的应用放到myAppInfos列表里。非常简单,这里注意注释掉部分,是过滤掉所有系统应用的,因为有时候我们只想知道第三方应用列表,便于管理。
最上面的mLocalInstallApps是开始留给做缓存用的,由于在扫描的时候要另外开一个线程,加缓存还牵涉到加锁,同步的问题,讲起来比较麻烦,所以暂且先不讲缓存。只讲这一个知识点。其实加上缓存代码也很简单。
好了,ApkTool写好了,我们怎么去调用呢。不上代码都是耍流氓,直接看代码:
private void initAppList(){
new Thread(){
@Override
public void run() {
super.run();
//扫描得到APP列表
final List<MyAppInfo> appInfos = ApkTool.scanLocalInstallAppList(MainActivity.this.getPackageManager());
mHandler.post(new Runnable() {
@Override
public void run() {
mAppAdapter.setData(appInfos);
}
});
}
}.start();
}
就这几行,我们在MainActivity里面写了这个方法,在onCreat()里去调用,初始化列表。开一个线程,然后在run()方法里面做我们想做的事,调用我们在ApkTool里写好的方法。返回封装好的,只有图标和包名的应用信息列表。这里解释下,因为扫描比较耗时,可能会引起ANR,所以开了一个子线程,去调用ApkTool来扫描应用信息。扫描到结果以后,我们要通知Adapter来更新UI,Android不允许在非UI线程里面更新UI的,所以这里用了Handler去post一个Runnable对象。如果对Handler不是很懂,可以去看下官方怎么讲。我后面也会写一篇相关的博客来专门讲Handler。还是先简单说下吧:(懂的跳过)
由于Android是移动设备,用户交互几乎全部通过屏幕,用户的全部注意力几乎都集中在屏幕上,屏幕交互卡顿,或者UI信息有丝毫的延迟,用户的感觉是很不爽的。所以Android把UI显示放到主线程里,并且强烈建议耗时操作放到子线程里。但是别的线程把事情做好了,总要通知UI,展示界面变化吧,比如新闻客户端里,连接网络加载信息的线程,把新闻从服务端拉过来了,如果它直接去操作界面,结束loading,显示内容,这样也不是不可以,但是,如果没有约束,UI展示的时序行就难保证了,各种事情做好了就来操作UI,那UI显示就乱掉了。所以android是拒绝的。但是UI线程也要知道事情做完了。所以UI线程就给子线程提供了一个交互的信使Handler。就是UI线程说,你想跟哥汇报什么事,先跟我的Handler说,我每隔一段时间再把我的Handler叫过来,取一件处理。我们在UI线程里new Handler的时候也就相当于雇了一个信使,然后子线程就可以用这个信使来给UI线程传信了。在Android里我们通过Handler可以传递一些Message,也可以通过传Runnable对象,这样Runnable的run()方法里面的内容就是我们想要在UI线程里要执行的代码。
扯完了Handler细节很多,但作用就是这个,还是建议认真看下官方文档。
关于ListView部分就不多讲了,直接贴出代码:
public class MainActivity extends AppCompatActivity {
private ListView lv_app_list;
private AppAdapter mAppAdapter;
public Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_app_list = (ListView) findViewById(R.id.lv_app_list);
mAppAdapter = new AppAdapter();
lv_app_list.setAdapter(mAppAdapter);
initAppList();
}
private void initAppList(){
new Thread(){
@Override
public void run() {
super.run();
//扫描得到APP列表
final List<MyAppInfo> appInfos = ApkTool.scanLocalInstallAppList(MainActivity.this.getPackageManager());
mHandler.post(new Runnable() {
@Override
public void run() {
mAppAdapter.setData(appInfos);
}
});
}
}.start();
}
class AppAdapter extends BaseAdapter {
List<MyAppInfo> myAppInfos = new ArrayList<MyAppInfo>();
public void setData(List<MyAppInfo> myAppInfos) {
this.myAppInfos = myAppInfos;
notifyDataSetChanged();
}
public List<MyAppInfo> getData() {
return myAppInfos;
}
@Override
public int getCount() {
if (myAppInfos != null && myAppInfos.size() > 0) {
return myAppInfos.size();
}
return 0;
}
@Override
public Object getItem(int position) {
if (myAppInfos != null && myAppInfos.size() > 0) {
return myAppInfos.get(position);
}
return null;
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder;
MyAppInfo myAppInfo = myAppInfos.get(position);
if (convertView == null) {
mViewHolder = new ViewHolder();
convertView = LayoutInflater.from(getBaseContext()).inflate(R.layout.item_app_info, null);
mViewHolder.iv_app_icon = (ImageView) convertView.findViewById(R.id.iv_app_icon);
mViewHolder.tx_app_name = (TextView) convertView.findViewById(R.id.tv_app_name);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
mViewHolder.iv_app_icon.setImageDrawable(myAppInfo.getImage());
mViewHolder.tx_app_name.setText(myAppInfo.getAppName());
return convertView;
}
class ViewHolder {
ImageView iv_app_icon;
TextView tx_app_name;
}
}
}
最后说下,如果想实时监听有app安装或者卸载,可以在资源清单里面注册监听安装和卸载app的广播,也可以在Activity里面监听,只要收到广播后再调用上面的initAppList()方法即可。如果你要实现跟我一样的功能,检测一个应用是否安装,可以在遍历的时候去拿包名比较,就可以的到结果。如果你要列出所有的系统应用或所有的非系统应用,上面注释出也给出了过滤方法。
好了,传送门:
https://github.com/angularzues/APPList.git
最后
以上就是优美心情为你收集整理的获取Android手机里所有已安装的APP的全部内容,希望文章能够帮你解决获取Android手机里所有已安装的APP所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复