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