6
requestPermissions
requestPermissions/onRequestPermissionsResult
底层也是基于
startActivityForResult/onActivityResult
实现的,因此同样被废弃了,升级为 Result API 的方式。
ActivityResultContracts
预置了申请权限相关的 Contract:
request_permission.setOnClickListener {
requestPermission.launch(permission.BLUETOOTH)
}
request_multiple_permission.setOnClickListener {
requestMultiplePermissions.launch(
arrayOf(
permission.BLUETOOTH,
permission.NFC,
permission.ACCESS_FINE_LOCATION
)
)
}
// 申请单一权限
private
val
requestPermission =
registerForActivityResult(ActivityResultContracts.RequestPermission) { isGranted ->
// Do something if permission grantedif (isGranted) toast("Permission is granted")
else
toast(
"Permission is denied"
)
}
// 一次申请多权限
private
val
requestMultiplePermissions =
registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions) { permissions : Map<String,
Boolean
> ->
// Do something if some permissions granted or denied
permissions.entries.forEach {
// Do checking here
}
}
7
setTargetFragment
setTargetFragment/getTargetFragment
原本用于 Fragment 之间的通信,例如从 FragmentA 跳转到 FragmentB ,在 B 中发送结果返回给 A:
// 向 FragmentB 设置 targetFragment
FragmentB fragment =
new
FragmentB;
fragment.setTargetFragment(FragmentA.
this
, AppConstant.REQ_CODE_SECOND_FRAGMENT);
//切换至 FragmentB
transaction.replace(R.id.fragment_container, fragment).commit;
// FragmentB 中获取 FragmentA 并进行回调
Fragment fragment = getTargetFragment;
fragment.onActivityResult(AppConstant.REQ_CODE_SECOND_FRAGMENT, Activity.RESULT_OK, inte
如上,代码非常简单,但是这样的通信无法感应生命周期,即使 FragmentA 处于后台也会在
onActivityResult
响应回调。目前
TargetFragment
相关 API 已经被废弃,取而代之的是更为合理的 Fragment Result API。
假设需要在 FragmentA 监听 FragmentB 返回的数据,首先在 FragmentA 设置监听。
override
fun
onCreate
(savedInstanceState:
Bundle
?)
{
super
.onCreate(savedInstanceState)
// setFragmentResultListener 是 fragment-ktx 提供的扩展函数
setFragmentResultListener(
"requestKey"
) { requestKey, bundle ->
// 监听key为“requestKey”的结果, 并通过bundle获取
val
result = bundle.getString(
"bundleKey"
)
// ...
}
}
// setFragmentResultListener 是Fragment的扩展函数,内部调用 FragmentManger 的同名方法
public
fun
Fragment.
setFragmentResultListener
(
requestKey:
String
,
listener: ((
requestKey
:
String
, bundle:
Bundle
) ->
Unit
)
) {
parentFragmentManager.setFragmentResultListener(requestKey,
this
, listener)
}
当从 FragmentB 返回结果时:
val
result =
"result"
setFragmentResult(
"requestKey"
, bundleOf(
"bundleKey"
to result))
//setFragmentResult 也是 Fragment 的扩展函数,其内部调用 FragmentManger 的同名方法
public
fun
Fragment.
setFragmentResult
(requestKey:
String
, result:
Bundle
)
{
parentFragmentManager.setFragmentResult(requestKey, result)
}
上面的代码可以用下图表示:
FragmentA 通过 Key 向
FragmentManager
注册
ResultListener
,FragmentB 返回 result 时, FM 通过 Key 将结果回调给FragmentA ,而且最重要的是 Result API 是生命周期可感知的,
listener.onFragmentResult
在
Lifecycle.Event.ON_START
的时候才调用,也就是说只有当 FragmentA 返回到前台时,才会收到结果。
关于 Fragment Result API 的更多介绍,可以参考:
盘点一下 Fragment 间的几种通信方式
8
最后
Fragment 是帮助我们组织和管理 UI 的重要组件,即使在 Compose 时代也具有使用价值,因此谷歌官方一直致力于对它的 API 的优化,希望它更加易用和便于测试。这些已废弃的 API 在未来的版本中将会彻底删除,所以如果你还在使用着他们,应该尽快予以替换。
官方也提供了工具帮助我们发现对于过期 API 的使用,Fragment-1.4.0 之后,我们可以通过全局设置严格模式策略,发现项目中的问题:
class
MyApplication
:
Application
{
override
fun
onCreate
{
super
.onCreate
FragmentStrictMode.defaultPolicy =
FragmentStrictMode.Policy.Builder
.detectFragmentTagUsage
//setTargetFragment的使用
.detectRetainInstanceUsage
//setRetainInstance的使用
.detectSetUserVisibleHint
//setUserVisibleHint的使用
.detectTargetFragmentUsage
//setTargetFragment的使用
.apply {
if
(BuildConfig.DEBUG) {
// Debug 模式下崩溃
penaltyDeath
}
else
{
// Release 模式下上报
penaltyListener {
FirebaseCrashlytics.getInstance.recordException(it)
}
}
}
.build
}
}
关于 FragmentStrictMode 的更多内容,请参考:
https://developer.android.com/guide/fragments/debugging#strictmode
最后推荐一下我做的网站,玩Android:
wanandroid.com
,包含详尽的知识体系、好用的工具,还有本公众号文章合集,欢迎体验和收藏!
:
Android 实现菜单拖拽排序, so easy
货拉拉 Android H5离线包原理与实践
这交互炸了系列,自定义 View 实现汉字笔顺动画
点击
关注我的公众号
如果你想要跟大家分享你的文章,欢迎投稿~
┏(^0^)┛明天见!
返回搜狐,查看更多