AndroidX Activity 改动 及ActivityResultLauncher 简单修改

google 在 androidX 上对 activity 及 fragment 部分功能调整(startActivityForResult ,requestPermission,Save/Restore InstanceState,onBackPress)简化为 callback 的可回调方式

使用(暂时还会修改,建议 beta 版再更)

 // build.gradle
 implementation 'androidx.activity:activity-ktx:1.2.0-alpha03'
 implementation 'androidx.fragment:fragment-ktx:1.3.0-alpha03'

demo

1 构造方法直接传 layoutId

class MyActivity : AppCompatActivity(R.layout.my_activity)
class MyFragmentActivity: FragmentActivity(R.layout.my_fragment_activity)
class MyFragment : Fragment(R.layout.my_fragment)

2 BackPress

class MyFragment : Fragment() {
  override fun onAttach(context: Context) {
    super.onAttach(context)
    val callback = object : OnBackPressedCallback(true) {
      override fun handleOnBackPressed() {
        // Do something
      }
    }
    requireActivity().onBackPressedDispatcher.addCallback(this, callback)
  }
}

3 SaveInstance

class MyActivity : AppCompatActivity() {
  companion object {
    private const val MY_SAVED_STATE_KEY = "my_saved_state"
    private const val SOME_VALUE_KEY = "some_value"
  }  
  private lateinit var someValue: String
    
  private val savedStateProvider = SavedStateRegistry.SavedStateProvider {    
    Bundle().apply {
      putString(SOME_VALUE_KEY, someValue)
    }
  }
  
  override fun onCreate(savedInstanceState: Bundle?) {    
    super.onCreate(savedInstanceState)
    savedStateRegistry
      .registerSavedStateProvider(MY_SAVED_STATE_KEY, savedStateProvider)
  }
  
  fun someMethod() {
    someValue = savedStateRegistry
      .consumeRestoredStateForKey(MY_SAVED_STATE_KEY)
      ?.getString(SOME_VALUE_KEY)
      ?: ""
  }
}

4 Permission 请求

val requestPermission = prepareCall(RequestPermission()) { isGranted ->
                toast("Location granted: $isGranted")
            }
requestPermission(ACCESS_FINE_LOCATION)

5 FragmentFactory

class MyFragmentFactory : FragmentFactory() {

  override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
    // 调用loadFragmentClass()获得Class对象
    val fragmentClass = loadFragmentClass(classLoader, className)
    // 现在,您可以使用className / fragmentClass来确定您的首选方式
    // 实例化Fragment对象,然后在此处进行操作。  
    // 或者调用常规FragmentFactory来实例化Fragment
    // 没有参数的构造函数
    return super.instantiate(classLoader, className)
  }
}

6 kotlin 对 FragmentManager 提供操作符

// Before
supportFragmentManager
  .beginTransaction()
  .add(R.id.container, MyFragment::class.java, null)
  .commit()

// After
supportFragmentManager.commit {
  replace<MyFragment>(R.id.container)
}

7 FragmentContainerView

如果您正在使用 FrameLayout  作为 Fragment 的父级,您应该切换到 FragmentContainerView代替。
它修复了一些动画z索引顺序问题和窗口插入调度。
FragmentContainerView 从 AndroidX Fragment 1.2.0 开始可用。

最后我们看下 startActivityForResult 使用、原理及参考源码做的修改
使用:MainActivity -> SecondActivity

class MainActivity : BaseActivity(R.layout.activity_main) {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        tvJump.setOnClickListener {
            prepareCall(StartSecondActivityForResultContract()){
                console("output",it)
            }.launch("input:哈哈")      
        }
    }
}

class StartSecondActivityForResultContract : ActivityResultContract<String, String>() {
    companion object {
        const val INPUT = "INPUT"
        const val OUTPUT = "OUTPUT"
    }
    override fun createIntent(context: Context, input: String?): Intent =
            Intent(context, SecondActivity::class.java).apply {
                putExtra(INPUT, input)
            }

