写点什么

MASA MAUI Plugin (九)Android 相册多选照片(使用 Android Jetpack 套件库)

  • 2023-03-01
    浙江
  • 本文字数:4004 字

    阅读完需:约 13 分钟

背景

MAUI 的出现,赋予了广大.Net 开发者开发多平台应用的能力,MAUI 是 Xamarin.Forms 演变而来,但是相比 Xamarin 性能更好,可扩展性更强,结构更简单。但是 MAUI 对于平台相关的实现并不完整。所以 MASA 团队开展了一个实验性项目,意在对微软 MAUI 的补充和扩展


项目地址https://github.com/BlazorComponent/MASA.Blazor/tree/feature/Maui/src/Masa.Blazor.Maui.Plugin


每个功能都有单独的 demo 演示项目,考虑到 app 安装文件体积(虽然 MAUI 已经集成裁剪功能,但是该功能对于代码本身有影响),届时每一个功能都会以单独的 nuget 包的形式提供,方便测试,现在项目才刚刚开始,但是相信很快就会有可以交付的内容啦。

前言

本系列文章面向移动开发小白,从零开始进行平台相关功能开发,演示如何参考平台的官方文档使用 MAUI 技术来开发相应功能。

介绍

Jetpack 包含一系列 Android 库,它们都采用最佳做法并在 Android 应用中提供向后兼容性。


https://developer.android.google.cn/jetpack?hl=zh-cn


上一篇我们是通过 Intent 实现的,今天我们用 Jetpack 实现相册的多选功能。

一、实现方式

可以使用以下 activity 结果协定来启动照片选择器: PickVisualMedia,用于选择单张图片或单个视频。 PickMultipleVisualMedia,用于选择多张图片或多个视频。 我们的需求是可以多选照片,我们主要介绍 PickMultipleVisualMedia 的使用方法。 我们先看一下 JAVA 的示例代码


JAVA代码// Registering Photo Picker activity launcher with multiple selects (5 max in this example)ActivityResultLauncher<PickVisualMediaRequest> pickMultipleMedia =        registerForActivityResult(new PickMultipleVisualMedia(5), uris -> {    // Callback is invoked after the user selects media items or closes the    // photo picker.    if (!uris.isEmpty()) {        Log.d("PhotoPicker", "Number of items selected: " + uris.size());    } else {        Log.d("PhotoPicker", "No media selected");    }});
// For this example, launch the photo picker and allow the user to choose images// and videos. If you want the user to select a specific type of media file,// use the overloaded versions of launch(), as shown in the section about how// to select a single media item.pickMultipleMedia.launch(new PickVisualMediaRequest.Builder() .setMediaType(PickVisualMedia.ImageAndVideo.INSTANCE) .build());
复制代码


这里先介绍一下 registerForActivityResult


在 Android 中启动另一个 activity(无论是您应用中的 activity 还是其他应用中的 activity)不一定是单向操作。我们需要获取 activity 的返回结果。这里我们就是启动了相册,并获取用户选取照片的返回结果。其他例如打开相机获取拍照结果,打开通讯录获取联系人结果都是具体的应用场景。

虽然所有 API 级别的 Activity 类均提供底层 startActivityForResult() 和 onActivityResult() API,但 Android 官方强烈建议使用 AndroidX Activity 和 Fragment 中引入的 Activity Result API。 Activity Result API 提供了用于注册结果、启动结果以及在系统分派结果后对其进行处理的组件。 在启动 activity 以获取结果时,可能会出现您的进程和 activity 因内存不足而被销毁的情况;如果是使用相机等内存密集型操作,几乎可以确定会出现这种情况。 因此,Activity Result API 会将结果回调从您之前启动另一个 activity 的代码位置分离开来。由于在重新创建进程和 activity 时需要使用结果回调,因此每次创建 activity 时都必须无条件注册回调,即使启动另一个 activity 的逻辑仅基于用户输入内容或其他业务逻辑也是如此。


位于 ComponentActivity 或 Fragment 中时,Activity Result API 会提供 registerForActivityResult() API,用于注册结果回调。registerForActivityResult() 接受 ActivityResultContract 和 ActivityResultCallback 作为参数,并返回 ActivityResultLauncher,用来启动另一个 activity。 ActivityResultContract 定义生成结果所需的输入类型以及结果的输出类型。这些 API 可为拍照和请求权限等基本 intent 操作提供默认协定。当然也可以创建自己的自定义协定。 ActivityResultCallback 是单一方法接口,带有 onActivityResult() 方法,可接受 ActivityResultContract 中定义的输出类型的对象:


JAVA代码// GetContent creates an ActivityResultLauncher<String> to allow you to pass// in the mime type you'd like to allow the user to selectActivityResultLauncher<String> mGetContent = registerForActivityResult(new GetContent(),    new ActivityResultCallback<Uri>() {        @Override        public void onActivityResult(Uri uri) {            // Handle the returned Uri        }});
复制代码


