Android 获取并添加 设备上的app

简介

实现内容:点击图片打开一个Dialog,Dialog中显示设备上的app,选中一个添加到RecyclerView中,点击后可以打开app。

1.引入依赖

因为,需要保存数据到数据库,所以这里需要用到Room,在build.gradle
你好

//Room
    implementation 'androidx.room:room-runtime:2.2.5'
    annotationProcessor 'androidx.room:room-compiler:2.2.5'

2.创建实体类、dao和database

2.1 app.java

@Entity
public class App {
    @PrimaryKey(autoGenerate = true)
    public int id;
    @ColumnInfo(defaultValue = "name")
    public String name;
    @ColumnInfo(defaultValue = "icon")
    public String icon;
    @ColumnInfo(defaultValue = "pck")
    public String pck;

    @Override
    public String toString() {
        return "App{" +
                "name='" + name + '\'' +
                ", icon=" + icon +
                ", pck='" + pck + '\'' +
                '}';
    }
}

2.2 AppDao.java

@Dao
public interface AppDao {

    @Insert
    void save(App...app);

    @Query("select * from app")
    List<App> queryAll();
}

2.3 AppDatabase.java

@Database(entities = {App.class},version = 1,exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    public  abstract AppDao appDao();
}

3.创建显示所有App的dialog和对应的RecyclerView适配器

3.1 AppDialog.java

/**
 * 显示设备上所有app的dialog
 */
public class AppDialog extends AlertDialog {

    //设置静态事件
    private static onClickDialog onClickDialog;
    //声明AppDao
    private AppDao appDao;
    //创建onClickDialog接口
    public interface onClickDialog{
        void click(int status);
    }
    //设置一个回调方法
    public void setOnClickApp(onClickDialog onClick){
        this.onClickDialog = onClick;
    }

    public AppDialog(@NonNull Context context) {
        super(context);
        //初始化数据库
        initDatabase();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.app_dialog);

