onactivityresult方法已被弃用,替代方法是什么?

dfuffjeb  于 2021-08-20  发布在  Java
关注(0)|答案(16)|浏览(1261)

我最近发现 onActivityResult 不推荐使用。我们该怎么处理呢?
有没有其他办法?

jc3wubiy

jc3wubiy1#

我的目标是重用当前的 startActivityForResult 方法,代码更改最少。为此,我使用onactivityresultfromlauncher方法创建了一个 Package 类和接口。

  1. interface ActivityResultLauncherWrapper {
  2. fun launchIntentForResult(activity: FragmentActivity, intent: Intent, requestCode: Int, callBack: OnActivityResultListener)
  3. fun unregister()
  4. interface OnActivityResultListener {
  5. fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?)
  6. }
  7. }
  8. class ActivityResultLauncherWrapperImpl : ActivityResultLauncherWrapper {
  9. private var weakLauncher: WeakReference<ActivityResultLauncher<Intent>>? = null
  10. override fun launchIntentForResult(
  11. activity: FragmentActivity,
  12. intent: Intent,
  13. requestCode: Int,
  14. callBack: ActivityResultLauncherWrapper.OnActivityResultListener
  15. ) {
  16. weakLauncher = WeakReference(
  17. activity.registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
  18. callBack.onActivityResultFromLauncher(requestCode, result.resultCode, result.data)
  19. }
  20. )
  21. weakLauncher?.get()?.launch(intent)
  22. }
  23. override fun unregister() {
  24. weakLauncher?.get()?.unregister()
  25. }
  26. }

我在我的项目中使用dagger,我在需要的地方注入了 Package 器

  1. @Inject
  2. lateinit var activityResultLauncher: ActivityResultLauncherWrapper

但 Package 器也可以直接示例化:

  1. val activityResultLauncher = ActivityResultLauncherWrapper()

那你就得换衣服了 startActivityForResult 方法 launchIntentForResult . 下面是从片段调用它的示例:

  1. activityResultLauncher.launchIntentForResult(
  2. requireActivity(),
  3. intent,
  4. REQUEST_CODE_CONSTANT,
  5. object: ActivityResultLauncherWrapper.OnActivityResultListener {
  6. override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {
  7. /*do something*/
  8. }
  9. }
  10. )

您将在匿名对象中收到结果。你可以用 OnActivityResultListener 在片段或片段活动中,如果您实现接口并按如下方式重构当前实现:

  1. class MyFragment : Fragment(), OnActivityResultListener {
  2. ...
  3. override fun onActivityResultFromLauncher(requestCode: Int, resultCode: Int, data: Intent?) {/*do somthing*/}
  4. ...
  5. }

正如我们所知,kotlin类activityresultlauncherwrapper也可以在java代码中使用。我的项目中也有java类。下面是一个在片段中实现回调接口的示例:

  1. public class MyFragment extends Fragment implements OnActivityResultListener {
  2. ...
  3. @Inject
  4. ActivityResultLauncherWrapper activityResultLauncher;
  5. //ActivityResultLauncherWrapper activityResultLauncher = new ActivityResultLauncherWrapper()
  6. ...
  7. public void launnchActivity(@NotNull Intent intent) {
  8. activityResultLauncher.launchIntentForResult(requireActivity(), intent, REQUEST_CODE_CONSTANT, this);
  9. }
  10. ...
  11. @Override
  12. public void onActivityResultFromLauncher(int requestCode, int resultCode, Intent data) {/*do somthing*/}
  13. ...
  14. }

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

展开查看全部
zlwx9yxi

zlwx9yxi2#

参考:kotlin-从图库中选择图像
到目前为止我找到的最简单的动词

  1. override fun onCreate(savedInstanceState: Bundle?) {
  2. super.onCreate(savedInstanceState)
  3. setContentView(R.id.activity_main)
  4. var ivPhoto = findViewById<ImageView>(R.id.ivPhoto)
  5. var btnChoosePhoto = findViewById<Button>(R.id.btnChoosePhoto)
  6. val getContent = registerForActivityResult(ActivityResultContracts.GetContent()) { uri: Uri? ->
  7. ivPhoto.setImageURI(uri) // Handle the returned Uri
  8. }
  9. btnChoose.setOnClickListener {
  10. getContent.launch("image/*")
  11. }
  12. }
展开查看全部
gwo2fgha

gwo2fgha3#

