すべてのAndroid開発者は、あるアクティビティから別のアクティビティにデータを転送する必要に直面していました。この些細な作業で、あまりエレガントでないコードを書くことを余儀なくされることがよくあります。
最後に、2020年に、Googleは古い問題の解決策であるActivity ResultAPIを導入しました。これは、アクティビティ間でデータを交換し、実行時のアクセス許可を要求するための強力なツールです。
この記事では、新しいAPIの使用方法とその利点について説明します。
onActivityResult()の何が問題になっていますか?
“ ” — DRY Don’t repeat yourself, , .
onActivityResult()
, . , , — SecondActivity
. SecondActivity
, .
class OldActivity : AppCompatActivity(R.layout.a_main) {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
vButtonCamera.setOnClickListener {
when {
checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED -> {
// ,
startActivityForResult(
Intent(MediaStore.ACTION_IMAGE_CAPTURE),
PHOTO_REQUEST_CODE
)
}
shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// ,
}
else -> {
// ,
requestPermissions(
arrayOf(Manifest.permission.CAMERA),
PHOTO_PERMISSIONS_REQUEST_CODE
)
}
}
}
vButtonSecondActivity.setOnClickListener {
val intent = Intent(this, SecondActivity::class.java)
.putExtra("my_input_key", "What is the answer?")
startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
when (requestCode) {
PHOTO_REQUEST_CODE -> {
if (resultCode == RESULT_OK && data != null) {
val bitmap = data.extras?.get("data") as Bitmap
// bitmap
} else {
//
}
}
SECOND_ACTIVITY_REQUEST_CODE -> {
if (resultCode == RESULT_OK && data != null) {
val result = data.getIntExtra("my_result_extra")
// result
} else {
//
}
}
else -> super.onActivityResult(requestCode, resultCode, data)
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == PHOTO_PERMISSIONS_REQUEST_CODE) {
when {
grantResults[0] == PackageManager.PERMISSION_GRANTED -> {
// ,
startActivityForResult(
Intent(MediaStore.ACTION_IMAGE_CAPTURE),
PHOTO_REQUEST_CODE
)
}
!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// , Don't ask again.
}
else -> {
// ,
}
}
} else {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
companion object {
private const val PHOTO_REQUEST_CODE = 1
private const val PHOTO_PERMISSIONS_REQUEST_CODE = 2
private const val SECOND_ACTIVITY_REQUEST_CODE = 3
}
}
, onActivityResult()
, Activity. , .
, , .
Activity Result API
API AndroidX Activity 1.2.0-alpha02
Fragment 1.3.0-alpha02
, build.gradle:
implementation 'androidx.activity:activity-ktx:1.3.0-alpha02'
implementation 'androidx.fragment:fragment-ktx:1.3.0'
Activity Result :
1.
— , ActivityResultContract<I,O>.
I
, Activity, O
— .
“ ”: PickContact
, TakePicture
, RequestPermission
. .
:
createIntent()
— , launch()
parseResult()
— , resultCode
— getSynchronousResult()
— . , Activity, , , . , null
.
, SecondActivity, :
class MySecondActivityContract : ActivityResultContract<String, Int?>() {
override fun createIntent(context: Context, input: String?): Intent {
return Intent(context, SecondActivity::class.java)
.putExtra("my_input_key", input)
}
override fun parseResult(resultCode: Int, intent: Intent?): Int? = when {
resultCode != Activity.RESULT_OK -> null
else -> intent?.getIntExtra("my_result_key", 42)
}
override fun getSynchronousResult(context: Context, input: String?): SynchronousResult<Int?>? {
return if (input.isNullOrEmpty()) SynchronousResult(42) else null
}
}
2.
— registerForActivityResult()
. ActivityResultContract
ActivityResultCallback
. .
val activityLauncher = registerForActivityResult(MySecondActivityContract()) { result ->
// result
}
Activity
, ActivityResultLauncher
, .
3.
Activity launch()
ActivityResultLauncher
, .
vButton.setOnClickListener {
activityLauncher.launch("What is the answer?")
}
!
, :
, CREATED . — .
registerForActivityResult()
if
when
. , (, , ). , .
, Activity, ActivityNotFoundException: “No Activity found to handle Intent”. ,
launch()
getSynchronousResult()
resolveActivity()
cPackageManager
.
runtime permissions
Activity Result API . checkSelfPermission()
, requestPermissions()
onRequestPermissionsResult()
, — RequestPermission
RequestMultiplePermissions
.
, — . RequestPermission
true
, , false
. RequestMultiplePermissions
Map
, — , — .
. Google :
runtime permissions:
, , ( 5a)
( 8b), , , “Don't ask again”
shouldShowRequestPermissionRationale()
. true
, , . shouldShowRequestPermissionRationale()
false
— “Don't ask again”, .
:
class PermissionsActivity : AppCompatActivity(R.layout.a_main) {
val singlePermission = registerForActivityResult(RequestPermission()) { granted ->
when {
granted -> {
// ,
}
!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// , Don't ask again.
}
else -> {
// ,
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
vButtonPermission.setOnClickListener {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
// ,
} else {
singlePermission.launch(Manifest.permission.CAMERA)
}
}
}
}
新しいAPIの知識を実践し、彼らの助けを借りて最初の例の画面を書き直してみましょう。その結果、かなりコンパクトで、読みやすく、スケーラブルなコードが得られます。
class NewActivity : AppCompatActivity(R.layout.a_main) {
val permission = registerForActivityResult(RequestPermission()) { granted ->
when {
granted -> {
camera.launch() // ,
}
!shouldShowRequestPermissionRationale(Manifest.permission.CAMERA) -> {
// , Don't ask again.
}
else -> {
//
}
}
}
val camera = registerForActivityResult(TakePicturePreview()) { bitmap ->
// bitmap
}
val custom = registerForActivityResult(MySecondActivityContract()) { result ->
// result
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
vButtonCamera.setOnClickListener {
if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
// ,
} else {
permission.launch(Manifest.permission.CAMERA)
}
}
vButtonSecondActivity.setOnClickListener {
custom.launch("What is the answer?")
}
}
}
onActivityResult()を介した通信の欠点を確認し、Activity Result APIの利点について学び、実際の使用方法を学びました。
新しいAPIは通常どおり完全に安定しており、非推奨onRequestPermissionsResult()
にonActivityResult()
なりstartActivityForResult()
ました。プロジェクトに変更を加える時が来ました!
ランタイム権限の操作を含む、Activty Result APIのさまざまな使用例を含むデモアプリケーションは、私のGithubリポジトリにあります。