ListView-4,获取手机中所有应用信息,listView复用,为listView插入不同的item,根据包名开启该应用

功能:获取安装在手机里的所有应用.

注意点:复用listView Item对象时的判断

软件信息封装:AppInfo.java

/**
 * 封装应用程序的信息
 */
public class AppInfo {
    /**
     * 应用图标
     */
    private Drawable icon;
    /**
     * 应用名称
     */
    private String name;
    /**
     * 应用包名
     */
    private String packname;
    
    /**
     * 判断应用安装的位置
     * true代表安装在手机内存
     * false代表安装在sd卡
     */
    private boolean inRom;
    
    /**
     * 判断是系统应用还是用户应用
     * true代表用户
     * false代表系统
     */
    private boolean userApp;
    public Drawable getIcon() {
        return icon;
    }
    public void setIcon(Drawable icon) {
        this.icon = icon;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPackname() {
        return packname;
    }
    public void setPackname(String packname) {
        this.packname = packname;
    }
    public boolean isInRom() {
        return inRom;
    }
    public void setInRom(boolean inRom) {
        this.inRom = inRom;
    }
    public boolean isUserApp() {
        return userApp;
    }
    public void setUserApp(boolean userApp) {
        this.userApp = userApp;
    }
}

获取所有应用信息: AppInfoProvider.java

/**
 * 从该类获取所有的应用信息
 * 系统的app都安装在:system/app目录下
 * 用户应用都安装在:data/app目录下
 */
public class AppInfoProvider {
    
    /**
     * 获取安装在该手机的所有app信息,并且分好类(系统程序,用户程序)
     * 信息:包名,图片,应用名,应用安装位置,应用类型
     * @param context
     * @return
     */
    public static HashMap<String,ArrayList<AppInfo>> getAppInfos(Context context){
        //获取应用管理者
        PackageManager pm = context.getPackageManager();
        //所有安装在手机上的应用程序包信息
        List<PackageInfo> packInfos = pm.getInstalledPackages(0);
        HashMap<String,ArrayList<AppInfo>> map=new HashMap<String, ArrayList<AppInfo>>();//放所有app信息
        ArrayList<AppInfo> userList=new ArrayList<AppInfo>();//放用户程序
        ArrayList<AppInfo> systemList=new ArrayList<AppInfo>();//放系统程序
        for (PackageInfo packInfo : packInfos) {
            //packageInfo 相当于一个应用程序apk包的清单文件
            String packname=packInfo.packageName;//获取应用包名
            //packInfo.applicationInfo相当于清单文件中的application
            Drawable icon = packInfo.applicationInfo.loadIcon(pm);//获取应用图标
            String name = packInfo.applicationInfo.loadLabel(pm).toString();//应用名称
            //将得到的信息设置到自定义应用的封装类中
            AppInfo app=new AppInfo();
            app.setIcon(icon);
            app.setName(name);
            app.setPackname(packname);
            //flags携带了很多种状态信息
            int flags = packInfo.applicationInfo.flags;//应用程序信息的标记
            if((flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) ==0){
                app.setInRom(true);//安装在手机内存中
            }else{
                app.setInRom(false);//安装在外部存储
                System.out.println("外部");
            }
            if((flags & ApplicationInfo.FLAG_SYSTEM)==0){
                app.setUserApp(true);//用户程序
                userList.add(app);
            }else{
                app.setUserApp(false);//系统程序
                systemList.add(app);
            }
        }
        map.put("用户程序", userList);
        map.put("系统程序", systemList);
        return map;
    }
}
通过(上面for循环的):int appId=packInfo.applicationInfo.uid;就可以获取安卓系统分配给这个软件的id,每个软件都有自己独立的id,通过这个id可以查看该软件使用的流量信息,具体见:手机流量的统计

显示应用信息列表的适配器ListViewAdapter.java

/**
 先显示用户程序,再显示系统
TextView 用户程序3个   (相对布局中的)
ursr 1    position 0  listView的子条目
ursr 2             1
ursr 3             2
系统程序:2个                               3
system 1           4
system 2           5

注意:listView复用对象的时候需要判断是否是合适的类型,否则会出现空指针异常
 */
public class ListViewAdapter extends BaseAdapter{
    private Context context;
    private ArrayList<AppInfo> userList;//存放用户应用
    private ArrayList<AppInfo> systemList;//存放系统应用
    