在java中,可以这样编写:

  1. ActivityResultLauncher<Intent> startActivityForResult = registerForActivityResult(
  2. new ActivityResultContracts.StartActivityForResult(),
  3. result -> {
  4. if (result.getResultCode() == AppCompatActivity.RESULT_OK) {
  5. Intent data = result.getData();
  6. // ...
  7. }
  8. }
  9. );
  10. Intent intent = new Intent( ... );
  11. startActivityForResult.launch(intent);
5lhxktic

5lhxktic4#

以下是我的解决方案:
在我们的项目中,startactivityforresult(和onactivityresult)出现了20多次。
我们希望尽可能少地更改代码(并继续使用请求代码),同时为将来的使用引入一个优雅的解决方案。
既然我们很多开发人员都使用baseactivity概念,为什么不利用它呢?
以下是基本活动:

  1. abstract class BaseActivity : AppCompatActivity()
  2. {
  3. private var requestCode: Int = -1
  4. private var resultHandler: ActivityResultLauncher<Intent>? = null
  5. override fun onCreate(savedInstanceState: Bundle?)
  6. {
  7. super.onCreate(savedInstanceState)
  8. registerForActivityResult()
  9. }
  10. private fun registerForActivityResult()
  11. {
  12. if (shouldRegisterForActivityResult())
  13. {
  14. resultHandler = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
  15. onActivityResult(result.data, requestCode, result.resultCode)
  16. this.requestCode = -1
  17. }
  18. }
  19. }
  20. fun startActivityForResult(requestCode: Int, intent: Intent)
  21. {
  22. this.requestCode = requestCode
  23. resultHandler?.launch(intent)
  24. }
  25. protected open fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
  26. {
  27. // For sub activities
  28. }
  29. protected open fun shouldRegisterForActivityResult(): Boolean
  30. {
  31. // Sub activities that need the onActivityResult "mechanism", should override this and return true
  32. return false
  33. }
  34. }

下面是子活动:

  1. class SubActivity : BaseActivity()
  2. {
  3. companion object
  4. {
  5. private const val SOME_REQUEST_CODE = 300
  6. }
  7. private fun testActivityResult()
  8. {
  9. val intent = Intent(this, OtherActivity::class.java)
  10. startActivityForResult(SOME_REQUEST_CODE, intent)
  11. }
  12. override fun shouldRegisterForActivityResult(): Boolean
  13. {
  14. return true
  15. }
  16. override fun onActivityResult(data: Intent?, requestCode: Int, resultCode: Int)
  17. {
  18. if (requestCode == SOME_REQUEST_CODE)
  19. {
  20. // Yes!
  21. }
  22. }
  23. }

希望它能帮助别人

展开查看全部
bkhjykvo

bkhjykvo5#

看来 onActivityResult 在超类中已弃用,但您没有提到超类名和 compileSdkVersion 这是你的问题。
在java和kotlin中,只要添加 @Deprecated 因此,检查你的超类,你可能会扩展一个错误的类。
当一个类被弃用时,它的所有方法也被弃用。
要查看快速解决方案,请单击不推荐的方法并按 Ctrl+Q 在androidstudio中,要查看该方法的文档,应该有一个解决方案。
在我的项目中使用 androidx 及api 29 as compileSdkVersion ,此方法在活动和片段中未被弃用

ikfrs5lh

ikfrs5lh6#

您可以为koltin使用扩展函数。例如:

  1. //random utils file
  2. fun Fragment.buildGetContentRequest(function: (Uri) -> Unit): ActivityResultLauncher<String> {
  3. return this.registerForActivityResult(ActivityResultContracts.GetContent()) {
  4. function(it)
  5. }
  6. }
  7. fun Fragment.buildTakePhotoRequest(function: (Boolean) -> Unit): ActivityResultLauncher<Uri> {
  8. return this.registerForActivityResult(ActivityResultContracts.TakePicture()) {
  9. function(it)
  10. }
  11. }
  12. fun Fragment.buildSelectMultipleContentRequest(function: (MutableList<Uri>?) -> Unit): ActivityResultLauncher<String> {
  13. return this.registerForActivityResult(ActivityResultContracts.GetMultipleContents()) {
  14. function(it)
  15. }
  16. }

然后在你的片段中,像这样的东西

  1. //your actual fragment logic
  2. class YourFragment : Fragment() {
  3. //we can assign our request in init process
  4. private val mRequestSelectFiles = buildSelectMultipleContentRequest {
  5. onFilesSelected(it)
  6. }
  7. fun onSelectFiles() {
  8. val mime = "*/*"
  9. mRequestSelectFiles.launch(mime)
  10. }
  11. fun onFilesSelected(list: MutableList<Uri>?) {
  12. //your logic
  13. }
  14. }
