OnActivityResult方法已弃用,替代方案是什么?

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

有什么替代方案吗?

图像显示代码与onActivityResult strike out,表明deprecation

332568 次浏览

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

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

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

要查看快速解决方案,单击已弃用的方法,并按Ctrl+Q在Android工作室查看方法的文档,应该有一个解决方案。


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

onActivityResultstartActivityForResultrequestPermissionsonRequestPermissionsResult是从1.3.0-alpha04androidx.fragment弃用,而不是在android.app.Activity上。
相反,你可以使用Activity Result APIsregisterForActivityResult

基本训练可在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):

public void openSomeActivityForResult() {
Intent intent = new Intent(this, SomeActivity.class);
someActivityResultLauncher.launch(intent);
}


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


新方法(Kotlin):

fun openSomeActivityForResult() {
val intent = Intent(this, SomeActivity::class.java)
resultLauncher.launch(intent)
}


var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
// There are no request codes
val data: Intent? = result.data
doSomeOperations()
}
}


编辑。一个更好的方法是使它更一般化,以便我们可以重用它。下面的代码片段用于我的一个项目,但请注意,它没有经过良好的测试,可能无法涵盖所有情况。

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

使用上述方法,您仍然必须在启动活动或片段附件之前或期间注册它。一旦定义,就可以在活动或片段中重用它。例如,如果你需要在大部分活动中启动新的活动,你可以定义一个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一起设置,因此可以在任何活动中重用它。

类似地,您也可以使用其他两个构造函数来使用其他活动契约。

从现在开始,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
}
}

< >强在芬兰湾的科特林 我改变了我的代码

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

我的目标是用最少的代码更改重用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()
}
}

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

@Inject
lateinit var activityResultLauncher: ActivityResultLauncherWrapper

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

val activityResultLauncher = ActivityResultLauncherWrapper()

那么你必须用launchIntentForResult来改变startActivityForResult方法。下面是一个从片段中调用它的例子:

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*/}
...
}

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

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

以下是我的解决方案:

在我们的项目中,我们有超过20次的startActivityForResult(和onActivityResult)。

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

既然我们很多开发人员都使用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
}
}

这是SubActivity:

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

希望它能帮助到别人

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

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.

您可以为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
}
}

参考:Kotlin -从图库中选择图像

