OnActivityResult 方法已弃用,有啥替代方法?

     2023-04-19     18

关键词:

【中文标题】OnActivityResult 方法已弃用,有啥替代方法?【英文标题】:OnActivityResult method is deprecated, what is the alternative?OnActivityResult 方法已弃用,有什么替代方法? 【发布时间】:2021-12-13 16:12:04 【问题描述】:

我最近发现onActivityResult 已被弃用。我们应该怎么处理?

为此引入了任何替代方案?

【问题讨论】:

如果我删除它,一个错误 lint 似乎添加了超级调用! 我不知道是否曾经有过未弃用的弃用,但我对startActivityForResult 抱有希望。这种新方法使代码过于复杂并降低了可读性。 谷歌是老大。但是他们在短时间内不断改变事物的方式令人沮丧。 现在很难测试这个东西:( 我明白为什么 Google 决定采用这条路线,它试图将 startActivityForResult 与视图生命周期分离。我只是希望有一种更优雅的方式来做到这一点。 【参考方案1】:

developer.android.com 提供基础培训。

以下是如何将现有代码转换为新代码的示例:

老办法:

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();
    

新方式(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);

新方式(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)

编辑。更好的方法是使其更通用,以便我们可以重用它。下面的 sn-p 用于我的一个项目中,但要注意它没有经过充分测试,可能无法涵盖所有​​情况。

BetterActivityResult.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);
    

使用上述方法,您仍然需要在启动活动或片段附件之前或期间进行注册。一旦定义,它可以在活动或片段中重用。例如,如果你需要在大部分activity中启动新的activity,你可以定义一个BaseActivity,并像这样注册一个新的BetterActivityResult

BaseActivity.java

public class BaseActivity extends AppCompatActivity 
    protected final BetterActivityResult<Intent, ActivityResult> activityLauncher = BetterActivityResult.registerActivityForResult(this);

之后,您可以像这样从任何子活动中简单地启动活动:

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();
        
    )

由于您可以将回调函数与Intent 一起设置,因此您可以在任何活动中重复使用它。

同样,您也可以使用其他两个构造函数来使用其他活动合约。

【讨论】:

与旧方法相比,新方法看起来过于复杂... 新方法比旧方法差得多。它破坏了代码的模块化,并迫使您使用更多的代码行来涵盖以前版本的用例。当您提供更好的 API 设计时,应该使用弃用,但在 Google 被任意弃用的东西是基于基于少数用例的在技术上不合理的可判断决策。 戏剧性的改变真的有必要吗?!谷歌一直在改变一些东西,比如某种婴儿尿布! 请注意 as per the documentation,绝对不应该使用“BetterActivityResult”解决方案 - onActivityResult 是一个单独的回调而不是您在 launch 时间设置的 lambda 的全部原因是它需要在配置更改或进程死亡/重新创建后存在(这两种情况都可能在其他活动打开时发生 - 只需旋转您的设备即可)。您基于 lambda 的方法将永远无法正确处理这些情况。 我很惊讶这个 API 没有被称为 startActivityForResult2。如果您认为使用结果代码很乏味,请等到您遇到一堆乱七八糟的东西。【参考方案2】:

从现在开始,startActivityForResult() 已被弃用,因此请改用新方法。

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
        
    

【讨论】:

【参考方案3】:

在 KOTLIN 中 我改变了我的代码

startActivityForResult(intent, Constants.MY_CODE_REQUEST)

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)

private fun onActivityResult(requestCode: Int, result: ActivityResult) 
    if(result.resultCode == Activity.RESULT_OK) 
        val intent = result.data
        when (requestCode) 
            Constants.MY_CODE_REQUEST -> 
            ...

我希望它对你有用。 :D

【讨论】:

onActivityResult registerForActivityResult 上的第三个代码 sn-p 已弃用。 @FilipeBrito onActivityResult 不是重写的方法,是我自己的方法,名字可以随便;) 新方式的requestCode看起来几乎没用。 这不是正确的做法。如果您将启动与 registerForActivityResult 一起设置,我们可能会遇到初始化错误。最好先创建一个变量并在那里进行注册。【参考方案4】:

在替换已弃用的方法 startActivityForResult(...) 时,只需执行 4 个简单的步骤。

    代替被覆盖的方法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...
                     
                 
    );
    

对于多个自定义请求,附加条件为

if (result.getResultCode() == 123) 
..
 else if(result.getResultCode() == 131)