展开查看全部
ldfqzlk8

ldfqzlk87#

  1. ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
  2. new ActivityResultContracts.StartActivityForResult(),
  3. new ActivityResultCallback<ActivityResult>() {
  4. @Override
  5. public void onActivityResult(ActivityResult result) {
  6. if (result.getResultCode() == Activity.RESULT_OK) {
  7. }
  8. }
  9. });
gudnpqoy

gudnpqoy8#

@muntashir-akon解决方案的kotlin版本

  1. class BetterActivityResult<Input, Result> private constructor(
  2. caller : ActivityResultCaller,
  3. contract : ActivityResultContract<Input, Result>,
  4. var onActivityResult : ((Result) -> Unit)?,
  5. ) {
  6. private val launcher : ActivityResultLauncher<Input> =
  7. caller.registerForActivityResult(contract) { onActivityResult?.invoke(it) }
  8. /**
  9. * Launch activity, same as [ActivityResultLauncher.launch] except that it
  10. * allows a callback
  11. * executed after receiving a result from the target activity.
  12. */
  13. /**
  14. * Same as [.launch] with last parameter set to `null`.
  15. */
  16. @JvmOverloads
  17. fun launch(
  18. input : Input,
  19. onActivityResult : ((Result) -> Unit)? = this.onActivityResult,
  20. ) {
  21. this.onActivityResult = onActivityResult
  22. launcher.launch(input)
  23. }
  24. companion object {
  25. /**
  26. * Register activity result using a [ActivityResultContract] and an in-place
  27. * activity result callback like
  28. * the default approach. You can still customise callback using [.launch].
  29. */
  30. fun <Input, Result> registerForActivityResult(
  31. caller : ActivityResultCaller,
  32. contract : ActivityResultContract<Input, Result>,
  33. onActivityResult : ((Result) -> Unit)?,
  34. ) : BetterActivityResult<Input, Result> {
  35. return BetterActivityResult(caller, contract, onActivityResult)
  36. }
  37. /**
  38. * Same as [.registerForActivityResult] except
  39. * the last argument is set to `null`.
  40. */
  41. fun <Input, Result> registerForActivityResult(
  42. caller : ActivityResultCaller,
  43. contract : ActivityResultContract<Input, Result>,
  44. ) : BetterActivityResult<Input, Result> {
  45. return registerForActivityResult(caller, contract, null)
  46. }
  47. /**
  48. * Specialised method for launching new activities.
  49. */
  50. fun registerActivityForResult(
  51. caller : ActivityResultCaller,
  52. ) : BetterActivityResult<Intent, ActivityResult> {
  53. return registerForActivityResult(caller, StartActivityForResult())
  54. }
  55. }
  56. }
展开查看全部
bvk5enib

bvk5enib9#

android 10 api 30中不推荐使用startactivityforresult和onactivityresult,现在我们有了一种使用registerforactivityresult获得结果的新方法

  1. resultContract =
  2. registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
  3. if (result.resultCode == Activity.RESULT_OK) {
  4. // There are no request codes
  5. val country = result.data?.getParcelableExtra<Country>("Country")
  6. showLiveDemoDialogue(country)
  7. }
  8. }

并开展活动

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

但是你应该在呼叫launch和launch之前注册。否则,您将获得此异常

  1. attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
展开查看全部
kg7wmglp

kg7wmglp10#

