OnActivityResult 方法已弃用,有啥替代方法?
Posted
技术标签:
【中文标题】OnActivityResult 方法已弃用,有啥替代方法?【英文标题】:OnActivityResult method is deprecated, what is the alternative?OnActivityResult 方法已弃用,有什么替代方法? 【发布时间】:2020-10-21 13:30:48 【问题描述】:我最近发现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】:
onActivityResult
、startActivityForResult
、requestPermissions
和 onRequestPermissionsResult
是 deprecated 上的 androidx.fragment
上的 1.3.0-alpha04
,而不是 android.app.Activity
。
相反,您可以将Activity Result APIs
与registerForActivityResult
一起使用。
【讨论】:
你从哪里知道这个带有“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<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)
行
【讨论】:
【参考方案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<Intent!>
类型的对象
像这样,
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 方法已弃用,有啥替代方法?的主要内容,如果未能解决你的问题,请参考以下文章
OnActivityResult 方法已弃用,如何使用菜单的 onOptionItemselected 中的 registerForActivityResult
GeotriggerHandlerReceiver 在 PlotProjects 中已弃用。有啥替代方法可以使用?
NSControl 的 setCellClass 在 OS X 10.10 中已弃用,有啥替代方法可以覆盖 NSTextField 的单元格类?
ConnectivityManager.getActiveNetworkInfo() / NetworkInfo 在 API 29 中已弃用。有啥替代方案?