..
 // so on..

    进口:

     import androidx.activity.result.ActivityResult;
     import androidx.activity.result.ActivityResultCallback;
     import androidx.activity.result.ActivityResultLauncher;
     import androidx.activity.result.contract.ActivityResultContracts;
    

    使用 startActivityForResult(intent, 123) 代替

     Intent intent = new Intent(this, SampleActivity.class);
     activityResultLaunch.launch(intent);
    

    在 SampleActivity.java 类中,在返回源活动时,代码将保持不变 -

    Intent intent = new Intent();
    setResult(123, intent);
    finish();
    

编码愉快! :)

【讨论】:

【参考方案5】:

在 Java 8 中可以这样写:

ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    result -> 
        if (result.getResultCode() == AppCompatActivity.RESULT_OK) 
            Intent data = result.getData();
            // ...
        
    
);

Intent intent = new Intent( ... );
startActivityForResult.launch(intent);

【讨论】:

如何处理多个requestCode?请帮忙。提前致谢。 一个Intent显然只有一个请求码。【参考方案6】:

onActivityResultstartActivityForResultrequestPermissionsonRequestPermissionsResult 是 deprecated 上的 androidx.fragment 上的 1.3.0-alpha04,而不是 android.app.Activity。 相反,您可以将Activity Result APIsregisterForActivityResult 一起使用。

【讨论】:

你从哪里知道这个带有“registerForActivityResult”的“Activity Result APIs”的来源? @Sumit 当我在文本 deprecated 上链接更改日志时,Android 团队说“请使用活动结果 API”【参考方案7】:

参考:Kotlin - Choose Image from gallery

迄今为止我发现的最简单的替代方案

override fun onCreate(savedInstanceState: Bundle?) 
    super.onCreate(savedInstanceState)
    setContentView(R.id.activity_main)

    var ivPhoto = findViewById<ImageView>(R.id.ivPhoto)
    var btnChoosePhoto = findViewById<Button>(R.id.btnChoosePhoto)

    

val getContent = registerForActivityResult(ActivityResultContracts.GetContent())   uri: Uri? ->
            ivPhoto.setImageURI(uri)    // Handle the returned Uri
        


    btnChoose.setOnClickListener 
        getContent.launch("image/*")
    
    
    

【讨论】:

【参考方案8】:

我的目标是重用startActivityForResult 方法的当前实现,并以最少的代码更改。为此,我使用 onActivityResultFromLauncher 方法制作了一个包装类和接口。

interface ActivityResultLauncherWrapper 

    fun launchIntentForResult(activity: FragmentActivity, intent: Intent, requestCode: Int, callBack: OnActivityResultListener)

    fun unregister()

    interface OnActivityResultListener 
        fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?)
    


class ActivityResultLauncherWrapperImpl : ActivityResultLauncherWrapper 
    private var weakLauncher: WeakReference<ActivityResultLauncher<Intent>>? = null

    override fun launchIntentForResult(
            activity: FragmentActivity,
            intent: Intent,
            requestCode: Int,
            callBack: ActivityResultLauncherWrapper.OnActivityResultListener
    ) 

        weakLauncher = WeakReference(
                activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult())  result ->
                    callBack.onActivityResultFromLauncher(requestCode, result.resultCode, result.data)
                
        )

        weakLauncher?.get()?.launch(intent)
    

    override fun unregister() 
        weakLauncher?.get()?.unregister()
    

我在我的项目中使用 Dagger,并在需要的地方注入了包装器

@Inject
lateinit var activityResultLauncher: ActivityResultLauncherWrapper

但是包装器也可以直接实例化:

val activityResultLauncher = ActivityResultLauncherWrapper()

那么您必须将startActivityForResult 方法更改为launchIntentForResult。这是从片段中调用它的示例:

activityResultLauncher.launchIntentForResult(
        requireActivity(),
        intent,
        REQUEST_CODE_CONSTANT,
        object: ActivityResultLauncherWrapper.OnActivityResultListener 
            override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) 
                /*do something*/
            
        
)

您将在匿名对象中收到结果。 如果您实现接口并像这样重构当前实现,则可以在 Fragment 或 FragmentActivity 中使用OnActivityResultListener

class MyFragment : Fragment(), OnActivityResultListener 
   
 ...
    
override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) /*do somthing*/

 ...