另一种方法是分3步进行(考虑到您有一个startactivityforresult(0和onactivityresult())
在表单中创建一个变量 var resultLauncher:ActivityResultLauncher<Intent> 创建一个私有函数,在该函数中以此基本格式初始化resultlauncher

  1. resultLauncher=registerForActivityResult(ActivityResultContracts.StartActivityForResult()){result ->
  2. // copy paste the code from the onActivityResult replacing resultcode to result.resultCode
  3. if(result.resultcode==Activity.Result_OK){
  4. val data=result.data // this data variable is of type intent and you can use it
  5. }else{
  6. //code if you do not get the data
  7. }
  8. }

去排队 startActivityForResult() 并将其替换为线路 resultLauncher.launch(intent)

i34xakig

i34xakig11#

startactivityforresult和requestmultiplepermissions from activity和fragment的registerforactivityresult的简单示例[在kotlin中]

正在请求活动以获取活动的结果

  1. registerForActivityResult(
  2. ActivityResultContracts.StartActivityForResult()
  3. ) { activityResult ->
  4. if (activityResult.resultCode == Activity.RESULT_OK) {
  5. //...
  6. }
  7. }

查看activityresult

正在从“活动”请求权限?

  1. registerForActivityResult(
  2. ActivityResultContracts.RequestMultiplePermissions()
  3. ) {
  4. //it: Map<String, Boolean>
  5. }

来自碎片?

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

展开查看全部
ztyzrc3y

ztyzrc3y12#

基本培训可在developer.android.com上获得。
以下是如何将现有代码转换为新代码的示例:
老办法:

  1. public void openSomeActivityForResult() {
  2. Intent intent = new Intent(this, SomeActivity.class);
  3. startActivityForResult(intent, 123);
  4. }
  5. @Override
  6. protected void onActivityResult (int requestCode, int resultCode, Intent data) {
  7. if (resultCode == Activity.RESULT_OK && requestCode == 123) {
  8. doSomeOperations();
  9. }
  10. }

新方式(java):

  1. // You can do the assignment inside onAttach or onCreate, i.e, before the activity is displayed
  2. ActivityResultLauncher<Intent> someActivityResultLauncher = registerForActivityResult(
  3. new ActivityResultContracts.StartActivityForResult(),
  4. new ActivityResultCallback<ActivityResult>() {
  5. @Override
  6. public void onActivityResult(ActivityResult result) {
  7. if (result.getResultCode() == Activity.RESULT_OK) {
  8. // There are no request codes
  9. Intent data = result.getData();
  10. doSomeOperations();
  11. }
  12. }
  13. });
  14. public void openSomeActivityForResult() {
  15. Intent intent = new Intent(this, SomeActivity.class);
  16. someActivityResultLauncher.launch(intent);
  17. }

新方法(kotlin):

  1. var resultLauncher = registerForActivityResult(StartActivityForResult()) { result ->
  2. if (result.resultCode == Activity.RESULT_OK) {
  3. // There are no request codes
  4. val data: Intent? = result.data
  5. doSomeOperations()
  6. }
  7. }
  8. fun openSomeActivityForResult() {
  9. val intent = Intent(this, SomeActivity::class.java)
  10. resultLauncher.launch(intent)
  11. }

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

  1. import android.content.Intent;
  2. import androidx.activity.result.ActivityResult;
  3. import androidx.activity.result.ActivityResultCaller;
  4. import androidx.activity.result.ActivityResultLauncher;
  5. import androidx.activity.result.contract.ActivityResultContract;
  6. import androidx.activity.result.contract.ActivityResultContracts;
  7. import androidx.annotation.NonNull;
  8. import androidx.annotation.Nullable;
  9. public class BetterActivityResult<Input, Result> {
  10. /**
  11. * Register activity result using a {@link ActivityResultContract} and an in-place activity result callback like
  12. * the default approach. You can still customise callback using {@link #launch(Object, OnActivityResult)}.
  13. */
  14. @NonNull
  15. public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
  16. @NonNull ActivityResultCaller caller,
  17. @NonNull ActivityResultContract<Input, Result> contract,
  18. @Nullable OnActivityResult<Result> onActivityResult) {
  19. return new BetterActivityResult<>(caller, contract, onActivityResult);
  20. }
  21. /**
  22. * Same as {@link #registerForActivityResult(ActivityResultCaller, ActivityResultContract, OnActivityResult)} except
  23. * the last argument is set to {@code null}.
  24. */
  25. @NonNull
  26. public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(
  27. @NonNull ActivityResultCaller caller,
  28. @NonNull ActivityResultContract<Input, Result> contract) {
  29. return registerForActivityResult(caller, contract, null);
  30. }
  31. /**
  32. * Specialised method for launching new activities.
  33. */
  34. @NonNull
  35. public static BetterActivityResult<Intent, ActivityResult> registerActivityForResult(
  36. @NonNull ActivityResultCaller caller) {
  37. return registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());
  38. }
  39. /**
  40. * Callback interface
  41. */
  42. public interface OnActivityResult<O> {
  43. /**
  44. * Called after receiving a result from the target activity
  45. */
  46. void onActivityResult(O result);
  47. }
  48. private final ActivityResultLauncher<Input> launcher;
  49. @Nullable
  50. private OnActivityResult<Result> onActivityResult;
  51. private BetterActivityResult(@NonNull ActivityResultCaller caller,
  52. @NonNull ActivityResultContract<Input, Result> contract,
  53. @Nullable OnActivityResult<Result> onActivityResult) {
  54. this.onActivityResult = onActivityResult;
  55. this.launcher = caller.registerForActivityResult(contract, this::callOnActivityResult);
  56. }
  57. public void setOnActivityResult(@Nullable OnActivityResult<Result> onActivityResult) {
  58. this.onActivityResult = onActivityResult;
  59. }
  60. /**
  61. * Launch activity, same as {@link ActivityResultLauncher#launch(Object)} except that it allows a callback
  62. * executed after receiving a result from the target activity.
  63. */
  64. public void launch(Input input, @Nullable OnActivityResult<Result> onActivityResult) {
  65. if (onActivityResult != null) {
  66. this.onActivityResult = onActivityResult;
  67. }
  68. launcher.launch(input);
  69. }
  70. /**
  71. * Same as {@link #launch(Object, OnActivityResult)} with last parameter set to {@code null}.
  72. */
  73. public void launch(Input input) {
  74. launch(input, this.onActivityResult);
  75. }
  76. private void callOnActivityResult(Result result) {
  77. if (onActivityResult != null) onActivityResult.onActivityResult(result);
  78. }
  79. }

