330 votes

La méthode OnActivityResult est dépréciée, quelle est l'alternative ?

J'ai récemment découvert que onActivityResult est déprécié. Que devons-nous faire pour le gérer ?

Une alternative introduite pour cela ?

Image showing code with onActivityResult striked out, indicating deprecation

1 votes

Si je l'enlève une erreur lint est apparue pour ajouter le super appel !

26 votes

Je ne sais pas s'il y a déjà eu une dépréciation qui n'a pas été dépréciée, mais j'ai bon espoir que startActivityForResult . Cette nouvelle façon de faire complique excessivement le code et en réduit la lisibilité.

57 votes

Google est le patron. Mais la façon dont ils continuent à changer les choses en peu de temps est frustrante.

3voto

VeeyaaR Points 121

J'ai compris comment le faire correctement à partir d'un Fragment en Kotlin, pour capturer une image et gérer le bitmap retourné. C'est à peu près la même chose dans d'autres cas aussi.

Tout d'abord, vous devez enregistrer le fragment pour écouter les résultats de l'activité. Cela doit être fait avant d'initier le fragment, ce qui signifie créer une variable membre au lieu de l'initier dans la fonction onCreate.

class DummyFragment : Fragment() {

  //registering fragment for camera listener
  private val takePhoto = registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
  ) {
    if (it.resultCode == Activity.RESULT_OK) {
      val imageBitmap = it.data?.extras?.get("data") as Bitmap
      // do your thing with the obtained bitmap
    }
  }

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
  }

}

Ensuite, appelez l'intention de la caméra comme vous le feriez normalement. Et utilisez la variable créée ci-dessus pour lancer l'intention.

override fun onCreate(savedInstanceState: Bundle?) {
  super.onCreate(savedInstanceState)
  someRandomButton.setOnClickListener {
    val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
    takePhoto.launch(takePictureIntent)
  }
}

2voto

dor506 Points 960

Voici ma solution :

Dans notre projet, nous avions plus de 20 occurrences de startActivityForResult (et onActivityResult).

Nous voulions modifier le code le moins possible (et continuer à utiliser les codes de demande), tout en introduisant une solution élégante pour une utilisation future.

Puisque beaucoup d'entre nous, les développeurs, utilisent BaseActivity pourquoi ne pas en profiter ?

Voici la BaseActivity :

abstract class BaseActivity : AppCompatActivity()
{
    private var requestCode: Int = -1
    private var resultHandler: ActivityResultLauncher<Intent>? = null

    override fun onCreate(savedInstanceState: Bundle?)
    {
        super.onCreate(savedInstanceState)
        registerForActivityResult()
    }

    private fun registerForActivityResult()
    {
        if (shouldRegisterForActivityResult())
        {
            resultHandler = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->

                onActivityResult(result.data, requestCode, result.resultCode)
                this.requestCode = -1
            }
        }
    }

   fun startActivityForResult(requestCode: Int, intent: Intent)
   {
       this.requestCode = requestCode
       resultHandler?.launch(intent)
   }

   protected open fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
   {
       // For sub activities
   }

   protected open fun shouldRegisterForActivityResult(): Boolean
   {
      // Sub activities that need the onActivityResult "mechanism", should override this and return true
       return false
   }
}

Voici la sous-activité :

class SubActivity : BaseActivity()
{
    companion object
    {
        private const val SOME_REQUEST_CODE = 300
    }

    private fun testActivityResult()
    {
        val intent = Intent(this, OtherActivity::class.java)
        startActivityForResult(SOME_REQUEST_CODE, intent)
    }

    override fun shouldRegisterForActivityResult(): Boolean
    {
        return true
    }

    override fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
    {
        if (requestCode == SOME_REQUEST_CODE)
        {
            // Yes!
        }
    }
}

J'espère que cela aidera quelqu'un

2voto

Muhammad Helmi Points 169

Version Kotlin de @Muntashir Akon solution