我们知道,Kotlin 类 ActivityResultLauncherWrapper 也可以在 java 代码中使用。我的项目中也有 java 类。有一个在 Fragment 中实现回调接口的示例:

public class MyFragment extends Fragment implements OnActivityResultListener 
    
...

    @Inject
    ActivityResultLauncherWrapper activityResultLauncher;
//ActivityResultLauncherWrapper activityResultLauncher = new ActivityResultLauncherWrapper()

...

public void launnchActivity(@NotNull Intent intent) 
        activityResultLauncher.launchIntentForResult(requireActivity(), intent, REQUEST_CODE_CONSTANT, this);
    

...

 @Override
    public void onActivityResultFromLauncher(int requestCode, int resultCode, Intent data) /*do somthing*/
...

我希望这有助于为您的案例构建解决方案。

【讨论】:

【参考方案9】:

您可以使用 Koltin 的扩展函数。例如:

//random utils file
fun Fragment.buildGetContentRequest(function: (Uri) -> Unit): ActivityResultLauncher<String> 
    return this.registerForActivityResult(ActivityResultContracts.GetContent()) 
        function(it)
    


fun Fragment.buildTakePhotoRequest(function: (Boolean) -> Unit): ActivityResultLauncher<Uri> 
    return this.registerForActivityResult(ActivityResultContracts.TakePicture()) 
        function(it)
    


fun Fragment.buildSelectMultipleContentRequest(function: (MutableList<Uri>?) -> Unit): ActivityResultLauncher<String> 
    return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) 
        function(it)
    

然后在你的片段中像这样

//your actual fragment logic
class YourFragment : Fragment() 
    //we can assign our request in init process
    private val mRequestSelectFiles = buildSelectMultipleContentRequest  
        onFilesSelected(it) 
    


    fun onSelectFiles() 
        val mime = "*/*"
        mRequestSelectFiles.launch(mime)
    

    fun onFilesSelected(list: MutableList<Uri>?) 
        //your logic
    

【讨论】:

您需要添加这些依赖项:- implementation "androidx.activity:activity-ktx:1.3.0" implementation "androidx.fragment:fragment-ktx:1.3.6"【参考方案10】:

我想出了如何从 Kotlin 的 Fragment 中正确执行此操作,以捕获图像并处理返回的位图。其他情况也差不多。

首先,您必须注册片段以侦听活动结果。这必须在启动片段之前完成,这意味着创建一个成员变量而不是在 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)
  


然后,像往常一样调用相机意图。并使用上面创建的这个变量来启动意图。

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

【讨论】:

【参考方案11】:

这是我的解决方案:

在我们的项目中,startActivityForResult(和 onActivityResult)出现了 20 多次。

我们希望尽可能少地更改代码(并继续使用请求代码),同时引入一个优雅的解决方案以供将来使用。

既然我们很多开发人员都使用 BaseActivity 概念 - 为什么不利用它呢?

这是 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
   

这是子活动:

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!
        
    

希望对某人有所帮助

【讨论】:

【参考方案12】:

@Muntashir Akon 解决方案的 Kotlin 版本

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

【讨论】:

【参考方案13】:

在被卡住了几个小时之后。我想出了我的问题。 因此,当我尝试使用意图时,我直接进入下一个活动,而不使用 Google 登录。

什么对我有用:

在 OnCreate 里面设置登录按钮的 onClickListener :

 btnSignIn.setOnClickListener 
    signIn()
    

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

在上面的代码中,我写的是去下一个活动的意图,但我必须写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)
        
    

【讨论】:

【参考方案14】:

dor506 答案对我有用,因为我在大多数项目中都使用 BaseActivity,因此我更容易更改单个文件中的代码而不是我的所有活动。我已经编写了这段代码的java版本。

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;

现在在任何活动中都可以像这样使用此代码:

 @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
        
    

【讨论】:

【参考方案15】:

似乎onActivityResult 在超类中已弃用,但您在问题中没有提及超类名称和compileSdkVersion

在 Java 和 Kotlin 中,只需向其添加 @Deprecated 即可将每个类或方法标记为已弃用,因此请检查您的超类,您可能扩展了错误的类。

当一个类被弃用时,它的所有方法也被弃用。

要查看快速解决方案,请单击已弃用的方法并在 Android Studio 中按 Ctrl+Q 以查看方法文档,应该有解决方案。


在我使用androidx 和API 29 作为compileSdkVersion 的项目中,此方法在活动和片段中不被弃用