使用上述方法,您仍然必须在启动活动或片段附件之前或期间注册它。一旦定义,它就可以在活动或片段中重用。例如,如果需要在大多数活动中启动新活动,可以定义 BaseActivity 并注册一个新的 BetterActivityResult 这样地:
baseactivity.java

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

之后,您只需从任何子活动启动活动,如下所示:

  1. public void openSomeActivityForResult() {
  2. Intent intent = new Intent(this, SomeActivity.class);
  3. activityLauncher.launch(intent, result -> {
  4. if (result.getResultCode() == Activity.RESULT_OK) {
  5. // There are no request codes
  6. Intent data = result.getData();
  7. doSomeOperations();
  8. }
  9. })
  10. }

因为您可以将回调函数与 Intent ,您可以将其重新用于任何活动。
同样,您也可以使用其他两个构造函数使用其他活动契约。

展开查看全部
mm9b1k5b

mm9b1k5b13#

从现在起,, startActivityForResult() 已弃用,请使用新方法。
Kotlin示例

  1. fun openActivityForResult() {
  2. startForResult.launch(Intent(this, AnotherActivity::class.java))
  3. }
  4. val startForResult = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
  5. result: ActivityResult ->
  6. if (result.resultCode == Activity.RESULT_OK) {
  7. val intent = result.data
  8. // Handle the Intent
  9. //do stuff here
  10. }
  11. }
t2a7ltrp

t2a7ltrp14#

在Kotlin,我更改了代码

  1. startActivityForResult(intent, Constants.MY_CODE_REQUEST)

  1. override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
  2. super.onActivityResult(requestCode, resultCode, data)
  3. if (resultCode == Activity.RESULT_OK) {
  4. when (requestCode) {
  5. Constants.MY_CODE_REQUEST -> {
  6. ...
  7. }

  1. registerForActivityResult(StartActivityForResult()) { result ->
  2. onActivityResult(Constants.MY_CODE_REQUEST, result)
  3. }.launch(intent)

  1. private fun onActivityResult(requestCode: Int, result: ActivityResult) {
  2. if(result.resultCode == Activity.RESULT_OK) {
  3. val intent = result.data
  4. when (requestCode) {
  5. Constants.MY_CODE_REQUEST -> {
  6. ...

我希望它对你有用D

展开查看全部
jfgube3f

jfgube3f15#

新方法是: registerForActivityResult 优点:
新的方法是降低当我们从片段或另一个活动调用活动时所面临的复杂性
轻松请求任何许可并获得回拨
在Kotlin:

  1. var launchSomeActivity = registerForActivityResult(StartActivityForResult()) { result ->
  2. if (result.resultCode == Activity.RESULT_OK) {
  3. val data: Intent? = result.data
  4. // your operation...
  5. }
  6. }
  7. fun openYourActivity() {
  8. val intent = Intent(this, SomeActivity::class.java)
  9. launchSomeActivity.launch(intent)
  10. }

在java中:

  1. // Create lanucher variable inside onAttach or onCreate or global
  2. ActivityResultLauncher<Intent> launchSomeActivity = registerForActivityResult(
  3. new ActivityResultContracts.StartActivityForResult(),
  4. new ActivityResultCallback<ActivityResult>() {
  5. @Override
  6. public void onActivityResult(ActivityResult result) {
  7. if (result.getResultCode() == Activity.RESULT_OK) {
  8. Intent data = result.getData();
  9. // your operation....
  10. }
  11. }
  12. });
  13. public void openYourActivity() {
  14. Intent intent = new Intent(this, SomeActivity.class);
  15. launchSomeActivity.launch(intent);
  16. }
展开查看全部

相关问题