Android 自定义应用选择器对话框
Android 自定义应用选择器对话框
- 一、获取可处理 `ACTION_VIEW` 的应用列表
- 二、显示应用列表对话框
- 三、自定义布局
- 四、示例代码
- 五、总结
一、获取可处理 ACTION_VIEW
的应用列表
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 neededPackageManager packageManager = context.getPackageManager();return packageManager.queryIntentActivities(intent, 0);
}
二、显示应用列表对话框
创建并显示一个对话框,其中包含应用列表。
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())) {@Overridepublic 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
:
Uri fileUri = Uri.parse("file://path/to/your/file"); // Adjust the file path
showAppChooserDialog(this, fileUri);
说明
- 自定义对话框:使用
AlertDialog
来创建一个应用选择对话框。 - 列表适配器:
ArrayAdapter
用于显示应用名称和图标。 - 启动选定应用:用户选择应用后,启动对应的应用来处理文件。
fileUri
:替换为实际需要打开的文件 URI。
三、自定义布局
创建一个布局文件 app_item.xml
,包含 ImageView
和 TextView
:
<!-- 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"><ImageViewandroid:id="@+id/app_icon"android:layout_width="40dp"android:layout_height="40dp"android:layout_marginEnd="8dp" /><TextViewandroid:id="@+id/app_name"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center_vertical"android:textSize="16sp" />
</LinearLayout>
自定义适配器
创建自定义适配器 AppListAdapter
:
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@Overridepublic 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;}
}
显示对话框
在你的活动或片段中使用自定义适配器:
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
包含ImageView
和TextView
。 - 自定义适配器:
AppListAdapter
负责为每个应用加载图标和名称。 - 对话框背景:使用
setBackgroundDrawableResource()
设置对话框背景颜色。你可以根据需要替换为其他颜色资源。
在 Android 中,当使用 Intent.createChooser()
创建一个应用选择器(chooser)时,系统不会自动为传入的 Intent
设置 setPackage()
。
详细解释:
Intent.createChooser()
的行为:- 当调用
Intent.createChooser()
时,系统会弹出一个对话框,显示所有能够处理该Intent
的应用程序列表。 - 用户选择一个应用后,系统会将该应用的信息(如其包名)与原始
Intent
结合,启动该应用来处理Intent
。
- 当调用
- 是否自动设置
setPackage()
:- 系统并不会自动为原始的
Intent
添加setPackage()
。 - 系统会临时将用户选择的应用与
Intent
绑定,但不会直接修改或传递setPackage()
的值到原始Intent
中。 - 如果你需要显式指定
setPackage()
,需要在代码中自己设置它。
- 系统并不会自动为原始的
- 为什么
setPackage()
很重要:- 使用
setPackage()
可以强制指定某个应用来处理Intent
,避免系统显示多个应用选择器。 - 如果使用了
Intent.createChooser()
,setPackage()
通常不需要,因为用户会手动选择应用。
- 使用
四、示例代码
以下是一个使用 Intent.createChooser()
的示例:
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()
,如下所示:
intent.setPackage("com.example.specificapp"); // 替换为目标应用的包名
startActivity(intent);
这样会直接跳转到指定应用,而不会弹出应用选择器。
五、总结
- 默认行为:
Intent.createChooser()
不会自动为Intent
添加setPackage()
。 - 临时绑定:系统会根据用户选择的应用临时绑定
Intent
与目标应用。 - 手动指定:如果需要某个特定应用处理
Intent
,需要显式调用setPackage()
。