MASA MAUI Plugin (九)Android相簿多選照片(使用Android Jetpack套件庫)
背景
MAUI的出現,賦予了廣大.Net開發者開發多平臺應用的能力,MAUI 是Xamarin.Forms演變而來,但是相比Xamarin效能更好,可擴充套件性更強,結構更簡單。但是MAUI對於平臺相關的實現並不完整。所以MASA團隊開展了一個實驗性專案,意在對微軟MAUI的補充和擴充套件
專案地址http://github.com/BlazorComponent/MASA.Blazor/tree/feature/Maui/src/Masa.Blazor.Maui.Plugin
每個功能都有單獨的demo演示專案,考慮到app安裝檔案體積(雖然MAUI已經整合裁剪功能,但是該功能對於程式碼本身有影響),屆時每一個功能都會以單獨的nuget包的形式提供,方便測試,現在專案才剛剛開始,但是相信很快就會有可以交付的內容啦。
前言
本系列文章面向移動開發小白,從零開始進行平臺相關功能開發,演示如何參考平臺的官方文件使用MAUI技術來開發相應功能。
介紹
Jetpack 包含一系列 Android 庫,它們都採用最佳做法並在 Android 應用中提供向後相容性。
上一篇我們是通過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 select
ActivityResultLauncher<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>
三、演示效果
注意介面的變化,這裡是以半屏彈出的方式展示的。
- Blazor在IoT領域的前端實踐 @.NET開發者日
- MASA MAUI Plugin (十)iOS訊息推送(原生APNS方式)
- MASA MAUI Plugin (九)Android相簿多選照片(使用Android Jetpack套件庫)
- MASA MAUI Plugin (八)Android相簿多選照片(Intent 方式)
- MASA Stack 1.0 釋出會講稿——生態篇
- MASA Stack 1.0 釋出會講稿——實踐篇
- MASA Stack 1.0 釋出會講稿——產品篇
- MASA Stack 1.0 釋出會講稿——趨勢篇
- MASA MAUI Plugin (七)應用通知角標(小紅點)Android iOS
- .NET現代化應用開發 - CQRS&類目管理程式碼剖析
- MASA MAUI Plugin 安卓藍芽低功耗(二)藍芽通訊
- MASA MAUI Plugin 安卓藍芽低功耗(一)藍芽掃描
- MASA MAUI Plugin 安卓藍芽低功耗(二)藍芽通訊
- MASA MAUI Plugin 安卓藍芽低功耗(一)藍芽掃描
- MASA Framework的分散式鎖設計
- MAUI Masa Blazor 開發介面跟隨系統主題切換的App
- MAUI Masa Blazor 開發介面跟隨系統主題切換的App
- MAUI Masa Blazor 開發帶自動更新功能的安卓App
- 開篇-開啟全新的.NET現代應用開發體驗
- 怎麼樣的框架對於開發者是友好的?