【讨论】:

从现在开始,在项目中,使用androidx和API 29作为compileSdkVersion,这个方法也被弃用了。【参考方案16】:
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        new ActivityResultCallback<ActivityResult>() 
            @Override
            public void onActivityResult(ActivityResult result) 
                if (result.getResultCode() == Activity.RESULT_OK) 

                
            
        );

【讨论】:

【参考方案17】:

执行此操作的另一种方法是分 3 个步骤。 (考虑到你有一个 startActivityForResult(0 和 onActivityResult())

    var resultLauncher:ActivityResultLauncher&lt;Intent&gt; 的形式创建一个变量 创建一个私有函数,您可以在其中以这种基本格式初始化 resultLauncher
resultLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult())result ->  

// copy paste the code from the onActivityResult replacing resultcode to result.resultCode  

if(result.resultcode==Activity.Result_OK)
val data=result.data // this data variable is of type intent and you can use it 

else
//code if you do not get the data 


    转到startActivityForResult() 行并将其替换为resultLauncher.launch(intent)

【讨论】:

【参考方案18】:

如果您像这样实现基本 Activity,您可以继续以旧方式使用 startActivityForResult。 唯一的限制是您必须使用 setResult(result, intent) 在活动中设置结果。 关键是让结果携带请求码返回给结果消费者。

public class MyBaseActivity extends AppCompatActivity 
    private ActivityResultLauncher<Intent> activityLauncher;
    protected static String ACTIVITY_REQUEST_CODE = "my.activity.request.code";
    protected _originalIntent; 

    public void launchActivityForResult(Intent intent, int requestCode)
        intent.putExtra(UGM_ACTIVITY_REQUEST_CODE, requestCode);
        activityLauncher.launch(intent);
    

    //
    //In order to be signature compatible for the rest of derived activities, 
    //we will override the deprecated method with our own implementation!
    //
    @SuppressWarnings( "deprecation" )
    public void startActivityForResult(Intent intent, int requestCode)
        launchActivityForResult(intent, requestCode);
    

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);

    _originalIntent = getIntent();
        //set the default result
        setResult(Activity.RESULT_OK, _originalIntent);

        activityLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() 
            @Override
            public void onActivityResult(ActivityResult result) 
                Intent intent = result.getData();
                int requestCode = intent.getIntExtra(ACTIVITY_REQUEST_CODE, -1);
                MyBaseActivity.this.onActivityResult(requestCode, result.getResultCode(), intent);
            
        );
    


【讨论】:

【参考方案19】:

这就是我替换多个 requestCodes 的方式(将此代码放入您的 Activity):

    ActivityResultLauncher<Intent> launchCameraActivity = registerForActivityResult(
        new ActivityResultContracts.StartActivityForResult(),
        new ActivityResultCallback<ActivityResult>() 
            @Override
            public void onActivityResult(ActivityResult result) 
                if (result.getResultCode() == Activity.RESULT_OK) 
                    Intent data = result.getData();
                    Bitmap photoBitmap;
                    if(data != null && data.getExtras() != null)
                        photoBitmap = (Bitmap) data.getExtras().get("data");
                        if (photoBitmap != null) 
                            dataModel.setPhoto(ImageUtil.convert(photoBitmap));
                            imageTaken.setVisibility(View.VISIBLE);
                            imageTaken.setImageBitmap(photoBitmap);
                        

                    
                
            
        );

ActivityResultLauncher<Intent> launchCameraAndGalleryActivity = registerForActivityResult(
    new ActivityResultContracts.StartActivityForResult(),
    new ActivityResultCallback<ActivityResult>() 
        @Override
        public void onActivityResult(ActivityResult result) 
            if (result.getResultCode() == Activity.RESULT_OK) 
                
                Intent data = result.getData();
                Uri imageUri;
                if (data != null) 
                    imageUri = data.getData();
                    InputStream imageStream;
                    try 
                        imageStream = getContentResolver().openInputStream(imageUri);
                        Bitmap photoBitmap = BitmapFactory.decodeStream(imageStream);
                        dataModel.setOtherImage(ImageUtil.convert(photoBitmap));
                        documentImageTaken.setVisibility(View.VISIBLE);
                        documentImageTaken.setImageBitmap(photoBitmap);
                    catch (FileNotFoundException e) 
                        e.printStackTrace();
                    
                
            
        
    );

