草庐IT

startActivityForResult废弃了,用Activity Result API吧

Chen_ShengJie 2023-04-16 原文

因为项目中突然需要用到两个activity之间进行数据交互,脑子里第一想法就是用EventBus来实现,但是需求仅仅只有2个activity之间进行交互(神奇的需求?),所以考虑几百年前用过的startActivityForResult来实现,但撸代码的时候发现,它过时了!!!

 如果你将项目中的appcompat库升级到1.3.0或更高的版本,startActivityForResult()方法就已经显示被废弃了,因为项目中引入的就是1.3.0的

所以才发现过时的,如果版本低了,我还蒙在鼓里。

     废弃了,自然有替代品。新欢胜旧爱,官网建议用Activity Result API来取代startActivityForResult了。

   OK,先回顾下startActivityForResult的用法,它主要作用就是用于两个activity之间传递数据,例如:

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<Button>(R.id.btn1).setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            val  bundle=Bundle()
            bundle.putString("key","from MainActivity data")
            intent.putExtras(bundle)
            startActivityForResult(intent, 1)
        }

    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            1 ->
                if (resultCode == RESULT_OK) {
                    val stringExtra = data?.getStringExtra("data")
                    Log.e("TAG", "onActivityResult: $stringExtra")
                }
        }
    }
}

在MainActivity里通过点击一个按钮,往Bundle里添加数据,然后放到intent里,通过startActivityForResult向SecondActivity传递数据,并且重写了onActivityResult()方法去解析SecondActivity返回来的数据。

SecondActivity就稍微简单点了,先获取到MainActivity传递过来的数据,然后再点击一个按钮,发送新的数据返回给MainActivity。

class SecondActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_second)
        val extras = intent.extras
        val data = extras?.getString("key")
        Log.e("SecondActivity", "onCreate: $data" )
        findViewById<Button>(R.id.btn).setOnClickListener {
            val intent = Intent()
            intent.putExtra("data", "data from SecondActivity")
            setResult(RESULT_OK, intent)
            finish()
        }
    }
}

以上代码应该没毛病,早几年每个项目百分百会用到的.

结果显而易见,从MainActivity点击按钮跳转到SecondActivity界面会打印 

SecondActivity: onCreate: from MainActivity data

然后在SecondActivity点击按钮回到MainActivity打印

TAG: onActivityResult: data from SecondActivity

接着我们学习一下如何使用Activity Result API来实现同样的功能。

import androidx.activity.result.contract.ActivityResultContracts

class MainActivity : AppCompatActivity() {

    private val requestDataLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == RESULT_OK) {
            val data = result.data?.getStringExtra("data")
            Log.e("TAG", "registerForActivityResult: $data")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<Button>(R.id.btn1).setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            val bundle = Bundle()
            bundle.putString("key", "from MainActivity data")
            intent.putExtras(bundle)
            requestDataLauncher.launch(intent)
           // startActivityForResult(intent, 1)
        }

    }
}

SecondActivity完全不用动,代码不用变。主要看下MainActivity的代码改动,移除了对onActivityResult()方法的重写,而是调用registerForActivityResult()方法来注册一个对Activity结果的监听。registerForActivityResult()方法接收两个参数,第一个参数是一种Contract类型,由于我们是希望从另外一个Activity中请求数据,因此这里使用了StartActivityForResult这种Contract。第二个参数是一个Lambda表达式,当有结果返回时则会回调到这里,然后我们在这里获取并处理数据即可。

  @NonNull
    @Override
    public final <I, O> ActivityResultLauncher<I> registerForActivityResult(
            @NonNull ActivityResultContract<I, O> contract,
            @NonNull ActivityResultCallback<O> callback) {
        return registerForActivityResult(contract, mActivityResultRegistry, callback);
    }

从源码可以看到registerForActivityResult返回的是ActivityResultLauncher对象,

 可以看到该对象当中有launch()方法可以用于去启用Intent。所以我们的代码中就能使用

 requestDataLauncher.launch(intent)去进行调整,从而代替startActivityForResult()方法。

以上代码运行效果和startActivityForResult()的完全一致。如果说单纯从数据跳转传递来讲,这也差不多呀。没啥优势的。

