內容目錄
概述
早期我們會用 startActivityForResult() 配合 onActivityResult() 來取得其他 Activity 的結果,但是這種方式有很多的缺點,例如:耦合嚴重、要定義 RequestCode 常數、難以維護…等,所以 Google 推出了新的 Activity Result API 來改善這狀況。
Activity Result API 的主要元件
ActivityResultContract
這是一個抽象類別,我們必須繼承它來定義如何傳遞資料及處理回傳資料 (也就是輸入和輸出),但是 Google 已經幫我們定義好一些常用的類別,通常我們可以直接拿來使用,例如:
ActivityResultContracts.TakePicture 使用相機取得影像
從原始碼可以知道輸入型別為 Uri,輸出(回傳) 的型別為 Boolean
open class TakePicture : ActivityResultContract<Uri, Boolean>() { @CallSuper override fun createIntent(context: Context, input: Uri): Intent { return Intent(MediaStore.ACTION_IMAGE_CAPTURE) .putExtra(MediaStore.EXTRA_OUTPUT, input) } final override fun getSynchronousResult( context: Context, input: Uri ): SynchronousResult<Boolean>? = null @Suppress("AutoBoxing") final override fun parseResult(resultCode: Int, intent: Intent?): Boolean { return resultCode == Activity.RESULT_OK } }
ActivityResultContracts.RequestPermission 運行時請求權限
從原始碼可以知道輸入型別為 String,輸出(回傳) 的型別為 Boolean
public static final class RequestPermission extends ActivityResultContract<String, Boolean> { @NonNull @Override public Intent createIntent(@NonNull Context context, @NonNull String input) { return RequestMultiplePermissions.createIntent(new String[] { input }); } @NonNull @Override public Boolean parseResult(int resultCode, @Nullable Intent intent) { if (intent == null || resultCode != Activity.RESULT_OK) return false; int[] grantResults = intent.getIntArrayExtra(EXTRA_PERMISSION_GRANT_RESULTS); if (grantResults == null || grantResults.length == 0) return false; return grantResults[0] == PackageManager.PERMISSION_GRANTED; } @Override public @Nullable SynchronousResult<Boolean> getSynchronousResult( @NonNull Context context, @Nullable String input) { if (input == null) { return new SynchronousResult<>(false); } else if (ContextCompat.checkSelfPermission(context, input) == PackageManager.PERMISSION_GRANTED) { return new SynchronousResult<>(true); } else { // proceed with permission request return null; } } }
ActivityResultLauncher
這是啟動器類別,其 launch() 方法可以用來啟動頁面的轉換,相當於本來的 startActivityForResult()。這裏有一點要注意,啟動器的初始化必須在 onCreate() 時處理,否則會丟出錯誤。
程式碼範例
以要求讀取聯絡人的權限為例
在 AndroidManifest.xml 中加入權限宣告
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="app.kirin.android.resultapidemo"> <uses-permission android:name="android.permission.READ_CONTACTS" /> ...
MainActivity.kt 完整程式碼
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val permissionLauncher = registerForActivityResult( ActivityResultContracts.RequestPermission() ) { result-> if(result) { Toast.makeText(this, "授權成功", Toast.LENGTH_SHORT).show() } else { Toast.makeText(this, "您必須同意授權才能繼續使用", Toast.LENGTH_SHORT).show() } } permissionLauncher.launch(android.Manifest.permission.READ_CONTACTS) } }
執行 app 就可以看到請求權限的提示。
Comments