美文网首页
自定义返回导航

自定义返回导航

作者: ErolC鱼 | 来源:发表于2021-01-20 19:37 被阅读0次

今天逛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加上。

相关文章

网友评论

      本文标题:自定义返回导航

      本文链接:https://www.haomeiwen.com/subject/stqlzktx.html