再来个例子,多任务之间进行区分。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<Button>(R.id.btn1).setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            val bundle = Bundle()
            bundle.putString("key", "from MainActivity data1")
            intent.putExtras(bundle)
            startActivityForResult(intent, 1)
        }
        findViewById<Button>(R.id.btn2).setOnClickListener {
            val intent = Intent(this, ThreeActivity::class.java)
            val bundle = Bundle()
            bundle.putString("key", "from MainActivity data2")
            intent.putExtras(bundle)
            startActivityForResult(intent, 2)
        }
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        when (requestCode) {
            1 -> {
                if (resultCode == RESULT_OK) {
                    val stringExtra = data?.getStringExtra("data")
                    Log.e("TAG", "onActivityResult: 1$stringExtra")
                }
            }
            2 ->
                if (resultCode == RESULT_OK) {
                    val stringExtra = data?.getStringExtra("data")
                    Log.e("TAG", "onActivityResult: 2 $stringExtra")
                }
        }
    }
}

通过设置不同的requestCode值来区分传递不同界面的数据。因此获取返回的数据时也要在onActivityResult()方法当中,再对requestCode进行判断。这种传统的写法,大家应该都很熟悉,也见得多了,那么看下Activity Result API是怎么实现这种多任务的数据传递接收的

class MainActivity : AppCompatActivity() {

    private val requestDataOneLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                val data = result.data?.getStringExtra("data")
                Log.e("TAG", "registerForActivityResult:one  $data")
            }
        }
    private val requestDataTwoLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
            if (result.resultCode == RESULT_OK) {
                val data = result.data?.getStringExtra("data")
                Log.e("TAG", "registerForActivityResult:two  $data")
            }
        }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        findViewById<Button>(R.id.btn1).setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            val bundle = Bundle()
            bundle.putString("key", "from MainActivity data1")
            intent.putExtras(bundle)
            requestDataOneLauncher.launch(intent)
          
        }
        findViewById<Button>(R.id.btn2).setOnClickListener {
            val intent = Intent(this, SecondActivity::class.java)
            val bundle = Bundle()
            bundle.putString("key", "from MainActivity data2")
            intent.putExtras(bundle)
            requestDataTwoLauncher.launch(intent)

        }
    }
}

通过ActivityResultLauncher不同对象处理不同的任务数据,无需借助requestCode数字来判断,万一数字多了不对,还容易出错。所以Activity Result API存在是有一定的合理性的。