        //绑定UI
        RecyclerView rvc = findViewById(R.id.rvc);
        //获取所有的app集合list
        List<PackageInfo> list = getAllApps(0);
        //声明适配器并传入list集合
        DialogAdapterTest adapter = new DialogAdapterTest(getContext(),list);
        //设置布局,2列,垂直布局
        rvc.setLayoutManager(new GridLayoutManager(getContext(),2,RecyclerView.VERTICAL,false));
        //填入适配器
        rvc.setAdapter(adapter);
    }

    /**
     * 获得所有的APPS
     * @param filter    选择筛选的类型,0,1,2
     * @return  app集合
     */
    @SuppressWarnings("static-access")
    public List<PackageInfo> getAllApps(int filter) {
        List<PackageInfo> apps = new ArrayList<PackageInfo>();
        PackageManager pManager = getContext().getPackageManager();

        // 获取手机内所有应用
        List<PackageInfo> packlist = pManager.getInstalledPackages(0);

        for (int i = 0; i < packlist.size(); i++) {
            PackageInfo pak = (PackageInfo) packlist.get(i);
            String packageName = pak.applicationInfo.packageName;

            switch (filter) {
                case 0:				//所有应用
                    if (!filterErrorPackage(pManager, packageName)) {
                        apps.add(pak);
                    }
                    break;
                case 1:				//第三方应用
                    if ((pak.applicationInfo.flags & pak.applicationInfo.FLAG_SYSTEM) <= 0) {
                        if (!filterErrorPackage(pManager, packageName)) {
                            apps.add(pak);
                        }
                    }
                    break;
                case 2:				//系统自带应用
                    if ((pak.applicationInfo.flags & pak.applicationInfo.FLAG_SYSTEM) != 0) {
                        if (!filterErrorPackage(pManager, packageName)) {
                            apps.add(pak);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
        return apps;
    }

    /**
     * 保存选中的app的对应数据到数据库
     * @param name  app名
     * @param icon  app的icon
     * @param pck   app的包名
     */
    public void go(String name,String icon,String pck){
        App app = new App();
        app.icon = icon;
        app.name = name;
        app.pck =  pck;
        appDao.save(app);
        //回调状态 1
        AppDialog.onClickDialog.click(1);
//        onClickDialog.click(1);
    }


    /**
     * 初始化数据库
     */
    public void initDatabase(){
        AppDatabase database = Room.databaseBuilder(getContext(),
                        AppDatabase.class,
                        "app")
                .allowMainThreadQueries()
                .build();
        appDao = database.appDao();
    }

    /**
     * 判断当前包是否可以打开
     * @return
     */
    public boolean filterErrorPackage(PackageManager pManager, String packageName) {
        Intent intent = new Intent();
        intent = pManager.getLaunchIntentForPackage(packageName);

        //如果该程序不可启动(像系统自带的包,有很多是没有入口的)会返回NULL
        if (intent == null) {
            return true;
        }

        return false;

    }
}

3.2 app_dialog.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:layout_gravity="center">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

3.3 DialogAdapterTest.java

/**
 * AppDialog的RecyclerView适配器
 */
public class DialogAdapterTest extends RecyclerView.Adapter<DialogAdapterTest.MyHolder> {

    private Context mContext;
    private List<PackageInfo> mList = new ArrayList<>();
    private PackageManager pm = null;
    private AppDialog appDialog;

    public DialogAdapterTest(Context context, List<PackageInfo> list) {
        this.mContext = context;
        this.mList = list;
        //通知刷新数据
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public DialogAdapterTest.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(mContext).inflate(R.layout.item_list, null);
        pm = mContext.getPackageManager();
        DialogAdapterTest.MyHolder myHolder = new MyHolder(view);
        return myHolder;
    }

	//可能int position下会冒红线,在 @Override上面加上这个就行了 -> @SuppressLint("RecyclerView")
    @Override
    public void onBindViewHolder(@NonNull DialogAdapterTest.MyHolder holder, int position) {

        holder.iv_image.setImageDrawable(pm.getApplicationIcon(mList.get(position).applicationInfo));
        holder.tv_text.setText(pm.getApplicationLabel(mList.get(position).applicationInfo));

        //app点击事件
        holder.iv_image.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                appDialog = new AppDialog(mContext);
                //调用appDialog的go方法存入app名、图片、包名到数据库
                appDialog.go(
                        (String) pm.getApplicationLabel(mList.get(position).applicationInfo),
                        DrawableToString(pm.getApplicationIcon(mList.get(position).applicationInfo)),
                        mList.get(position).applicationInfo.packageName
                );
            }
        });
    }

    @Override
    public int getItemCount() {
        return mList.size();
    }

    /**
     * 内部类MyHolder,声明和绑定iv_image,tv_text
     */
    public static class MyHolder extends RecyclerView.ViewHolder {

        ImageView iv_image;
        TextView tv_text;

        public MyHolder(@NonNull View itemView) {
            super(itemView);
            iv_image = itemView.findViewById(R.id.iv_image);
            tv_text = itemView.findViewById(R.id.tv_text);

        }
    }

    /**
     * 将drawable转化成字符串
     * @param drawable  要转换成String类型的Drawable文件
     * @return
     */
    public synchronized static String DrawableToString(Drawable drawable) {
        if (drawable != null) {
            Bitmap bitmap = Bitmap
                    .createBitmap(
                            drawable.getIntrinsicWidth(),
                            drawable.getIntrinsicHeight(),
                            drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888
                                    : Bitmap.Config.ARGB_8888);
            Canvas canvas = new Canvas(bitmap);
            drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
                    drawable.getIntrinsicHeight());
            drawable.draw(canvas);
            int size = bitmap.getWidth() * bitmap.getHeight() * 4;

            // 创建一个字节数组输出流,流的大小为size
            ByteArrayOutputStream baos = new ByteArrayOutputStream(size);
            // 设置位图的压缩格式,质量为100%,并放入字节数组输出流中
            bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
            // 将字节数组输出流转化为字节数组byte[]
            byte[] imagedata = baos.toByteArray();

            return Base64.encodeToString(imagedata, Base64.DEFAULT);
        }
        return " ";
    }
}

4.创建主页面和对应的适配器

4.1创建主页面AddAppActivity .java

/**
 * 主页面
 */
public class AddAppActivity extends AppCompatActivity {

    //声明AppDao
    private AppDao appDao;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_app);
        initDatabase();

        //绑定UI
        RecyclerView app = findViewById(R.id.app);
        //声明adapter
        MainAdapterTest adapter = new MainAdapterTest(this);
        //查询数据库传入App的集合
        adapter.setAppList(appDao.queryAll());
        //设置布局,2列,垂直布局
        app.setLayoutManager(new GridLayoutManager(this,2,RecyclerView.VERTICAL,false));
        //填入适配器
        app.setAdapter(adapter);
    }

    /**
     * 初始化数据库
     */
    public void initDatabase(){
        AppDatabase database = Room.databaseBuilder(this,
                AppDatabase.class,
                "app")
                .allowMainThreadQueries()
                .build();
        appDao = database.appDao();
    }
}

4.2 activity_add_app.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".AddAppActivity">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/app"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
</LinearLayout>

4.3 MainAdapterTest.java

/**
 * AddAppActivity的RecyclerView的适配器
 */
public class MainAdapterTest extends RecyclerView.Adapter<MainAdapterTest.MyHolder> {

    //声明上下文
    private Context mContext;
    //声明一个App的list集合
    private List<App> appList = new ArrayList<>();
    //声明包管理器
    private PackageManager packageManager = null;
    //声明AppDao
    private AppDao appDao;

    public MainAdapterTest(Context context) {
        this.mContext = context;
        initDatabase();
    }

