不要再用onActivityResult了,用更高級更方便的。
啟動一個activity需要一個laucher,這個laucher由registerForActivityResult返回,這個方法需要兩個參數,一個參數為一個抽象類——ActivityResultContract<I, O>的實現,另一個參數是一個函數式接口的實現(用一個lambda表達式來代替)。
第一個參數要實現兩個方法:
public abstract class ActivityResultContract<I, O> { /** Create an intent that can be used for {@link Activity#startActivityForResult} */ public abstract @NonNull Intent createIntent(@NonNull Context context, @SuppressLint("UnknownNullness") I input); /** Convert result obtained from {@link Activity#onActivityResult} to O */ @SuppressLint("UnknownNullness") public abstract O parseResult(int resultCode, @Nullable Intent intent);
第一個方法是配置結合input配置intent, 第二個方法是從intent取出數據返回。
第二個參數是對從intent取出的數據的處理。
技巧:官方為我們提供了很多便捷的實現好的第一個參數:
預定義的Contract 大伙都看出來,新的Activity Results API使用起來好像有點麻煩,每次都得定義Contract。Google肯定考慮到了這個問題的,於是,Google 預定義了很多Contract,
把你們能想到的使用場景基本上都想到了,它們都定義在類ActivityResultContracts中,有以下這些Contract: StartActivityForResult() RequestMultiplePermissions() RequestPermission() TakePicturePreview() TakePicture() TakeVideo() PickContact() CreateDocument() OpenDocumentTree() OpenMultipleDocuments() OpenDocument() GetMultipleContents() GetContent() 下面分別介紹一下這些Contract: StartActivityForResult: 通用的Contract,不做任何轉換,Intent作為輸入,ActivityResult作為輸出,這也是最常用的一個協定。 RequestMultiplePermissions: 用於請求一組權限 RequestPermission: 用於請求單個權限 TakePicturePreview: 調用MediaStore.ACTION_IMAGE_CAPTURE拍照,返回值為Bitmap圖片 TakePicture: 調用MediaStore.ACTION_IMAGE_CAPTURE拍照,並將圖片保存到給定的Uri地址,返回true表示保存成功。 TakeVideo: 調用MediaStore.ACTION_VIDEO_CAPTURE 拍攝視頻,保存到給定的Uri地址,返回一張縮略圖。 PickContact: 從通訊錄APP獲取聯系人 GetContent: 提示用選擇一條內容,返回一個通過ContentResolver#openInputStream(Uri)訪問原生數據的Uri地址(content://形式) 。默認情況下,它增加了Intent#CATEGORY_OPENABLE, 返回可以表示流的內容。 CreateDocument: 提示用戶選擇一個文檔,返回一個(file:/http:/content:)開頭的Uri。 OpenMultipleDocuments: 提示用戶選擇文檔(可以選擇多個),分別返回它們的Uri,以List的形式。 OpenDocumentTree: 提示用戶選擇一個目錄,並返回用戶選擇的作為一個Uri返回,應用程序可以完全管理返回目錄中的文檔。
具體可參考:https://developer.android.com/reference/androidx/activity/result/contract/ActivityResultContracts
比如說,打開聯系人列表選擇一個聯系人的ActivityResultContracts的實現為:
/** * An {@link ActivityResultContract} to request the user to pick a contact from the contacts * app. * <p> * The result is a {@code content:} {@link Uri}. * * @see ContactsContract */ public static final class PickContact extends ActivityResultContract<Void, Uri> { @NonNull @Override public Intent createIntent(@NonNull Context context, @Nullable Void input) { return new Intent(Intent.ACTION_PICK).setType(ContactsContract.Contacts.CONTENT_TYPE); } @Nullable @Override public Uri parseResult(int resultCode, @Nullable Intent intent) { if (intent == null || resultCode != Activity.RESULT_OK) return null; return intent.getData(); } }
附上一個實例:
private val aLauncher = registerForActivityResult(ActivityResultContracts.PickContact()) { uri: Uri? -> // Handle the returned Uri //crimesuspect啟動activity的注冊laucher val queryFields = arrayOf(ContactsContract.Contacts.DISPLAY_NAME) val cursor = uri?.let { requireActivity().contentResolver.query( it, queryFields, null, null, null ) } cursor?.use { if (it.count > 0) { it.moveToFirst() val suspect = it.getString(0) crime.suspect = suspect crimeDetailViewModel.saveCrime(crime) binding.crimeSuspect.text = suspect } } }
設置監聽器的時候:binding.crimeSuspect.setOnClickListener {
aLauncher.launch()
}