这里的代码看起来很简单,我们只需要在 registerForActivityResult 的第二个参数中 new 一个 ActivityResultCallback 并重写 onActivityResult 方法即可实现获取用户操作返回的需求。但是目前在 MAUI 中实现并非如此简单,因为 MAUI 中没有定义好的 ActivityResultCallback 类。下面我们来编写代码。

二、代码编写

1、实现代码

在上文代码的基础上,我们继续在 MainActivity.cs 添加代码

    public class MainActivity : MauiAppCompatActivity    {        internal static MainActivity Instance { get; private set; }        internal static ActivityResultLauncher PickMultipleMedia { get; private set; }
public TaskCompletionSource<Dictionary<string, string>> PickImageTaskCompletionSource { set; get; } protected override void OnCreate(Bundle savedInstanceState) { Instance = this; PickMultipleMedia = Instance.RegisterForActivityResult(new ActivityResultContracts.PickMultipleVisualMedia(100), new ActivityResultCallback()); base.OnCreate(savedInstanceState); }
private class ActivityResultCallback : Java.Lang.Object, IActivityResultCallback { public void OnActivityResult(Java.Lang.Object p0) { if (!p0.Equals(new Android.Runtime.JavaList())) { var list = (Android.Runtime.JavaList)p0; if (!list.IsEmpty) { var uris = list.Cast<Uri>().ToList();
var fileList = Instance.GetImageDicFromUris(uris); Instance.PickImageTaskCompletionSource.SetResult(fileList); } else { Instance.PickImageTaskCompletionSource.SetResult(new Dictionary<string, string>()); } } } } }
复制代码


我们创建了一个静态的 ActivityResultLauncher 类型的 PickMultipleMedia,并在 OnCreate 方法中通过 RegisterForActivityResult 注册,方法第一个参数类型为 ActivityResultContract,我们设置了 100 个图片的限制,第二个参数是一个 IActivityResultCallback 类型的 Callback。由于默认没有提供,我们需要自己定义。 注意:我们的 callback 方法在继承 IActivityResultCallback 接口的同时,还必须显示的继承 Java.Lang.Object,否则会报错。 我们仅需实现 OnActivityResult 方法即可,这里注意,方法的参数为 Java.Lang.Object 类型,有些文章会让我们将 Java.Lang.Object 强制转换为 ActivityResult 类型,然后再获取其中的文件 Uri,但是经过测试目前在 MAUI 中不可用,转换之后永远为 null。经过多次尝试后,确定多选照片返回的类型为 Android.Runtime.JavaList。 我这里通过 !p0.Equals(new Android.Runtime.JavaList()) 判断用户没有选择任何照片的场景。最后通过遍历,使用之前写好的 GetImageDicFromUris 方法获取所有文件的内容。

2、测试代码

我们在上文的 IPhotoPickerService.cs 接口中扩展一个 GetImageAsync4 方便我们对几种实现方式进行对比。

    public class AndroidPhotoPickerService : IPhotoPickerService    {        ...        public Task<Dictionary<string, string>> GetImageAsync4()        {            MainActivity.PickMultipleMedia.Launch(new PickVisualMediaRequest.Builder()                .SetMediaType(ActivityResultContracts.PickVisualMedia.ImageAndVideo.Instance).Build());            MainActivity.Instance.PickImageTaskCompletionSource = new TaskCompletionSource<Dictionary<string, string>>();                       return MainActivity.Instance.PickImageTaskCompletionSource.Task;        }    }
复制代码

这里使用的方法非常简单,参考上面 JAVA 的写法即可

JAVA代码pickMultipleMedia.launch(new PickVisualMediaRequest.Builder()        .setMediaType(PickVisualMedia.ImageAndVideo.INSTANCE)        .build());
复制代码

在 Index.razor 中添加一个 MListItem

<MList> ...       <MListItem OnClick="GetImageAsync4">		       <MListItemContent>		                   <MListItemTitle>Jetpack-PickMultipleVisualMedia</MListItemTitle>		       </MListItemContent>       </MListItem></MList>
复制代码

三、演示效果


 注意界面的变化,这里是以半屏弹出的方式展示的。


如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们

WeChat:MasaStackTechOps

QQ:7424099

发布于: 刚刚阅读数: 3
用户头像

还未添加个人签名 2021-10-26 加入

MASA技术团队官方账号,我们专注于.NET现代应用开发解决方案,Wechat:MasaStackTechOps ,Website:www.masastack.com

评论

发布
暂无评论
MASA MAUI Plugin (九)Android相册多选照片(使用Android Jetpack套件库)_.net_MASA技术团队_InfoQ写作社区