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 ?
Une formation de base est disponible sur développeur.Android.com .
Voici un exemple de la façon de convertir le code existant avec le nouveau :
L'ancienne méthode :
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
startActivityForResult(intent, 123);
}
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == 123) {
doSomeOperations();
}
}
La nouvelle voie (Java) :
// You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
doSomeOperations();
}
}
});
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
someActivityResultLauncher.launch(intent);
}
La nouvelle méthode (Kotlin) :
var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
doSomeOperations()
}
}
fun openSomeActivityForResult() {
val intent = Intent(this, SomeActivity::class.java)
resultLauncher.launch(intent)
}
EDIT. Une meilleure approche serait de le rendre plus généralisé afin que nous puissions le réutiliser. Le snippet ci-dessous est utilisé dans un de mes projets mais attention, il n'est pas bien testé et peut ne pas couvrir tous les cas.
MeilleureActivitéRésultat.java
import android.content.Intent;
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCaller;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContract;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
public class BetterActivityResult<Input, Result> {
/**
* Register activity result using a {@link ActivityResultContract} and an in-place activity result callback like
* the default approach. You can still customise callback using {@link #launch(Object, OnActivityResult)}.
*/
@NonNull
public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract,
@Nullable OnActivityResult<Result> onActivityResult) {
return new BetterActivityResult<>(caller, contract, onActivityResult);
}
/**
* Same as {@link #registerForActivityResult(ActivityResultCaller, ActivityResultContract, OnActivityResult)} except
* the last argument is set to {@code null}.
*/
@NonNull
public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract) {
return registerForActivityResult(caller, contract, null);
}
/**
* Specialised method for launching new activities.
*/
@NonNull
public static BetterActivityResult<Intent, ActivityResult> registerActivityForResult(
@NonNull ActivityResultCaller caller) {
return registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());
}
/**
* Callback interface
*/
public interface OnActivityResult<O> {
/**
* Called after receiving a result from the target activity
*/
void onActivityResult(O result);
}
private final ActivityResultLauncher<Input> launcher;
@Nullable
private OnActivityResult<Result> onActivityResult;
private BetterActivityResult(@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Input, Result> contract,
@Nullable OnActivityResult<Result> onActivityResult) {
this.onActivityResult = onActivityResult;
this.launcher = caller.registerForActivityResult(contract, this::callOnActivityResult);
}
public void setOnActivityResult(@Nullable OnActivityResult<Result> onActivityResult) {
this.onActivityResult = onActivityResult;
}
/**
* Launch activity, same as {@link ActivityResultLauncher#launch(Object)} except that it allows a callback
* executed after receiving a result from the target activity.
*/
public void launch(Input input, @Nullable OnActivityResult<Result> onActivityResult) {
if (onActivityResult != null) {
this.onActivityResult = onActivityResult;
}
launcher.launch(input);
}
/**
* Same as {@link #launch(Object, OnActivityResult)} with last parameter set to {@code null}.
*/
public void launch(Input input) {
launch(input, this.onActivityResult);
}
private void callOnActivityResult(Result result) {
if (onActivityResult != null) onActivityResult.onActivityResult(result);
}
}
Avec l'approche ci-dessus, vous devez toujours l'enregistrer avant ou pendant le lancement de l'activité ou du fragment attaché. Une fois défini, il peut être réutilisé au sein de l'activité ou du fragment. Par exemple, si vous devez lancer de nouvelles activités dans la majeure partie de l'activité, vous pouvez définir un fichier BaseActivity
et enregistrer un nouveau BetterActivityResult
comme ça :
BaseActivity.java
public class BaseActivity extends AppCompatActivity {
protected final BetterActivityResult<Intent, ActivityResult> activityLauncher = BetterActivityResult.registerActivityForResult(this);
}
Après cela, vous pouvez simplement lancer une activité à partir de n'importe quelle activité enfant comme ceci :
public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
activityLauncher.launch(intent, result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// There are no request codes
Intent data = result.getData();
doSomeOperations();
}
})
}
Puisque vous pouvez définir la fonction de rappel en même temps que l'option Intent
vous pouvez le réutiliser pour n'importe quelle activité.
De même, vous pouvez utiliser d'autres contrats d'activité à l'aide des deux autres constructeurs.
@drmrbrewer il supprime le tracas de la maintenance des codes de demande et ajoute la possibilité d'exécuter des tests. Mais je pense que son principal problème est la réutilisation. A mon avis ActivityResultCallback
devrait faire partie de ActivityResultLauncher#launch()
afin de pouvoir la réutiliser à d'autres fins. Par exemple, si j'avais eu besoin de vérifier les autorisations de stockage pour plusieurs actions, j'aurais pu utiliser un seul fichier ActivityResultContracts.RequestPermission()
pour tous. Vous pourriez mettre en œuvre ActivityResultCallback
pour tenter de résoudre ce problème mais cela sera pire que l'ancienne méthode puisque vous avez besoin de quelque chose de similaire pour demander des codes.
Si mon activité démarre 2 nouvelles activités pour le résultat, comment puis-je le différencier sur onActivityResult ?
A partir de maintenant, startActivityForResult()
a été déprécié, utilisez donc la nouvelle méthode à la place.
Exemple Kotlin
fun openActivityForResult() {
startForResult.launch(Intent(this, AnotherActivity::class.java))
}
val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// Handle the Intent
//do stuff here
}
}
Il y a 4 étapes simples à suivre lors du remplacement de la méthode dépréciée startActivityForResult(...)
.
En lieu et place de la méthode surchargée onActivityResult(..)
-
ActivityResultLauncher<Intent> activityResultLaunch = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == 123) {
// ToDo : Do your stuff...
} else if(result.getResultCode() == 321) {
// ToDo : Do your stuff...
}
}
});
Pour les demandes personnalisées multiples, ajoutez la condition comme
if (result.getResultCode() == 123) {
..
} else if(result.getResultCode() == 131){
..
} // so on..
Importations :
import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
A la place de startActivityForResult(intent, 123), utilisez
Intent intent = new Intent(this, SampleActivity.class);
activityResultLaunch.launch(intent);
Dans la classe SampleActivity.java, en retournant à l'activité source, le code restera le même, comme -
Intent intent = new Intent();
setResult(123, intent);
finish();
Bon codage ! :)
A KOTLIN J'ai modifié mon code
startActivityForResult(intent, Constants.MY_CODE_REQUEST)
y
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK) {
when (requestCode) {
Constants.MY_CODE_REQUEST -> {
...
}
à
registerForActivityResult(StartActivityForResult()) { result ->
onActivityResult(Constants.MY_CODE_REQUEST, result)
}.launch(intent)
y
private fun onActivityResult(requestCode: Int, result: ActivityResult) {
if(result.resultCode == Activity.RESULT_OK) {
val intent = result.data
when (requestCode) {
Constants.MY_CODE_REQUEST -> {
...
J'espère que cela fonctionnera pour vous. :D
onActivityResult
de votre troisième extrait de code sur registerForActivityResult
est déprécié.
@FilipeBrito onActivityResult n'est pas une méthode écrasée, c'est ma propre méthode, le nom peut être n'importe quoi ;)
La nouvelle voie est : registerForActivityResult
Avantage :
Dans Kotlin :
var launchSomeActivity = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val data: Intent? = result.data
// your operation...
}
}
fun openYourActivity() {
val intent = Intent(this, SomeActivity::class.java)
launchSomeActivity.launch(intent)
}
En Java :
// Create lanucher variable inside onAttach or onCreate or global
ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {
Intent data = result.getData();
// your operation....
}
}
});
public void openYourActivity() {
Intent intent = new Intent(this, SomeActivity.class);
launchSomeActivity.launch(intent);
}
Et si quelqu'un veut passer android.content.Intent intent, int requestCode
comme paramètres comme sur une méthode dépréciée pour une raison quelconque ?
Sans vouloir trop changer la logique antérieure, jusqu'à ce que l'on s'adapte à la nouvelle façon de faire ?
@AtomX pas besoin de passer le code de la demande parce que vous avez besoin de créer cet objet de lancement pour l'appel individuel, donc si vous voulez appeler deux activités différentes, vous devez créer un objet de rappel.
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.
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.
0 votes
C'est difficile de tester la chose maintenant :(
1 votes
Je peux comprendre pourquoi Google a décidé de suivre cette voie, il essaie de découpler
startActivityForResult
du cycle de vie de la vue. Je souhaitais simplement qu'il y ait un moyen plus élégant de le faire.0 votes
Le site docs ne le montre pas comme étant déprécié.
0 votes
Veuillez consulter cette documentation officielle. J'espère que cela vous aidera. developer.Android.com/training/basics/intents/résultat
0 votes
StartActivityForResult semble également déprécié. Est-ce le cas ?