Conseguimos o resultado certo (Parte 1). Activity Result API

Todo desenvolvedor Android enfrentou a necessidade de transferir dados de uma atividade para outra. Essa tarefa trivial geralmente nos força a escrever um código menos elegante. 





Finalmente, em 2020, o Google introduziu uma solução para um problema antigo - a API Activity Result. É uma ferramenta poderosa para trocar dados entre atividades e solicitar permissões de tempo de execução. 





Neste artigo, vamos entender como usar a nova API e quais as vantagens que ela tem.





O que há de errado com 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)
           }
       }
   }
}


      
      



Vamos colocar o conhecimento da nova API em prática e reescrever a tela do primeiro exemplo com a ajuda deles. Como resultado, obtemos um código bastante compacto, facilmente legível e escalonável:





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 as desvantagens da comunicação por meio de onActivityResult (), aprendemos sobre as vantagens da API Activity Result e aprendemos como usá-la na prática.  





A nova API é completamente estável, embora o normal onRequestPermissionsResult()



, onActivityResult()



e startActivityForResult()



começou obsoleta. É hora de fazer alterações em seus projetos! 





Um aplicativo de demonstração com vários exemplos de uso da API de resultado do Activty, incluindo trabalho com permissões de tempo de execução, pode ser encontrado em meu repositório Github .








All Articles