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

有什么替代方案吗?


当前回答

Kotlin版本的@Muntashir阿肯解决方案

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

其他回答

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
        }
    }
}

添加到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)
....

这将允许您保持类的调用相同,只需要额外的一行来添加原始调用的结果代码。还允许您创建一个可重用的启动程序实例。

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.

另一种方法是分3步完成。(考虑到你有一个startActivityForResult(0和onActivityResult()))

创建一个形式为var resultLauncher的变量:ActivityResultLauncher<Intent> 创建一个私有函数,在其中以这种基本格式初始化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)

从现在开始,startActivityForResult()已经被弃用,所以使用new方法代替。

芬兰湾的科特林的例子

    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
        }
    }