    public ListViewAdapter(Context context, HashMap<String, ArrayList<AppInfo>> map) {
        this.context = context;
        userList=map.get("用户程序");
        systemList=map.get("系统程序");
    }

    @Override
    public int getCount() {
        return userList.size()+systemList.size()+1;//加1是用来显示系统程序的条例
    }

    @Override
    public Object getItem(int position) {
        if(position>userList.size()){
            return systemList.get(position-userList.size()-1);//减去前面的系统个数条例
        }
        return userList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        //显示系统个数的条目
        if(position==userList.size()){
            TextView tv=new TextView(context);
            tv.setText("系统应用有:"+systemList.size()+"个");
            tv.setTextSize(20);
            tv.setTextColor(Color.RED);
            tv.setBackgroundColor(Color.GRAY);//灰色背景
            return tv;//其实这里需要返回的是布局文件,而不是控件,就和向listView添加头一样,只能是R.layout找到的View
        }//但是对于TextView可以直接返回,如果这里返回一个ImageView或者其他的控件,肯定就报什么布局的类型转换异常了
        ViewHolder holder;
        //解决复用时,将textview复用给LineatLayout而产生空指针异常
        if(convertView!=null && convertView instanceof LinearLayout){
            holder=(ViewHolder) convertView.getTag();
        }else{
            convertView=View.inflate(context, R.layout.appinfo_item_layout, null);
            holder=new ViewHolder();
            holder.img=(ImageView) convertView.findViewById(R.id.appinfo_img);
            holder.name=(TextView) convertView.findViewById(R.id.app_name);
            holder.location=(TextView) convertView.findViewById(R.id.app_loction);
            convertView.setTag(holder);
        }
        //显示用户程序条目
        if(position<userList.size()){
            AppInfo appInfo = userList.get(position);
            holder.img.setImageDrawable(appInfo.getIcon());
            holder.name.setText(appInfo.getName());
            if(appInfo.isInRom()){
                holder.location.setText("内部存储");
            }else{
                holder.location.setText("外部存储");
            }
            return convertView;
        }else{
            AppInfo appInfo = systemList.get(position-userList.size()-1);
            holder.img.setImageDrawable(appInfo.getIcon());
            holder.name.setText(appInfo.getName());
            if(appInfo.isInRom()){
                holder.location.setText("内部存储");
            }else{
                holder.location.setText("外部存储");
            }
            return convertView;
        }
    }
    class ViewHolder{
        private ImageView img;
        private TextView name,location;
    }
}

MainActivity.java

主活动布局文件:activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
<!-- 显示设备存储空间的内存大小 -->
    <TextView
        android:id="@+id/storageInfo"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
           android:textSize="25sp" />
    <RelativeLayout 
        android:id="@+id/frame_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
         <!-- 做为应用程序类型的提示  和listview中的textview设置成一样,产生视觉效果 fastScrollEnabled为快速滑动-->
             <TextView
                android:id="@+id/listview_text"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                   android:textSize="20sp"
                   android:background="#888888"
                   android:textColor="#ff0000" />
            <ListView 
                android:id="@+id/listView"
                android:fastScrollEnabled="true"
                android:dividerHeight="2dp"
                android:layout_below="@id/listview_text"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
    </RelativeLayout>
</LinearLayout>

ListView的item布局文件 appinfo_item_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal" >
   