    public void setAppList(List<App> list){
        this.appList = list;
        Log.d("TAG", "当前app数量: " + list.size());
        //通知刷新数据
        notifyDataSetChanged();
    }

    @NonNull
    @Override
    public MainAdapterTest.MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

        packageManager = mContext.getPackageManager();
        View view;
        switch (viewType) {
            case 0:
                //添加应用的view
                view = LayoutInflater.from(mContext).inflate(R.layout.item_list, null);
                break;

            case 1:
                //打开应用的view
                view = LayoutInflater.from(mContext).inflate(R.layout.item_list_add, null);
                break;
            default:
                view = LayoutInflater.from(mContext).inflate(R.layout.item_list_add, null);
        }

        MainAdapterTest.MyHolder myHolder = new MyHolder(view);
        return myHolder;
    }
    //可能int position下会冒红线,在 @Override上面加上这个就行了 -> @SuppressLint("RecyclerView")
    @Override
    public void onBindViewHolder(@NonNull MainAdapterTest.MyHolder holder,  int position) {

        //appList有数据时,设置对应app的文字和图片
        if (getItemViewType(position) == 1) {
            holder.iv_image.setImageDrawable(StringToDrawable(appList.get(position).icon));
            holder.tv_text.setText(appList.get(position).name);

            //对应app的点击事件
            holder.iv_image.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //打开对应的app
                    startAPK(appList.get(position).pck);
                }
            });
        } else {
            //添加app的点击事件
            holder.iv_image.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    //声明AppDialog
                    AppDialog dialog = new AppDialog(mContext);
                    //显示dialog
                    dialog.show();
                    //AppDialog的回调事件
                    dialog.setOnClickApp(new AppDialog.onClickDialog() {
                        @Override
                        public void click(int status) {
                            if (status!=0){
                                //查询保存到数据库的所有App
                                setAppList(appDao.queryAll());
                                //关闭dialog
                                dialog.dismiss();
                            }
                        }
                    });
                }
            });
        }


    }

    @Override
    public int getItemViewType(int position) {
        //未添加app时返回0
        if (appList == null || appList.size() == 0 || position == appList.size()) return 0;
        return 1;
    }

    @Override
    public int getItemCount() {
        //未添加app时设置appList.size()为1,添加过则始终+1,保证加号存在
        return appList == null ? 1 : appList.size() + 1;
    }

    /**
     * 内部类MyHolder,声明和绑定iv_image,tv_text
     */
    public static class MyHolder extends RecyclerView.ViewHolder {

        ImageView iv_image;
        TextView tv_text;
        public MyHolder(@NonNull View itemView) {
            super(itemView);
            iv_image = itemView.findViewById(R.id.iv_image);
            tv_text = itemView.findViewById(R.id.tv_text);

        }
    }

    /**
     * 根据包名打开第三方app
     * @param pck   包名
     */
    private void startAPK(String pck){
        if (packageManager!=null){
            Intent intent = packageManager.getLaunchIntentForPackage(pck);
            if (intent != null){
                try {
                    mContext.getApplicationContext().startActivity(intent);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 初始化数据库
     */
    public void initDatabase() {
        AppDatabase database = Room.databaseBuilder(mContext,
                        AppDatabase.class,
                        "app")
                .allowMainThreadQueries()
                .build();
        appDao = database.appDao();
    }

    /**
     * 将字符串转化成Drawable
     * @param icon  要转换成Drawable类型的String字符串
     * @return  Drawable类型
     */
    public synchronized static Drawable StringToDrawable(String icon) {
        if (icon == null || icon.length() < 10)
            return null;
        byte[] img = Base64.decode(icon.getBytes(), Base64.DEFAULT);
        Bitmap bitmap;
        if (img != null) {
            bitmap = BitmapFactory.decodeByteArray(img, 0, img.length);
            @SuppressWarnings("deprecation")
            Drawable drawable = new BitmapDrawable(bitmap);

            return drawable;
        }
        return null;
    }
}

4.4 item_list_add.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    android:gravity="center_horizontal">

    <ImageView
        android:id="@+id/iv_image"
        android:layout_width="50dp"
        android:background="@color/black"
        android:layout_height="50dp"/>

    <TextView
        android:id="@+id/tv_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/black"/>
</LinearLayout>

(两个适配器用的item_list.xml是同一个 ) (^_^)

5.备忘录

如果是直接以创建Java 文件的形式创建AddAppActivity,不要忘记去Androidmanifest.xml里去注册你的Activity
你好啊

		<activity
            android:name=".AddAppActivity"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

6.结果展示

你好啊

7.参考(抄袭)链接

gaosunqiong大佬的在 Dialog中显示所有应用程序

灬布衣丶公爵丨大佬的 Android–字符串和Drawable之间互相转化

8.补充、拓展

当然啦,你可以在添加app的时候根据该app的包名对数据库进行查询,如果已保存过这个app,则返回,不进行添加,并使用吐司弹出 “该app以添加” 的提示框

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值