class BetterActivityResult<Input, Result> private constructor(
  caller : ActivityResultCaller,
  contract : ActivityResultContract<Input, Result>,
  var onActivityResult : ((Result) -> Unit)?,
) {

private val launcher : ActivityResultLauncher<Input> =
   caller.registerForActivityResult(contract) { onActivityResult?.invoke(it) }

  /**
   * Launch activity, same as [ActivityResultLauncher.launch] except that it 
   * allows a callback
   * executed after receiving a result from the target activity.
   */
  /**
   * Same as [.launch] with last parameter set to `null`.
   */
  @JvmOverloads
  fun launch(
     input : Input,
     onActivityResult : ((Result) -> Unit)? = this.onActivityResult,
  ) {
    this.onActivityResult = onActivityResult
    launcher.launch(input)
  }

  companion object {
  /**
   * Register activity result using a [ActivityResultContract] and an in-place 
   * activity result callback like
   * the default approach. You can still customise callback using [.launch].
   */
  fun <Input, Result> registerForActivityResult(
    caller : ActivityResultCaller,
    contract : ActivityResultContract<Input, Result>,
    onActivityResult : ((Result) -> Unit)?,
  ) : BetterActivityResult<Input, Result> {
    return BetterActivityResult(caller, contract, onActivityResult)
  }

  /**
   * Same as [.registerForActivityResult] except
   * the last argument is set to `null`.
   */
  fun <Input, Result> registerForActivityResult(
    caller : ActivityResultCaller,
    contract : ActivityResultContract<Input, Result>,
  ) : BetterActivityResult<Input, Result> {
    return registerForActivityResult(caller, contract, null)
  }

  /**
   * Specialised method for launching new activities.
   */
  fun registerActivityForResult(
    caller : ActivityResultCaller,
  ) : BetterActivityResult<Intent, ActivityResult> {
    return registerForActivityResult(caller, StartActivityForResult())
  }
 }
}

2voto

oyeraghib Points 93

Après avoir été bloqué pendant quelques heures. J'ai résolu mon problème. Lorsque j'essayais d'utiliser l'intention, je passais directement à l'activité suivante sans utiliser la connexion Google.

Ce qui a fonctionné pour moi :

À l'intérieur de OnCreate, définissez le onClickListener pour le bouton d'inscription :

 btnSignIn.setOnClickListener {
    signIn()
    }

private fun signIn() {
    val intent = client.signInIntent
    mainActivityResultLauncher.launch(intent)
}

Dans le code ci-dessus, j'écrivais l'intention de passer à l'activité suivante mais j'ai dû écrire client.signInIntent

var mainActivityResultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->

    if(result.resultCode == Activity.RESULT_OK){
        val data = result.data
        val task = GoogleSignIn.getSignedInAccountFromIntent(data)
        try {
            // Google Sign In was successful, authenticate with Firebase
            val account = task.getResult(ApiException::class.java)!!
            Log.d(TAG, "firebaseAuthWithGoogle:" + account.id)
            firebaseAuthWithGoogle(account.idToken!!)
        } catch (e: ApiException) {
            // Google Sign In failed, update UI appropriately
            Log.w(TAG, "Google sign in failed", e)
        }
    }
}

2voto

Tarun Yadvendu Points 39

dor506 La réponse a fonctionné pour moi car j'utilise BaseActivity dans la plupart de mes projets et il est donc plus facile pour moi de modifier le code dans un seul fichier plutôt que dans toutes mes activités. J'ai écrit la version java de ce code.

Code BaseActivity :

private int requestCode = -1;
private ActivityResultLauncher<Intent> resultHandler = null;

 @Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    mContext = this;

    registerForActivityResult();
}
  private final void registerForActivityResult() {
    if (shouldRegisterForActivityResult()) {
        this.resultHandler = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(),
                new ActivityResultCallback() {

            public void onActivityResult(Object var1) {
                this.onActivityResult((ActivityResult)var1);
            }

            public final void onActivityResult(ActivityResult result) {
                Intrinsics.checkNotNullExpressionValue(result, "result");
                AppActivityClass.onActivityResult(result.getData(), AppActivityClass.this.requestCode, result.getResultCode());
                AppActivityClass.this.requestCode = -1;
            }
        });
    }
}

public final void startActivityForResult(int requestCode, Intent intent) {
    this.requestCode = requestCode;
    if (resultHandler != null) {
        resultHandler.launch(intent);
    }
}

protected static void onActivityResult(Intent intent, int requestCode, int resultCode) {
}

protected Boolean shouldRegisterForActivityResult() {
    return false;
}

Maintenant, dans n'importe quelle activité, utilisez ce code comme ceci :

 @Override
protected Boolean shouldRegisterForActivityResult() {
    return true;  // this will override the baseactivity method and we can use onactivityresult
}

  private void someMethod(){
    Intent i = new Intent(mContext,SomeOtherClassActivity.class);
    startActivityForResult(101,i);
}

  @Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    if (requestCode == 101) {
        if (resultCode == RESULT_OK) {
            //revert from called class
        }
    }
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X