我发起这样的活动:

                    Intent photoIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
                launchCameraAndGalleryActivity.launch(photoIntent );

Intent galleryIntent= new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
    launchCameraActivity.launch(galleryIntent);

【讨论】:

【参考方案20】:

我找到的分享解决方案

首先,使用registerForActivityResult 注册此活动以获得结果 这将返回ActivityResultLauncher&lt;Intent!&gt; 类型的对象 像这样,

private val getResult =
        registerForActivityResult(
            ActivityResultContracts.StartActivityForResult()
        ) 
            if (it.resultCode == Activity.RESULT_OK) 
                val value = it.data?.getStringExtra("input")
            
        

现在我们可以使用getResult.launch(intent) 为结果发起活动的任何地方

【讨论】:

简单易学的例子 - 谢谢!【参考方案21】:

startActivityForResult 和 onActivityResult 在 android 10 API 30 中已弃用,现在我们有了一种使用 registerForActivityResult 获取结果的新方法

resultContract =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult())  result ->
        if (result.resultCode == Activity.RESULT_OK) 
            // There are no request codes
            val country = result.data?.getParcelableExtra<Country>("Country")
            showLiveDemoDialogue(country)
        
    

并启动活动

val intent = Intent(this, CountriesListActivity::class.java)
        resultContract.launch(intent)

但您应该在调用启动之前注册并在任何您想要的地方启动。 否则,你会得到这个异常

attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.

【讨论】:

【参考方案22】:

来自 Activity 和 Fragment [in Kotlin] 的 StartActivityForResult 和 RequestMultiplePermissions 的 registerForActivityResult 简单示例

从 Activity 请求 Activity 的结果

registerForActivityResult(
    ActivityResultContracts.StartActivityForResult()
)  activityResult ->
    if (activityResult.resultCode == Activity.RESULT_OK) 
        //...
    

查看ActivityResult

向 Activity 请求权限?

registerForActivityResult(
    ActivityResultContracts.RequestMultiplePermissions()
) 
    //it: Map<String, Boolean>

来自片段?

使用相同的方法,但确保将这些实现放在initialization, onAttach(), or onCreate()

【讨论】:

【参考方案23】:

如果您使用 SMS 同意 API,请使用以下代码 (Kotlin):

resultLauncher.launch( consentIntent
                            )

    var resultLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult())  result ->
    if (result.resultCode == Activity.RESULT_OK) 
        // There are no request codes
    //    val data: Intent? = result.data
        val message = result.data?.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
        getOtpFromMessage(message)

    

【讨论】:

【参考方案24】:

我正在使用 kotlin 扩展使其变得非常简单。在 Extensions.kt 文件中添加以下扩展功能:

fun AppCompatActivity.startForResult(intent: Intent,
    onResult: (resultCode: Int, data: Intent?) -> Unit
) 
    this.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) result ->
        onResult(result.resultCode, result.data)
    .launch(intent)

现在,在任何继承 AppCompatActivity 的 Activity 中,您都可以使用以下简单代码:

val i = Intent(this, TargetActivity::class.java)
startForResult(i)  resultCode, data ->
   //put your code here like:
   if (resultCode == RESULT_OK) 
      //your code here...
      
   

更新 上述实施可能会导致以下异常: java.lang.IllegalStateException: LifecycleOwner xxxx 正在尝试注册,而当前状态为 RESUMED。 LifecycleOwners 必须在开始之前调用 register。

所以 registerForActivityResult 应该被提前调用,例如在 onCreate 之前。这是替代解决方案。

在您的 Extensions.kt 文件中添加以下扩展功能:

fun AppCompatActivity.registerForResult(onResult: (resultCode: Int, data: Intent?) -> Unit):
        ActivityResultLauncher<Intent> 
    return this.registerForActivityResult(ActivityResultContracts.StartActivityForResult())  result ->
        onResult(result.resultCode, result.data)
    

现在,在任何继承 AppCompatActivity 的 Activity 中,您都可以使用以下简单代码:

    为每个需要结果的操作定义一个类成员变量
private val myActionResult = registerForResult  resultCode, data ->
   //put your code here like:
   if (resultCode == RESULT_OK) 
      //your code here...
      
   

    启动操作
val i = Intent(this, TargetActivity::class.java)
myActionResult.launch(i)

【讨论】:

【参考方案25】:

除了muntashir akon 和abhijeet 的答案之外,您可以通过在意图中传递值来修改新格式以像旧格式一样工作,例如:

// calling class
....
val i = Intent(this@GEBShopActivity, BarcodeScannerActivity::class.java)
when(loadedFragment)   
   is ShopHomeFragment      ->  i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_LIST_MAINT) 
   is ShopListFragment      ->  i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_LIST_MAINT) 
   is ShopItemMaintFragment ->  i.putExtra("myapp.result.code", CODE_ACTIVITY_SCAN_ITEM_MAINT) 
   is ShopPriceFragment     ->  i.putExtra("myapp.result.code", CODE_ACTIVITY_PRICE_CAPTURE) 
   is ShopCompareFragment   ->  i.putExtra("myapp.result.code", CODE_ACTIVITY_PRICE_CAPTURE) 

shopFragmentLauncher.launch(i)
....
// called class
....
val resultIntent = Intent()
val bundle = Bundle()
bundle.putStringArrayList("scanned_barcodes", scanned_barcodes)
bundle.putInt("scan_count", scan_count)
resultIntent.putExtras(bundle)
resultIntent.putExtra("myapp.result.code", intent.getIntExtra("myapp.result.code", 0))
setResult(Activity.RESULT_OK, resultIntent)
....

这将允许您保持类调用相同,只需多行添加您的原始调用结果代码。还允许您创建可重用的启动器实例。

【讨论】:

onActivityResult 已弃用如何发送 startResolutionForResult

】onActivityResult已弃用如何发送startResolutionForResult【英文标题】:onActivityResultisdeprecatedhowdoIsendstartResolutionForResult【发布时间】:2021-03-2521:28:29【问题描述】:所以我使用gps类来打开gps,这是一个允许我们发送到onActivityResult的方... 查看详情

OnActivityResult 方法已弃用,如何使用菜单的 onOptionItemselected 中的 registerForActivityResult

】OnActivityResult方法已弃用,如何使用菜单的onOptionItemselected中的registerForActivityResult【英文标题】:OnActivityResultmethodisdeprecated,howdoIuseregisterForActivityResultfromaMenu\'sonOptionItemselected【发布时间】:2021-08-1207:38:08【问题描述】:我正在 查看详情

GeotriggerHandlerReceiver 在 PlotProjects 中已弃用。有啥替代方法可以使用?

】GeotriggerHandlerReceiver在PlotProjects中已弃用。有啥替代方法可以使用?【英文标题】:GeotriggerHandlerReceiverisdeprecatedinPlotProjects.Whatisthealternativetouse?GeotriggerHandlerReceiver在PlotProjects中已弃用。有什么替代方法可以使用?【发布时间】... 查看详情

NSControl 的 setCellClass 在 OS X 10.10 中已弃用,有啥替代方法可以覆盖 NSTextField 的单元格类?

】NSControl的setCellClass在OSX10.10中已弃用,有啥替代方法可以覆盖NSTextField的单元格类?【英文标题】:NSControl\'ssetCellClassisdeprecatedinOSX10.10what\'sthealternativeforoverridingNSTextField\'scellclass?NSControl的setCellClass在OSX10.10中已弃用,有什么替... 查看详情

在 androidx 中弃用 OnActivityResult()

】在androidx中弃用OnActivityResult()【英文标题】:deprecatedOnActivityResult()inandroidx【发布时间】:2021-03-1709:02:59【问题描述】:OnActivityResult()在androidx中已弃用。我从以下链接中获取了参考https://developer.android.com/training/basics/intents/result... 查看详情

Gtk.stock 已弃用,有啥替代方案?

】Gtk.stock已弃用,有啥替代方案?【英文标题】:Gtk.stockisdeprecated,what\'sthealternative?Gtk.stock已弃用,有什么替代方案?【发布时间】:2016-08-1618:34:43【问题描述】:我一直在学习开发Gtk,网上的大多数示例都建议使用Gtk.stock图标... 查看详情

ConnectivityManager.getActiveNetworkInfo() / NetworkInfo 在 API 29 中已弃用。有啥替代方案?

】ConnectivityManager.getActiveNetworkInfo()/NetworkInfo在API29中已弃用。有啥替代方案?【英文标题】:ConnectivityManager.getActiveNetworkInfo()/NetworkInfoisdeprecatedinAPI29.What\'sanalternative?ConnectivityManager.getActiveNetworkInfo()/Ne 查看详情

