今天逛Android官方文档的时候发现了一个比较简单也有点意思的东西。自定义返回导航。这篇文章就这个简单说一下:
自定义返回导航是啥;
怎么用;
简单场景;
看一下源码;
什么是自定义返回导航
简单点来说就是可以对返回进行拦截了。有人就会说了:之前也可以拦截呀!!
对,以前对后退做拦截的的方式基本上是对onKeyDown
方法做拦截(也可以对onBackPressed
做拦截),但onKeyDown
职能比较多,包含了很多物理按键,现在android官方将返回拿出来单独处理肯定会好一点的(原理就是对onBackPressed
做拦截)。
是这样的
通过activity的getOnBackPressedDispatcher()
方法你可以得到一个OnBackPressedDispatcher
,看名字就知道,这是用来调度返回用的,而我们可以通过它的addCallback
方法将我们想要的返回逻辑加给他,就像这样:
val callback = onBackPressedDispatcher.addCallback(this,true){
//back code
}
这是kotlin对addCallback
优化的一个扩展函数,如果是java的话,是这样的:
OnBackPressedCallback callback = new OnBackPressedCallback(true) {//true 开启自定义返回逻辑
@Override
public void handleOnBackPressed() {
//back code
}
};
getOnBackPressedDispatcher().addCallback(callback);
然后我们可以通过callback的setEnabled
方法对这个自定义返回逻辑开启和关闭。callback.setEnabled(false);
关闭返回拦截,最主要的功能就这么多。
一个实现场景
我使用自定义返回导航改了一下之前写的后退提示,通常在退出最后一个activity的时候提醒一下用户:再点击就退出这个app啦
这样的需求。改后对比了一下简洁了好多(也因为是kotlin):
fun AppCompatActivity.exit(message: String = "再按一次返回键退出", duration: Int = Toast.LENGTH_SHORT) {
onBackPressedDispatcher.addCallback(this, true) {
val toast = Toast.makeText(this@exit, message, duration)
toast.show()
isEnabled = false
toast.view.postDelayed(
Runnable {
isEnabled = true
},
if (toast.duration == Toast.LENGTH_SHORT) 4000 else 7000)
}
}
最后看一下源码
我们除了要知道怎么用之外,最好要知道怎么实现的,这样知识才是完整的。而且有关自定义返回导航的代码也不多,完完全全加起来还不够一千行应该。
从androidX
开始,在activity中(准确来说是在ComponentActivity这一层)后退部分的逻辑变了,变成这样了
//ComponentActivity
public void onBackPressed() {
mOnBackPressedDispatcher.onBackPressed();
}
后退的逻辑全都交给了后退调度器了。
点进去一看:
//OnBackPressedDispatcher
public void onBackPressed() {
Iterator<OnBackPressedCallback> iterator =
mOnBackPressedCallbacks.descendingIterator();//得到所有注册到调度器中的各种后退逻辑
while (iterator.hasNext()) {
OnBackPressedCallback callback = iterator.next();
if (callback.isEnabled()) {//如果callback是可用的话
callback.handleOnBackPressed();//执行自定义后退逻辑
return;
}
}
if (mFallbackOnBackPressed != null) {//如果没有执行任何自定义后退逻辑,那么就执行一下这个,如果mFallbackOnBackPressed存在的话
mFallbackOnBackPressed.run();
}
}
但是我们始终没有看到原本后退的逻辑,也就是返回到上一个activity的后退逻辑,但是有这么个东西mFallbackOnBackPressed
,无论从逻辑还是名字,原本的后退逻辑
这个逻辑应该就藏在这个run方法里了。
往上找找这个实例:
//OnBackPressedDispatcher
public OnBackPressedDispatcher(@Nullable Runnable fallbackOnBackPressed) {
mFallbackOnBackPressed = fallbackOnBackPressed;
}
原来是初始化的时候设置的,那我们就可以回到ComponentActivity再看看OnBackPressedDispatcher是在哪里被实例化的了:
//ComponentActivity
private final OnBackPressedDispatcher mOnBackPressedDispatcher =
new OnBackPressedDispatcher(new Runnable() {
@Override
public void run() {
ComponentActivity.super.onBackPressed();//原本的后退逻辑
}
});
好了,整个逻辑下来就通了。
小建议
在使用自定义返回导航的时候,注意把LifecycleOwner
加上。
网友评论