有关startActivityForResult废弃了,用Activity Result API吧的更多相关文章

  1. android - 无法使用 "startActivityForResult"启动第二个 Activity - 2

    与标题相同:我已经尝试使用“startActivity”,但结果相同。当我按下fab按钮时,它会显示HomeActivity。希望你能帮助我。想从这里发送人员名单家庭Activity:publicclassHomeActivityextendsAppCompatActivity{privateRecyclerViewmRecyclerView;privateRecyclerView.AdaptermAdapter;privateRecyclerView.LayoutManagermLayoutManager;publicArrayListresult=newArrayList();@O

  2. javascript - 为什么 ECMAScript 第 4 版被完全废弃了? - 2

    我一直在寻找有关废弃的ECMAScript4thEdition的一些信息,但没有取得太大成功,即使是在SO上也是如此。我知道Mozilla的JavaScript1.7实现了第4版中提供的许多(全部?)新功能,我想我记得关于它的一篇很好的JohnResig帖子,但我现在似乎无法在他的博客上找到它。特别是,我想知道为什么它被完全废弃以支持ECMA-262第5版,以及为什么它没有得到改进。其中一些功能非常酷,例如生成器、迭代器、let、新赋值运算符和(我特别喜欢的)解构赋值。我知道所有这些特殊功能只会在具有过时ECMAScript实现的浏览器中抛出错误,但为什么不包括它们,因为总有一天这些实

  3. ios - 我是否需要完全废弃我的应用程序才能添加核心数据? - 2

    我是初学者,当我第一次制作这个应用程序(简单的待办事项列表应用程序)时,我不知道CoreData。现在我正在尝试实现核心数据,但似乎如果我想这样做,我基本上必须完全改变我的应用程序。例如,我用CoreData创建了一个新的MasterDetail应用程序,并将其与我当前的应用程序进行比较,基本上两者都不相同。一个特别令人困惑的部分是,在我当前的TableView中,我有两个部分从两个不同的数组中获取它们的对象。如果我要添加CoreData,我会不知道该怎么做。我是否必须完全消除数组并仅使用NSFetchedResultsController?此外,在我的应用程序中,我有模态视图Cont

  4. Android:startActivityForResult 的 resultCode 总是为 0? - 2

    这个问题不太可能帮助任何future的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visitthehelpcenter.关闭10年前。出于某种原因,当我使用该调用时,结果始终返回0。我所做的只是弹出选择框,然后在做出选择后,用户点击后退按钮。有谁知道我可能犯了什么错误?通话Activity:Intenti=newIntent(this,Selection.class);Log.d("Front-End","LaunchingActivity");startActivityForResu

  5. java - startActivityForResult(Intent, int) 整数参数的目的是什么 - 2

    我正在学习使用“startActivityForResult”函数的教程。我知道为什么要使用这个函数,如果我们想使用返回的数据,我们使用onActivityResult()函数。我想知道的是,为什么我们要将Integer传递给startActivityForResult()函数?它用在什么地方?感谢您的帮助! 最佳答案 当您开始的Activity完成时,第二个参数将传递给调用Activity的方法onActivityResult()。这是为了区分不同的结果。您可能遇到这样的情况,一个Activity需要调用其他几个Activity来

  6. android - startActivityForResult 似乎没有调用 onActivityResult - 2

    当用户单击要调用对话框的按钮时-该对话框包含ListView中的产品列表。用户选择产品后,它应该进入上一个Activity。我已经使用startActivityForResult()完成了。有一些问题。我的调用Activity在正常标签Activity中,正常标签Activity在标签Activity组中。实际上我想在drropdown(Spinner)中做。在我的scanerio中我无法获取上下文。它awalys给AndroidSpinnerError:android.view.WindowManager$BadTokenException:Unabletoaddwindow所以我对

  7. android - 如何在从布局 : main. xml 初始化的类中调用 startActivityForResult - 2

    这与“我怎样才能将数据从新数据检索到旧数据”是同一个问题。但在我的第一个Activity中,我调用了setContentView(R.layout.main);。canvas上有一个surfaceview绘图。我知道的唯一方法是调用getContext()获取上下文,然后调用startActivity()。但是我不能从我得到的上下文中调用startActivityForResult(),它似乎不支持,我只需要在我的Activity类中调用它。谁能给我意见?编辑:这是我的代码:publicclassgameViewextendsSurfaceViewimplementsSurfaceHo

  8. Android 你能从链式 startActivityForResult 获得 Activity 结果吗 - 2

    我有以下Activity屏幕ActivityA-包含一个链接到ActivityB的按钮ActivityB-包含订单确认,然后是打开ActivityC(以捕获签名)的“下一步”按钮ActivityC-弹出一个对话框供用户输入他们的签名和一个完成按钮。ActivityA-包含启动ActivityB的Intent开始并实现onActivityForResultIntentintent=newIntent(this,ConfirmLines.class);startActivityForResult(intent,GET_SIGNATURE);protectedvoidonActivityRe

  9. android startActivityForResult 街景获取数据 - 2

    如何从街景中获取结果?比如Lat,Lng,Pitch,heading,FOV,Zoom...等等。我想做一个Activity,点击“步行”按钮打开街景。用户走到某个位置,保存它。我尝试使用startActivityForResult来查看街景,但我无法选择位置。它只是打开了一个仅供查看的街景。IntentstreetView=newIntent(android.content.Intent.ACTION_VIEW,Uri.parse("google.streetview:cbll="+objLatitude+","+objLongitude+"&cbp=1,99.56,,1,-5.27

  10. Android:singleInstance 和 startActivityForResult - 2

    据我所知,startActivityForResult无法与launchModesingleInstance一起正常工作here.而最近,我发现它在AndroidLollipop(5.0)上运行良好并且找不到描述它的官方文档。我认为这也同时与任务和返回堆栈有关。有没有人可以提供一些关于它的信息或解释或任何关于它的信息?谢谢:) 最佳答案 https://stackoverflow.com/questions/8960072/onactivityresult-with-launchmode-singletask这是一个简短的解释。答案

随机推荐