Obtener el resultado correcto (Parte 1). API de resultados de actividad

Todos los desarrolladores de Android se enfrentaron a la necesidad de transferir datos de una actividad a otra. Esta tarea trivial a menudo nos obliga a escribir código menos elegante. 





Finalmente, en 2020, Google presentó una solución a un viejo problema: la API de resultados de actividad. Es una herramienta poderosa para intercambiar datos entre actividades y solicitar permisos de tiempo de ejecución. 





En este artículo, entenderemos cómo utilizar la nueva API y qué ventajas tiene.





¿Qué pasa con 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()



    c   PackageManager



    .





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)
           }
       }
   }
}


      
      



Pongamos en práctica el conocimiento de la nueva API y reescribamos la pantalla del primer ejemplo con su ayuda. Como resultado, obtenemos un código bastante compacto, fácilmente legible y escalable:





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?")
       }
   }
}


      
      



Vimos las desventajas de comunicarse a través de onActivityResult (), aprendimos sobre las ventajas de la API de resultados de actividad y aprendimos cómo usarla en la práctica.  





La nueva API es completamente estable, mientras que la habitual onRequestPermissionsResult()



, onActivityResult()



y startActivityForResult()



comenzó en desuso. ¡Es hora de hacer cambios en tus proyectos! 





En mi repositorio de Github se puede encontrar una aplicación de demostración con varios ejemplos del uso de Activty Result API, incluido el trabajo con permisos de tiempo de ejecución .








All Articles