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 needed
PackageManager 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())
) {
@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
:
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">
<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
:
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;
}
}
显示对话框
在你的活动或片段中使用自定义适配器:
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()
。