API 29 已弃用“getBitmap”。还有其他代码吗?

...ivecodes?【发布时间】:2019-11-0105:39:32【问题描述】:我的onActivityResult无法正常工作,因为getBitmap已弃用,是否有任何替代代码可以实现此目的?这里是需要修改的代码,有什么建议吗?valbitmap=MediaS 查看详情

管理 Firebase 安装实施的截止日期是啥时候?移动应用中已弃用的 Firebase 安装 ID 有啥影响?

】管理Firebase安装实施的截止日期是啥时候?移动应用中已弃用的Firebase安装ID有啥影响?【英文标题】:WhatisDeadlineofManageFirebaseinstallationsimplementation?WhatisimpactofdeprecatedFirebaseinstallationIDinMobileapp?管理Firebase安装实施的截止日期是... 查看详情

load() 方法已弃用?

】load()方法已弃用?【英文标题】:load()methoddeprecated?【发布时间】:2012-09-2012:35:24【问题描述】:我在浏览jQueryapi时发现loadmethod在已弃用列表中。类别:已弃用|事件>文档加载我通常使用这种方法来检查图像是否完全加载。... 查看详情

方法 setDrawerListener 已弃用

】方法setDrawerListener已弃用【英文标题】:MethodsetDrawerListenerisdeprecated【发布时间】:2016-06-0822:40:23【问题描述】:当我在我的应用上做某事时,我看到我的应用上的导航抽屉减小了它的大小。但我没有对此做任何事情。然后,... 查看详情

已弃用的 NSURLConnection 方法,有替代方法吗?

】已弃用的NSURLConnection方法,有替代方法吗?【英文标题】:DeprecatedNSURLConnectionMethods,isthereanalternative?【发布时间】:2012-02-2814:12:26【问题描述】:我正在设置一个NSURLConnection来访问远程服务器:NSURL*url=[[NSURLalloc]initWithString:proj... 查看详情

替换 Java Awt 已弃用的方法

】替换JavaAwt已弃用的方法【英文标题】:ReplacingJavaAwtdeprecatedmethod【发布时间】:2018-03-3016:17:56【问题描述】:我发现了一个非常旧的代码,其中包含一个已弃用的java方法。如何转换为新方法。publicbooleanmouseDown(Evente,intx,inty)//co... 查看详情

如何更改已弃用的 beginSheetForDirectory 方法

】如何更改已弃用的beginSheetForDirectory方法【英文标题】:HowtochangeadeprecatedbeginSheetForDirectorymethod【发布时间】:2012-07-0715:49:38【问题描述】:我有一个使用beginSheetForDirectory:file:modalForWindow:modalDelegate:didEndSelector:contextInfo:的应用。... 查看详情

Android 数据绑定:“使用 '.' 的方法引用已弃用”

】Android数据绑定:“使用\\\'.\\\'的方法引用已弃用”【英文标题】:AndroidDatabinding:"Methodreferencesusing\'.\'isdeprecated"Android数据绑定:“使用\'.\'的方法引用已弃用”【发布时间】:2016-09-1608:36:53【问题描述】:在我的应用... 查看详情

AsyncTask 已弃用?使用啥方法代替 onPreExecute 和 onPostExecute?

】AsyncTask已弃用?使用啥方法代替onPreExecute和onPostExecute?【英文标题】:AsyncTaskisdeprecated?WhatmethodusedinsteadofonPreExecuteandonPostExecute?AsyncTask已弃用?使用什么方法代替onPreExecute和onPostExecute?【发布时间】:2021-02-2309:35:26【问题描... 查看详情

window.requestFileSystem 方法是不是已弃用?

】window.requestFileSystem方法是不是已弃用?【英文标题】:Iswindow.requestFileSystemmethodisdeprecated?window.requestFileSystem方法是否已弃用?【发布时间】:2016-10-3012:57:50【问题描述】:我目前正在开发一个旧的iOS应用程序。我对科尔多瓦没... 查看详情

猫鼬新版本是不是已弃用 exexPopulate() 方法?

】猫鼬新版本是不是已弃用exexPopulate()方法?【英文标题】:IsexexPopulate()methodisdeprecatedfromthemongoosenewversion?猫鼬新版本是否已弃用exexPopulate()方法?【发布时间】:2021-11-1514:43:20【问题描述】:main()constmain=async()=>consttask=awaitTask... 查看详情