Android 自定义应用选择器对话框

Android 自定义应用选择器对话框

一、获取可处理 ACTION_VIEW 的应用列表

java 复制代码
public List<ResolveInfo> getAppsForActionView(Context context, Uri fileUri) {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setData(fileUri);
    intent.setType("*/*"); // Adjust the MIME type as needed

    PackageManager packageManager = context.getPackageManager();
    return packageManager.queryIntentActivities(intent, 0);
}

二、显示应用列表对话框

创建并显示一个对话框,其中包含应用列表。

java 复制代码
public void showAppChooserDialog(Context context, Uri fileUri) {
    List<ResolveInfo> apps = getAppsForActionView(context, fileUri);
    PackageManager packageManager = context.getPackageManager();

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("Select an application");

    ListAdapter adapter = new ArrayAdapter<String>(
        context,
        android.R.layout.select_dialog_item,
        apps.stream().map(info -> info.loadLabel(packageManager).toString()).collect(Collectors.toList())
    ) {
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view = super.getView(position, convertView, parent);
            TextView text = view.findViewById(android.R.id.text1);
            text.setCompoundDrawablesWithIntrinsicBounds(
                apps.get(position).loadIcon(packageManager),
                null, null, null
            );
            text.setCompoundDrawablePadding(16);
            return view;
        }
    };

    builder.setAdapter(adapter, (dialog, which) -> {
        ResolveInfo selectedApp = apps.get(which);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(fileUri);
        intent.setType("*/*");
        intent.setPackage(selectedApp.activityInfo.packageName);
        context.startActivity(intent);
    });

    builder.show();
}

使用方法

调用 showAppChooserDialog 方法并传递文件的 Uri:

java 复制代码
Uri fileUri = Uri.parse("file://path/to/your/file"); // Adjust the file path
showAppChooserDialog(this, fileUri);

说明

  • 自定义对话框 :使用 AlertDialog 来创建一个应用选择对话框。
  • 列表适配器ArrayAdapter 用于显示应用名称和图标。
  • 启动选定应用:用户选择应用后,启动对应的应用来处理文件。
  • fileUri:替换为实际需要打开的文件 URI。

三、自定义布局

创建一个布局文件 app_item.xml,包含 ImageViewTextView

xml 复制代码
<!-- res/layout/app_item.xml -->
<LinearLayout xmlns:android="<http://schemas.android.com/apk/res/android>"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="horizontal"
    android:padding="8dp">

    <ImageView
        android:id="@+id/app_icon"
        android:layout_width="40dp"
        android:layout_height="40dp"
        android:layout_marginEnd="8dp" />

    <TextView
        android:id="@+id/app_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:textSize="16sp" />
</LinearLayout>

自定义适配器

创建自定义适配器 AppListAdapter

java 复制代码
public class AppListAdapter extends ArrayAdapter<ResolveInfo> {
    private final List<ResolveInfo> apps;
    private final PackageManager packageManager;
    private final int resource;

    public AppListAdapter(Context context, int resource, List<ResolveInfo> apps) {
        super(context, resource, apps);
        this.apps = apps;
        this.packageManager = context.getPackageManager();
        this.resource = resource;
    }

    @NonNull
    @Override
    public View getView(int position, View convertView, @NonNull ViewGroup parent) {
        if (convertView == null) {
            convertView = LayoutInflater.from(getContext()).inflate(resource, parent, false);
        }

        ResolveInfo appInfo = apps.get(position);

        ImageView appIcon = convertView.findViewById(R.id.app_icon);
        TextView appName = convertView.findViewById(R.id.app_name);

        appIcon.setImageDrawable(appInfo.loadIcon(packageManager));
        appName.setText(appInfo.loadLabel(packageManager));

        return convertView;
    }
}

显示对话框

在你的活动或片段中使用自定义适配器:

java 复制代码
public void showAppChooserDialog(Context context, Uri fileUri) {
    List<ResolveInfo> apps = getAppsForActionView(context, fileUri);

    AppListAdapter adapter = new AppListAdapter(context, R.layout.app_item, apps);

    AlertDialog.Builder builder = new AlertDialog.Builder(context);
    builder.setTitle("Select an application");
    builder.setAdapter(adapter, (dialog, which) -> {
        ResolveInfo selectedApp = apps.get(which);
        Intent intent = new Intent(Intent.ACTION_VIEW);
        intent.setData(fileUri);
        intent.setType("*/*");
        intent.setPackage(selectedApp.activityInfo.packageName);
        context.startActivity(intent);
    });

    AlertDialog dialog = builder.create();
    dialog.show();

    // 设置对话框背景
    dialog.getWindow().setBackgroundDrawableResource(android.R.color.background_light);
}

说明

  • 自定义布局app_item.xml 包含 ImageViewTextView
  • 自定义适配器AppListAdapter 负责为每个应用加载图标和名称。
  • 对话框背景 :使用 setBackgroundDrawableResource() 设置对话框背景颜色。你可以根据需要替换为其他颜色资源。

在 Android 中,当使用 Intent.createChooser() 创建一个应用选择器(chooser)时,系统不会自动为传入的 Intent 设置 setPackage()

详细解释:

  1. Intent.createChooser() 的行为
    • 当调用 Intent.createChooser() 时,系统会弹出一个对话框,显示所有能够处理该 Intent 的应用程序列表。
    • 用户选择一个应用后,系统会将该应用的信息(如其包名)与原始 Intent 结合,启动该应用来处理 Intent
  2. 是否自动设置 setPackage()
    • 系统并不会自动为原始的 Intent 添加 setPackage()
    • 系统会临时将用户选择的应用与 Intent 绑定,但不会直接修改或传递 setPackage() 的值到原始 Intent 中。
    • 如果你需要显式指定 setPackage(),需要在代码中自己设置它。
  3. 为什么 setPackage() 很重要
    • 使用 setPackage() 可以强制指定某个应用来处理 Intent,避免系统显示多个应用选择器。
    • 如果使用了 Intent.createChooser()setPackage() 通常不需要,因为用户会手动选择应用。

四、示例代码

以下是一个使用 Intent.createChooser() 的示例:

java 复制代码
Intent intent = new Intent(Intent.ACTION_SEND);
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "Hello, World!");

// 创建一个 chooser
Intent chooser = Intent.createChooser(intent, "Choose an app");
startActivity(chooser);
  • 在这里,系统不会为 intent 添加 setPackage(),而是根据用户选择的应用临时处理。

如果需要手动设置 setPackage()

如果你需要显式指定某个应用,可以在 Intent 上调用 setPackage(),如下所示:

java 复制代码
intent.setPackage("com.example.specificapp"); // 替换为目标应用的包名
startActivity(intent);

这样会直接跳转到指定应用,而不会弹出应用选择器。


五、总结

  • 默认行为Intent.createChooser() 不会自动为 Intent 添加 setPackage()
  • 临时绑定 :系统会根据用户选择的应用临时绑定 Intent 与目标应用。
  • 手动指定 :如果需要某个特定应用处理 Intent,需要显式调用 setPackage()
相关推荐
2501_9160088921 小时前
Web 前端开发常用工具推荐与团队实践分享
android·前端·ios·小程序·uni-app·iphone·webview
我科绝伦(Huanhuan Zhou)1 天前
MySQL一键升级脚本(5.7-8.0)
android·mysql·adb
怪兽20141 天前
Android View, SurfaceView, GLSurfaceView 的区别
android·面试
龚礼鹏1 天前
android 图像显示框架二——流程分析
android
消失的旧时光-19431 天前
kmp需要技能
android·设计模式·kotlin
帅得不敢出门1 天前
Linux服务器编译android报no space left on device导致失败的定位解决
android·linux·服务器
雨白1 天前
协程间的通信管道 —— Kotlin Channel 详解
android·kotlin
TimeFine1 天前
kotlin协程 容易被忽视的CompletableDeferred
android
czhc11400756631 天前
Linux1023 mysql 修改密码等
android·mysql·adb
GOATLong1 天前
MySQL内置函数
android·数据库·c++·vscode·mysql