    override fun parseResult(resultCode: Int, intent: Intent?): String? {
        return when (resultCode) {
            Activity.RESULT_OK -> intent?.getStringExtra(OUTPUT)
            else -> null
        }
    }
}
class SecondActivity : AppCompatActivity(R.layout.activity_second) {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        tvInput.text = intent?.getStringExtra(INPUT)?:"Null"
        btn.setOnClickListener {
            setResultAndFinish()
        }
    }
}

fun Activity.setResultAndFinish(){
    setResult(Activity.RESULT_OK, Intent().putExtra(OUTPUT," nice "))
    finish()
}

原理:观察者模式
1: prepareCall 会调用 ActivityResultRegistry 的 register 方法拿到 ActivityResultLauncher 对象
2: register 方法调用时 将 ActivityResultCallback 对象 登记在注册中心(ActivityResultRegistry) 的 Map 里
3: prepareCall 返回 ActivityResultLauncher对象后会调用 launch 方法
4: launch 方法会调用 ActivityResultRegistry 的抽象方法 invoke
5: 而 invoke 会 调用 startActivityForResult
6: 最终等 ComponentActivity 回调到 onActivityResult
7: 再通过 dispatchResult(requestCode, resultCode, data) 分发 result
8: 通过 requestCode 找到 key ,再从 Map 里 拿到 ActivityResultCallback 对象并调用 他的 onActivityResult( O result) 返回结果

以下是相关类图:

 

截屏2020-04-22下午8.47.17.png

上面 demo 代码并不简单,还需要创建 ActivityResultContract 实现类。虽然多了也可以像 google 的 ActivityResultContracts 那样管理,但对于我们还是只想知道
callback,不必关心 contracts。
于是我们可以根据这个思路做个精简版的 ActivityResultCallback

// MainActivity
prepareCall(ActivityResultCallback<String> { result ->
                console(
                    "output",
                    result ?: "Null"
                )
            }).launch(Intent(this, SecondActivity::class.java).apply {
                putExtra("INPUT", "hhhhh")
            })
// SecondActivity
class SecondActivity : BaseActivity(R.layout.activity_second) {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        tvInput.text = intent?.getStringExtra("INPUT") ?: "Null"
        btn.setOnClickListener {
            setResult(" nice ")
            finish()
        }
    }
}

hh, 没有 contracts 并且不用关心 extras 的 key 名字了
code 地址
end...
1:BaseActivity 相当于ComponentActivity 重写了 onActivityResult / setResult 等方法
2: ActivityResultRegistry 提供注册 分发 result 等gong n
2:另外需注意使用场景,result 需基本数据类型和序列化对象,数据量不能超过1m
注册中心代码:

abstract class ActivityResultRegistry {

    private val requestCodeToCallback = SparseArray<ActivityResultCallback<*>>()
    private val code = AtomicInteger(0)

    fun <O> register(
        owner: LifecycleOwner,
        callback: ActivityResultCallback<O>
    ): ActivityResultLauncher {
        val requestCode = code.getAndIncrement()
        requestCodeToCallback.put(requestCode, callback)
        val lifecycle = owner.lifecycle
        lifecycle.addObserver(LifecycleEventObserver { _, event ->
            if (Lifecycle.Event.ON_DESTROY == event) {
                unregister(requestCode)
            }
        })
        return ActivityResultLauncher {
               intent -> invoke(requestCode, intent)
        }
    }

    abstract operator fun invoke(rc: Int, intent: Intent?)

    private fun unregister(requestCode: Int) {
        requestCodeToCallback.remove(requestCode)
    }

    fun dispatchResult(requestCode: Int, resultCode: Int, data: Intent?): Boolean {
        val callback = requestCodeToCallback[requestCode] ?: return false
        doDispatch(resultCode, data, callback)
        return true
    }

    @Suppress("UNCHECKED_CAST")
    private fun <O> doDispatch(
        resultCode: Int, data: Intent?,
        callback: ActivityResultCallback<O?>?
    ) {
        if (resultCode == Activity.RESULT_OK)
            callback?.onGetResult(data?.extras?.get(OUTPUT_EXTRA) as O?)
    }
}



作者:半只温柔
链接:https://www.jianshu.com/p/e76bfccbb80d
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值