110/01 - 什麽!startActivityForResult 被标记弃用?

讲到硬体就会用到权限控制,然後一定会用onActivityResultstartActivityForResult
结果上面这两个在最新的版本已经被标记弃用

让我们看看原始码

@SuppressWarnings("deprecation")
@Override
@CallSuper
protected void onActivityResult(int requestCode,int resultCode,@Nullable Intent data){
        mFragments.noteStateNotSaved();
        super.onActivityResult(requestCode,resultCode,data);
        }

/**
 * {@inheritDoc}
 *
 * @deprecated use
 * {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
 * passing in a {@link StartActivityForResult} object for the {@link ActivityResultContract}.
 */
@Override
@Deprecated
public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,int requestCode){
        super.startActivityForResult(intent,requestCode);
        }

/**
 * {@inheritDoc}
 *
 * @deprecated use
 * {@link #registerForActivityResult(ActivityResultContract, ActivityResultCallback)}
 * passing in a {@link StartActivityForResult} object for the {@link ActivityResultContract}.
 */
@Override
@Deprecated
public void startActivityForResult(@SuppressLint("UnknownNullness") Intent intent,int requestCode,@Nullable Bundle options){
        super.startActivityForResult(intent,requestCode,options);
        }

现在Google建议使用 Activity Results API
所以现在来实作怎麽使用

首先是Activity带值互相跳页的写法
建立MainActivitySaberActivityArcherActivity
MainActivity跳到SaberActivityArcherActivity时会带姓名
SaberActivityArcherActivity离开页面後会回传武器

MainActivity画面如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    tools:context=".MainActivity">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/amMbSaber"
        android:layout_width="match_parent" 
        android:layout_height="0dp"
        android:layout_marginStart="8dp" 
        android:layout_marginTop="4dp"
        android:layout_marginEnd="8dp" 
        android:text="跳转 SaberActivity"
        android:textAllCaps="false"
        app:layout_constraintDimensionRatio="5:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <com.google.android.material.button.MaterialButton 
        android:id="@+id/amMbArcher"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="跳转 ArcherActivity"
        android:textAllCaps="false"
        app:layout_constraintDimensionRatio="5:1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/amMbSaber" />
</androidx.constraintlayout.widget.ConstraintLayout>

SaberActivity画面如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".SaberActivity">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/asMbMain"
        android:layout_width="match_parent" 
        android:layout_height="0dp"
        android:layout_marginStart="8dp" 
        android:layout_marginTop="4dp"
        android:layout_marginEnd="8dp" 
        android:text="跳转 Main 回传 Excalibur"
        android:textAllCaps="false" 
        app:layout_constraintDimensionRatio="5:1"
        app:layout_constraintEnd_toEndOf="parent" 
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

ArcherActivity画面如下

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools" 
    android:layout_width="match_parent"
    android:layout_height="match_parent" 
    tools:context=".ArcherActivity">

    <com.google.android.material.button.MaterialButton 
        android:id="@+id/aaMbMain"
        android:layout_width="match_parent" 
        android:layout_height="0dp"
        android:layout_marginStart="8dp" 
        android:layout_marginTop="4dp"
        android:layout_marginEnd="8dp" 
        android:text="跳转 Main 回传 Unlimited Blade Works"
        android:textAllCaps="false" 
        app:layout_constraintDimensionRatio="5:1"
        app:layout_constraintEnd_toEndOf="parent" 
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity程序码的部份,以前是建立onActivityResult监听资料
现在改成建立合约(Contract)和启动器(Launcher)

所以我们先在MainActivity建立启动器,里面的监听跟以前onActivityResult的写法一样

private val resultLauncher =
    registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
        if (RESULT_OK == activityResult.resultCode) {
            Log.d(
                "maho",
                "回传: ${activityResult.data?.getStringExtra(BaseConstants.WEAPON)}"
            )
        }
    }