    <ImageView 
        android:id="@+id/appinfo_img"
        android:src="@drawable/ic_launcher"
        android:layout_width="70dp"
        android:layout_height="70dp"/>
    <RelativeLayout 
        android:layout_width="match_parent"
        android:layout_marginLeft="7dp"
        android:layout_height="70dp">
        <TextView 
            android:id="@+id/app_name"
            android:text="应用名称:"
            android:textSize="30sp"
            android:textColor="#000000"
            android:singleLine="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
         <TextView 
            android:id="@+id/app_loction"
            android:text="安装位置:"
            android:textSize="25sp"
            android:textColor="#99000000"
            android:singleLine="true"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"/>
    </RelativeLayout>
</LinearLayout>

 listView的单击事件弹出窗体可见:PopupWindow弹出窗口的使用(点击item弹出一个窗体,窗体包含一个布局,布局中为三个图片按钮,分别为卸载,开启,分享),一般的软件管理都是这样的,我们也可以仿照实现

 

通过程序的包名,启动这个程序: (上面有介绍获取程序包名)

  //单击事件
    public void btnOnClick(View v){
        PackageManager manager = getPackageManager();
        Intent intent=new Intent();
        intent.setAction("android.intent.action.MAIN");
        intent.addCategory("android.intent.category.LAUNCHER");
        //查询出手机上所有具有启动能力的activity
        List<ResolveInfo> infos = manager.queryIntentActivities(intent, PackageManager.GET_META_DATA);
        for (ResolveInfo info : infos) {
            Log.i("tag","主activity的全包名:"+info.activityInfo.name);
            //获取包名
            String packageName = info.activityInfo.packageName;
            try {
                //通过包名获取应用名称与图标
                String appName= manager.getPackageInfo(packageName, 0).applicationInfo.loadLabel(manager).toString();
                Drawable icon = manager.getPackageInfo(packageName, 0).applicationInfo.loadIcon(manager);
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            }
        }
        //通过包名,开启这个应用
        Intent intent2 = manager.getLaunchIntentForPackage("包名");
        if(intent2!=null){
            startActivity(intent2);
        }else{
            Toast.makeText(this,"不能启动该应用",Toast.LENGTH_LONG).show();
        }
    }

 

上面在代码中已经说明了BastAdapter的getView方法必须是返回一个布局文件View,但是返回TextView不会报错,返回其他控件就会报错了,那么当listView显示比较复杂的时候,还是使用之前的方法就不太合适了,要是数据还是动态的就更麻烦了,并且当你两个View的布局都是线性布局的时候,convertView instanceof LinearLayout就不能使用了,或许你会使用相对布局,这样确实可以,但是还是不太好吧

所以改进方法如下:

public class MyAdapter extends BaseAdapter {

    @Override
    public int getCount() {
        return 0;
    }

    @Override
    public Object getItem(int position) {
        return null;
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    /**
     * 确定当前adapter中item的view的种类的数量
     */
    @Override
    public int getViewTypeCount() {
        return 2;//默认返回的1,所以只能显示一种布局
    }

    /**
     * 根据position来获得当前的要显示的item的view类型
     */
    @Override
    public int getItemViewType(int position) {
        int type = Integer.parseInt(dataList.get(position).getType());//获取你数据中给的类型
        return type;//getView也就是根据获取这个值来确定要显示哪个布局了
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        int itemViewType = getItemViewType(position);//先获取类型
        ViewHolder1 viewHolder1;
        ViewHolder2 viewHolder2;
        switch (itemViewType) {
            case 0://第一种布局,比如显示图片加文本
                //这里就跟基本的使用差不多了
                break;
            case 1://第二种布局,比如只显示一个图片

                break;
            default:
        }

        return convertView;
    }

    class ViewHolder1 {
        public ImageView imageView;
        public TextView textView;
    }

    class ViewHolder2 {
        public ImageView img;
    }

}

 

posted @ 2016-08-20 23:16  ts-android  阅读(667)  评论(0编辑  收藏  举报