Chaque développeur Android était confronté à la nécessité de transférer des données d'une activité à une autre. Cette tùche triviale nous oblige souvent à écrire du code moins élégant.
Enfin, en 2020, Google a introduit une solution à un ancien problÚme: l'API Activity Result. C'est un outil puissant pour échanger des données entre les activités et demander des autorisations d'exécution.
Dans cet article, nous allons comprendre comment utiliser la nouvelle API et ses avantages.
Quel est le problĂšme avec 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)
}
}
}
}
Mettons en pratique la connaissance de la nouvelle API et réécrivons l'écran du premier exemple avec leur aide. En conséquence, nous obtenons un code assez compact, facilement lisible et évolutif:
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?")
}
}
}
Nous avons vu les inconvénients de la communication via onActivityResult (), découvert les avantages de l'API Activity Result et appris à l'utiliser dans la pratique.
La nouvelle API est complĂštement stable, alors que d'habitude onRequestPermissionsResult()
, onActivityResult()
et a startActivityForResult()
commencĂ© Ă ĂȘtre obsolĂšte. Il est temps d'apporter des modifications Ă vos projets!
Une application de dĂ©monstration avec divers exemples d'utilisation de l'API Activty Result, y compris l'utilisation des autorisations d'exĂ©cution, peut ĂȘtre trouvĂ©e dans mon rĂ©fĂ©rentiel Github .