至於跳页,以前我们使用startActivity(intent),因为建立启动器的关系,所以改用启动器执行

//跳转到SaberActivity
val intent = Intent(this, SaberActivity::class.java).apply {
    this.putExtra(BaseConstants.NAME, "Arthur")
}

resultLauncher.launch(intent)

//跳转到ArcherActivity
val intent = Intent(this, ArcherActivity::class.java).apply {
    this.putExtra(BaseConstants.NAME, "Emiya")
}

resultLauncher.launch(intent)

MainActivity全部的程序码是这样

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initClickListener()
    }

    private fun initClickListener() {
        amMbSaber.setOnClickListener {
            val intent = Intent(this, SaberActivity::class.java).apply {
                this.putExtra(BaseConstants.NAME, "Arthur")
            }

            resultLauncher.launch(intent)
        }

        amMbArcher.setOnClickListener {
            val intent = Intent(this, ArcherActivity::class.java).apply {
                this.putExtra(BaseConstants.NAME, "Emiya")
            }

            resultLauncher.launch(intent)
        }
    }

    private val resultLauncher =
        registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { activityResult ->
            if (RESULT_OK == activityResult.resultCode) {
                Log.d(
                    "maho",
                    "回传: ${activityResult.data?.getStringExtra(BaseConstants.WEAPON)}"
                )
            }
        }
}

跳转後的程序码,写法和以前一样

class SaberActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_saber)

        val name = intent.getStringExtra(BaseConstants.NAME)
        Log.d("maho", "姓名: $name")

        initClickListener()
    }

    private fun initClickListener() {
        asMbMain.setOnClickListener {

            val intent = Intent().apply {
                this.putExtra(BaseConstants.WEAPON, "Excalibur")
            }

            setResult(RESULT_OK, intent)
            finish()
        }
    }
}


class ArcherActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_archer)

        val name = intent.getStringExtra(BaseConstants.NAME)
        Log.d("maho", "姓名: $name")

        initClickListener()
    }

    private fun initClickListener() {
        aaMbMain.setOnClickListener {

            val intent = Intent().apply {
                this.putExtra(BaseConstants.WEAPON, "Unlimited Blade Works")
            }

            setResult(RESULT_OK, intent)
            finish()
        }
    }
}

实际执行程序後的Log

tw.com.andyawd.androidsystem D/maho: 姓名: Arthur
tw.com.andyawd.androidsystem D/maho: 回传: Excalibur
tw.com.andyawd.androidsystem D/maho: 姓名: Emiya
tw.com.andyawd.androidsystem D/maho: 回传: Unlimited Blade Works

所以我们已经跨出第一步,不使用onActivityResult监听Result
改成使用合约(Contract)和启动器(Launcher)监听Result
接下来几天会继续讲解Activity Results API的用法

程序码放在feature/result分支
https://github.com/AndyAWD/AndroidSystem/tree/feature/result


<<:  前言&动机

>>:  Day 16-隔离框架 (isolation Framework) - NSubstitute 基本介绍 (核心技术-8)

自动化 End-End 测试 Nightwatch.js 之踩雷笔记:等待时间

在测试一个网页时,时常会有需要等待的时候,可能是等待网页载入、等待 UI 显示或等待搜寻结果等 pa...

Day30 I’m on the next level

Summary 承续昨天所说,我们将PivotTable.js的版面调整,让资料区域的表格和图表可...

【Day 8】Google Apps Script - 依文件实作 Demo 用的 API

依文件的描述撰写 API,实作时如果发现有实作的问题,再反馈讨论修正。 今日要点: 》制作 API...

Day.26 「闭包要谨慎使用!」 —— JavaScript 闭包(Closure)

我们前面已经认识了函式作用域,也了解了回调函式,但有时候会产生意想不到的事情,造成内存问题,其中一...

Day 0x8 UVa10193 All You Need Is Love

Virtual Judge ZeroJudge 题意 输入两字串 S1、S2,问是否能找出对两字串...