迄今为止我发现的最简单的Alernative

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/*")
}
    

}
ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
new ActivityResultCallback<ActivityResult>() {
@Override
public void onActivityResult(ActivityResult result) {
if (result.getResultCode() == Activity.RESULT_OK) {


}
}
});

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

  1. 创建一个var resultLauncher:ActivityResultLauncher<Intent>形式的变量
  2. 创建一个私有函数,在其中以这种基本格式初始化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
}
}
  1. 找到带有startActivityForResult()的行,并将其替换为resultLauncher.launch(intent)

StartActivityForResult &活动和片段的多重权限[在Kotlin]

请求活动以获得活动的结果

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

查看ActivityResult

向活动请求许可?

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

从片段?

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

在替换已弃用的方法startActivityForResult(...)时,需要遵循4个简单的步骤。

  1. 代替被覆盖的方法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..
  1. < p >进口:

     import androidx.activity.result.ActivityResult;
    import androidx.activity.result.ActivityResultCallback;
    import androidx.activity.result.ActivityResultLauncher;
    import androidx.activity.result.contract.ActivityResultContracts;
    
  2. 在startActivityForResult(intent, 123)的地方,使用

     Intent intent = new Intent(this, SampleActivity.class);
    activityResultLaunch.launch(intent);
    
  3. 在SampleActivity.java类中,当返回到源活动时,代码将保持相同的-

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

编码快乐!:)

如果您正在使用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)


}
}

我使用kotlin扩展,使它非常简单。在你的Extenstions.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的任何活动中,你可以使用下面的简单代码:

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正在尝试注册,而当前状态为恢复。 .生命周期所有者必须在启动之前调用寄存器

因此,registerForActivityResult应该提前调用,例如在onCreate之前。这是另一种解决方案。

在你的Extenstions.kt文件中添加以下扩展函数:

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

现在,在继承AppCompatActivity的任何活动中,你可以使用下面的简单代码:

  1. 定义一个类成员变量为每个动作要求结果
private val myActionResult = registerForResult { resultCode, data ->
//put your code here like:
if (resultCode == RESULT_OK) {
//your code here...
}
}
}
  1. 启动动作
val i = Intent(this, TargetActivity::class.java)
myActionResult.launch(i)
如果你像这样实现你的base 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);
}
});
}


}

在我的情况下,我试图使用意图,我直接移动到下一个活动,而不使用谷歌登录。

对我有用的是:

Inside OnCreate set the onClickListener for the sign-in button :

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

通过muntashir阿肯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)
....

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

这就是我如何替换多个requestCodes(把这段代码放在你的活动中):

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

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

分享我找到的解决方法

首先,使用registerForActivityResult为结果注册这个活动 这将返回一个ActivityResultLauncher<Intent!>类型的对象 像这样,< / p >
private val getResult =
registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) {
if (it.resultCode == Activity.RESULT_OK) {
val value = it.data?.getStringExtra("input")
}
}

现在,无论我们想在哪里启动result活动,我们都可以使用getResult.launch(intent)

我想出了如何从Kotlin的片段中正确地做到这一点,以捕获图像并处理返回的位图。在其他情况下也是一样的。

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

对于那些具有多个requestCode的片段,并且如果你不确定如何处理这些requestCode的多个结果,你需要理解requestCode在新方法中是无用的。

我想象你以前的编码方式是这样的:

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_CODE) {
when (requestCode) {
REQUEST_TAKE_PHOTO -> {
// handle photo from camera
}
REQUEST_PICK_IMAGE_FROM_GALLERY -> {
// handle image from gallery
}
}
}
}

在新的API中,你需要在一个单独的ActivityResultContract中实现每个请求的结果:

val takePhotoForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// handle photo from camera
}
}


val pickImageFromGalleryForResult = registerForActivityResult(StartActivityForResult()) { result: ActivityResult ->
if (result.resultCode == Activity.RESULT_OK) {
val intent = result.data
// handle image from gallery
}
}

然后你需要像这样开始这些活动/意图:

private fun startTakePhotoActivity() {
takePhotoForResult.launch(Intent(requireActivity(), TakePhotoActivity::class.java))
}


private fun pickImageFromGallery() {
val pickIntent = Intent(Intent.ACTION_PICK)
pickIntent.setDataAndType(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
"image/*"
)
pickImageFromGalleryForResult.launch(pickIntent)
}

通过这样做,你可以在你的项目中摆脱数百个const val REQUEST_值。

下面我来解释一下这种新方法

private val scan =
registerForActivityResult(ActivityResultContracts.StartActivityForResult())
{ result: ActivityResult ->
if (result.resultCode == AppCompatActivity.RESULT_OK && result.data != null) {


var selected_hub = result!!.data!!.getParcelableExtra<ExtendedBluetoothDevice>(Utils.EXTRA_DEVICE)
Log.d(TAG,"RECONNECT PROCESS "+selected_hub!!.name)
reconnect(selected_hub!!)


}
}

从活动或片段调用此方法

private fun callScan() {
val intent = Intent(requireActivity(), ScanningMeshDevices::class.java)
scan.launch(intent)
}

结合上面的答案,我有一个与旧方法startActivityForResult ()兼容的方法,在不改变旧代码结构的情况下继续使用requestCode:

ActivityLauncher.class

public class ActivityLauncher {


private final ActivityResultLauncher<Intent> launcher;
private ActivityResultCallback<ActivityResult> activityResultCallback;


private ActivityLauncher(@NonNull ActivityResultCaller caller,
@NonNull ActivityResultContract<Intent, ActivityResult> contract,
@Nullable ActivityResultCallback<ActivityResult> activityResultCallback) {
this.activityResultCallback = activityResultCallback;
this.launcher = caller.registerForActivityResult(contract, this::onActivityResult);
}


public static ActivityLauncher registerActivityForResult(
@NonNull ActivityResultCaller caller) {
return new ActivityLauncher(caller, new ActivityResultContracts.StartActivityForResult(), null);
}


public void launch(Intent intent, @Nullable ActivityResultCallback<ActivityResult> activityResultCallback) {
if (activityResultCallback != null) {
this.activityResultCallback = activityResultCallback;
}
launcher.launch(intent);
}


private void onActivityResult(ActivityResult result) {
if (activityResultCallback != null) activityResultCallback.onActivityResult(result);
}


public interface OnActivityResult {
void onActivityResultCallback(int requestCode, int resultCode, Intent data);
}

BaseActivity.java中的代码

private final ActivityLauncher activityLauncher = ActivityLauncher.registerActivityForResult(this);


public void startActivityForResult(Intent intent, int requestCode, ActivityLauncher.OnActivityResult onActivityResult) {
activityLauncher.launch(intent, result -> onActivityResult.onActivityResultCallback(requestCode, result.getResultCode(), result.getData()));
}

最后,在每个扩展BaseActivity活动中,实现ActivityLauncher。OnActivityResult并更改覆盖函数的名称"onActivityResult"onActivityResultCallback"“帮助”。还记得删除super.onActivityResult ()

如何使用:startActivityForResult(intent, requestCode, this)