前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Android | Jetpack 处理回退事件的新姿势 —— OnBackPressedDispatcher

Android | Jetpack 处理回退事件的新姿势 —— OnBackPressedDispatcher

作者头像
用户9995743
发布于 2022-09-26 12:40:45
发布于 2022-09-26 12:40:45
1.9K00
代码可运行
举报
文章被收录于专栏:彭旭锐彭旭锐
运行总次数:0
代码可运行

前言

  • 从 androidx.activity 1.0.0 开始,Google 引入 OnBackPressedDispatcher API 来处理回退事件,旨在优化回退事件处理:你可以在任何位置定义回退逻辑,而不是依赖于 Activity#onBackPressed();
  • 在这篇文章里,我将介绍 OnBackPressedDispatcher 的使用方法 & 实现原理 & 应用场景。如果能帮上忙,请务必点赞加关注,这真的对我非常重要。

目录

1. 概述

  • OnBackPressedDispatcher 解决了什么问题: 在 Activity 里可以通过回调方法 onBackPressed() 处理,而 Fragment / View 却没有直接的回调方法。现在,我们可以使用 OnBackPressedDispatcher 替代 Activity#onBackPressed(),更优雅地实现回退逻辑。
  • OnBackPressedDispatcher 的整体处理流程: 分发器整体采用责任链设计模式,向分发器添加的回调对象都会成为责任链上的一个节点。当用户触发返回键时,将按顺序遍历责任链,如果回调对象是启用状态(Enabled),则会消费该回退事件,并且停止遍历。如果最后事件没有被消费,则交回到 Activity#onBackPressed() 处理。
  • OnBackPressedDispatcher 与其他方案对比: 在 OnBackPressedDispatcher 之前,我们只能通过 “取巧” 的方法处理回退事件:
    • 1、在 Fragment 中定义回调方法,从 Activity#onBackPressed() 中传递回调事件(缺点:增加了 Activity & Fragment 的耦合关系);
    • 2、在 Fragment 根布局中设置按键监听 setOnKeyListener(缺点:不灵活 & 多个 Fragment 监听冲突)。

2. OnBackPressedDispatcher 有哪些 API?

主要有以下几个,其他这几个 API 都比较好理解。其中 addCallback(LifecycleOwner, callback) 会在生命周期持有者 LifecycleOwner 进入 Lifecycle.State.STARTED 状态,才会加入分发责任链,而在 LifecycleOwner 进入 Lifecycle.State.STOP 状态时,会从分发责任链中移除。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
1、添加回调对象
public void addCallback(OnBackPressedCallback onBackPressedCallback)

2、添加回调对象,关联到指定生命周期持有者
public void addCallback(LifecycleOwner owner, OnBackPressedCallback onBackPressedCallback)

3、判断是否有启用的回调
public boolean hasEnabledCallbacks()

4、回退事件分发入口
public void onBackPressed()

5、构造器(参数为最终回调)
public OnBackPressedDispatcher(@Nullable Runnable fallbackOnBackPressed) {
    mFallbackOnBackPressed = fallbackOnBackPressed;
}

3. OnBackPressedDispatcher 源码分析

OnBackPressedDispatcher 源码不多,我直接带着问题入手,帮你梳理 OnBackPressedDispatcher 内部的实现原理:

3.1 Activity 如何将事件分发到 OnBackPressedDispatcher?

答:ComponentActivity 内部组合了分发器对象,返回键回调 onBackPressed() 会直接分发给 OnBackPressedDispatcher#onBackPressed()。另外,Activity 本身的回退逻辑则封装为 Runnable 交给分发器处理。

androidx.activity.ComponentActivity.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
private final OnBackPressedDispatcher mOnBackPressedDispatcher =
    new OnBackPressedDispatcher(new Runnable() {
        @Override
        public void run() {
            // Activity 本身的回退逻辑
            ComponentActivity.super.onBackPressed();
        }
});

@Override
@MainThread
public void onBackPressed() {
    mOnBackPressedDispatcher.onBackPressed();
}

@NonNull
@Override
public final OnBackPressedDispatcher getOnBackPressedDispatcher() {
    return mOnBackPressedDispatcher;
}
3.2 说一下 OnBackPressedDispatcher 的处理流程?

答:分发器整体采用责任链设计模式,向分发器添加的回调对象都会成为责任链上的一个节点。当用户触发返回键时,将按顺序遍历责任链,如果回调对象是启用状态(Enabled),则会消费该回退事件,并且停止遍历。如果最后事件没有被消费,则交回到 Activity#onBackPressed() 处理。

OnBackPressedDispatcher.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// final 回调:Activity#onBackPressed()
@Nullable
private final Runnable mFallbackOnBackPressed;

// 责任链
final ArrayDeque<OnBackPressedCallback> mOnBackPressedCallbacks = new ArrayDeque<>();

// 构造器
public OnBackPressedDispatcher() {
    this(null);
}

// 构造器
public OnBackPressedDispatcher(@Nullable Runnable fallbackOnBackPressed) {
    mFallbackOnBackPressed = fallbackOnBackPressed;
}

// 判断是否有启用的回调
@MainThread
public boolean hasEnabledCallbacks() {
    Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator();
    while (iterator.hasNext()) {
        if (iterator.next().isEnabled()) {
            return true;
        }
    }
    return false;
}

入口方法:责任链上的每个回调方法仅在前面的回调处于未启用状态(unEnabled)才能调用。
如果如果都没有启用,最后会回调给 mFallbackOnBackPressed
@MainThread
public void onBackPressed() {
    Iterator<OnBackPressedCallback> iterator = mOnBackPressedCallbacks.descendingIterator();
    while (iterator.hasNext()) {
        OnBackPressedCallback callback = iterator.next();
        if (callback.isEnabled()) {
            callback.handleOnBackPressed();
            // 消费
            return;
        }
    }
    if (mFallbackOnBackPressed != null) {
        mFallbackOnBackPressed.run();
    }
}
3.3 回调方法执行在主线程还是子线程?

答:主线程,分发器的入口方法 Activity#onBackPressed() 执行在主线程,因此回调方法也是执行在主线程。另外,添加回调的 addCallback() 方法也要求在主线程执行,分发器内部使用非并发安全容器 ArrayDeque 存储回调对象。

3.4 OnBackPressedCallback 可以同时添加到不同分发器吗?

答:可以。

3.5 加入返回栈的Fragment 事务,如何回退?

答:FragmentManager 也将事务回退交给 OnBackPressedDispatcher 处理。首先,在 Fragment attach 时,会创建一个回调对象加入分发器,回调处理时弹出返回栈栈顶事务。不过初始状态是未启用,只有当事务添加进返回栈后,才会修改回调对象为启用状态。源码体现如下:

FragmentManagerImpl.java

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 3.5.1 分发器与回调对象(初始状态是未启用)
private OnBackPressedDispatcher mOnBackPressedDispatcher;
private final OnBackPressedCallback mOnBackPressedCallback =
    new OnBackPressedCallback(false) {
        @Override
        public void handleOnBackPressed() {
            execPendingActions();
            if (mOnBackPressedCallback.isEnabled()) {
                popBackStackImmediate();
            } else {
                mOnBackPressedDispatcher.onBackPressed();
            }
        }
    };

// 3.5.2 添加回调对象 addCallback
public void attachController(@NonNull FragmentHostCallback host, @NonNull FragmentContainer container, @Nullable final Fragment parent) {
    if (mHost != null) throw new IllegalStateException("Already attached");
    ...
    // Set up the OnBackPressedCallback
    if (host instanceof OnBackPressedDispatcherOwner) {
        OnBackPressedDispatcherOwner dispatcherOwner = ((OnBackPressedDispatcherOwner) host);
        mOnBackPressedDispatcher = dispatcherOwner.getOnBackPressedDispatcher();
        LifecycleOwner owner = parent != null ? parent : dispatcherOwner;
        mOnBackPressedDispatcher.addCallback(owner, mOnBackPressedCallback);
    }
    ...
}

// 3.5.3 执行事务时,尝试修改回调对象状态
void scheduleCommit() {
     ...
    updateOnBackPressedCallbackEnabled();
}

private void updateOnBackPressedCallbackEnabled() {
    if (mPendingActions != null && !mPendingActions.isEmpty()) {
        mOnBackPressedCallback.setEnabled(true);
        return;
    }

    mOnBackPressedCallback.setEnabled(getBackStackEntryCount() > 0 && isPrimaryNavigation(mParent));
}

// 3.5.4 回收
public void dispatchDestroy() {
    mDestroyed = true;
    ...
    if (mOnBackPressedDispatcher != null) {
        // mOnBackPressedDispatcher can hold a reference to the host
        // so we need to null it out to prevent memory leaks
        mOnBackPressedCallback.remove();
        mOnBackPressedDispatcher = null;
    }
}

讨论完 OnBackPressedDispatcher 的使用方法 & 实现原理,下面我们直接通过一些应用场景来实践:


4. 再按一次返回键退出

再按一次返回键退出是一个很常见的功能,本质上是一种退出挽回。网上也流传着很多不全面的实现方式。其实,这个功能看似简单,却隐藏着一些优化细节,一起来看看~

4.1 需求分析

首先,我分析了几十款知名的 App,梳理总结出 4 类返回键交互:

分类

描述

举例

1、系统默认行为

返回键事件交给系统处理,应用不做干预

微信、支付宝等

2、再按一次退出

是否两秒内再次点击返回键,是则退出

爱奇艺、高德等

3、返回首页 Tab

按一次先返回首页 Tab,再按一次退出

Facebook、Instagram等

4、刷新信息流

按一次先刷新信息流,再按一次退出

小红书、今日头条等

4.2 如何退出 App?

交互逻辑主要依赖于产品形态和具体应用场景,对于我们技术同学还需要考虑不同的退出 App 的方式的区别。通过观测以上 App 的实际效果,我梳理出以下 4 种退出 App 的实现方式:

  • 1、系统默认行为: 将回退事件交给系统处理,而系统的默认行为是 finish() 当前 Activity,如果当前 Activity 位于栈底,则将 Activity 任务栈转入后台;
  • 2、调用 moveTaskToBack(): 手动将当前 Activity 所在任务栈转入后台,效果与系统的默认行为类似(该方法接收一个 nonRoot 参数:true:要求只有当前 Activity 处于栈底有效、false:不要求当前 Activity 处于栈底)。因为 Activity 实际上并没有销毁,所以用户下次返回应用时是热启动;
  • 3、调用 finish(): 结束当前 Activity,如果当前 Activity 处于栈底,则销毁 Activity 任务栈,如果当前 Activity 是进程最后一个组件,则进程也会结束。需要注意的是,进程结束后内存不会立即被回收,将来(一段时间内)用户重新启动应用时是温启动,启动速度比冷启动更快;
  • 4、调用 System.exit(0) 杀死应用: 杀死进程 JVM,将来用户重新启动为冷启动,需要花费更多时间。

那么,我们应该如何选择呢?一般情况下,“调用 moveTaskToBack()” 表现最佳,两个论点:

  • 1、两次点击返回键的目的是挽回用户,确认用户真的需要退出。那么,退出后的行为与无拦截的默认行为相同,这点 moveTaskToBack() 可以满足,而 finish() 和 System.exit(0) 的行为比默认行为更严重;
  • 2、moveTaskToBack() 退出应用并没有真正销毁应用,用户重新返回应用是热启动,恢复速度最快。

需要注意,一般不推荐使用 System.exit(0) 和 Process.killProcess(Process.myPid) 来退出应用。因为这些 API 的表现并不理想:

  • 1、当调用的 Activity 不位于栈顶时,杀死进程系统会立即重新启动 App(可能是系统认为 前台 App 是意外终止的,会自动重启);
  • 2、当 App 退出后,粘性服务会自动重启(Service#onStartCommand() 返回 START_STICKY 的 Service),粘性服务会一致运行除非手动停止。

分类

应用返回效果

举例

1、系统默认行为

热启动

微信、支付宝等

2、调用 moveTaskToBack()

热启动

QQ 音乐、小红书等

3、调用 finish()

温启动

待确认(备选爱奇艺、高德等)

4、调用 System.exit(0) 杀死应用

冷启动

待确认(备选爱奇艺、高德等)

4.3 具体代码实现

BackPressActivity.kt

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fun Context.startBackPressActivity() {
    startActivity(Intent(this, BackPressActivity::class.java))
}

class BackPressActivity : AppCompatActivity(R.layout.activity_backpress) {

    // ViewBinding + Kotlin 委托
    private val binding by viewBinding(ActivityBackpressBinding::bind)

    /**
     * 上次点击返回键的时间
     */
    private var lastBackPressTime = -1L

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // 添加回调对象
        onBackPressedDispatcher.addCallback(this, onBackPress)

        // 返回按钮
        binding.ivBack.setOnClickListener {
            onBackPressed()
        }
    }

    private val onBackPress = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            if (popBackStack()) {
                return
            }
            val currentTIme = System.currentTimeMillis()
            if (lastBackPressTime == -1L || currentTIme - lastBackPressTime >= 2000) {
                // 显示提示信息
                showBackPressTip()
                // 记录时间
                lastBackPressTime = currentTIme
            } else {
                //退出应用
                finish()
                // android.os.Process.killProcess(android.os.Process.myPid())
                // System.exit(0) // exitProcess(0)
                // moveTaskToBack(false)
            }
        }
    }

    private fun showBackPressTip() {
        Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
    }
}

这段代码的逻辑并不复杂,我们主要通过 OnBackPressedDispatcher#addCallback() 添加了一个回调对象,从而干预了返回键事件的逻辑:“首次点击返回键弹出提示,两秒内再次点击返回键退出应用”。

另外,需要解释下这句代码:private val binding by viewBinding(ActivityBackpressBinding::bind)。这里其实是使用了 ViewBinding + Kotlin 委托属性的视图绑定方案,相对于传统的 findViewById、ButterKnife、Kotlin Synthetics 等方案,这个方案从多个角度上表现更好。

4.4 优化:兼容 Fragment 返回栈

上一节基本能满足需求,但考虑一种情况:页面内有多个 Fragment 事务加入了返回栈,点击返回键时需要先依次清空返回栈,最后再走 “再按一次返回键退出” 逻辑。

此时,你会发现上一节的方法不会等返回栈清空就直接走退出逻辑了。原因也很好理解,因为 Activity 的回退对象的加入时机比 FragmentManagerImpl 中的回退对象加入时机更早,所以 Activity 的回退逻辑优先处理。解决方法就是在 Activtiy 回退逻辑中手动弹出 Fragment 事务返回栈。完整演示代码如下:

BackPressActivity.kt

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class BackPressActivity : AppCompatActivity(R.layout.activity_backpress) {

    private val binding by viewBinding(ActivityBackpressBinding::bind)

    /**
     * 上次点击返回键的时间
     */
    private var lastBackPressTime = -1L

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        addFragmentToStack()
        onBackPressedDispatcher.addCallback(this, onBackPress)

        binding.ivBack.setOnClickListener {
            onBackPressed()
        }
    }

    private fun addFragmentToStack() {
        // 提示:为了聚焦问题,这里不考虑 Activity 重建的场景
        for (index in 1..5) {
            supportFragmentManager.beginTransaction().let { it ->
                it.add(
                    R.id.container,
                    BackPressFragment().also { it.text = "fragment_$index" },
                    "fragment_$index"
                )
                it.addToBackStack(null)
                it.commit()
            }
        }
    }

    /**
     * @return true:没有Fragment弹出 false:有Fragment弹出
     */
    private fun popBackStack(): Boolean {
        // 当 Fragment 状态以保存,不弹出返回栈
        return supportFragmentManager.isStateSaved
                || supportFragmentManager.popBackStackImmediate()
    }

    private val onBackPress = object : OnBackPressedCallback(true) {
        override fun handleOnBackPressed() {
            if (popBackStack()) {
                return
            }
            val currentTIme = System.currentTimeMillis()
            if (lastBackPressTime == -1L || currentTIme - lastBackPressTime >= 2000) {
                // 显示提示信息
                showBackPressTip()
                // 记录时间
                lastBackPressTime = currentTIme
            } else {
                //退出应用
                finish()
                // android.os.Process.killProcess(android.os.Process.myPid())
                // System.exit(0) // exitProcess(0)
                // moveTaskToBack(false)
            }
        }
    }

    private fun showBackPressTip() {
        Toast.makeText(this, "再按一次退出", Toast.LENGTH_SHORT).show();
    }
}
4.5 在 Fragment 中使用

TestFragment.kt

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class TestFragment : Fragment() {
    private val dispatcher by lazy {requireActivity().onBackPressedDispatcher}
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        dispatcher.addCallback(this, object : OnBackPressedCallback(true) {
            override fun handleOnBackPressed() {
                Toast.makeText(context, "TestFragment - handleOnBackPressed", Toast.LENGTH_SHORT).show()
            }
        })
    }
}
4.6 其他 finish() 方法

另外,finish() 还有一些类似的 API,可以补充了解下:

  • finishAffinity():关闭当前 Activity 任务栈中,位于当前 Activity 底下的所有 Activity(例如 A 启动 B,B 启动 C,如果 B 调用 finishAffinity(),则会关闭 A 和 B,而 C 保留)。该 API 在 API 16 后引入,最好通过 ActivityCompat.finishAffinity() 调用。
  • finishAfterTransition():执行转场动画后 finish Activity,需要通过 ActivityOptions 定义转场动画。该 API 在 API 21 后引入,最好通过 ActivityCompat.finishAfterTransition() 调用。

5. 总结

关于 OnBackPressedDispatcher 的讨论就先到这里,给你留两个思考题:

  • 1、如果 Activity 上弹出一个 Dialog,此时点返回键是先关闭 Dialog,还是会分发给 OnBackPressedDispatcher?如果弹出的是 PopupWindow 呢?
  • 2、Activity 的 WebView 中弹出了一个浮层,怎么实现点击返回键先关闭浮层,再次点击才回退页面?

创作不易,你的「三连」是丑丑最大的动力,我们下次见!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-05-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 彭旭锐 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
使用OnBackPressedDispatcher处理回退事件
在单 Activity 多 Fragment 的场景下处理回退按键一直是一件比较恶心的事情。前段时间看 jetpack 在宣传中有提到利用 OnBackPressedDispatcher 处理回退,于是研究了一下。
烧麦程
2022/05/10
1.8K0
使用OnBackPressedDispatcher处理回退事件
Android onBackPressed不执行的解决方案
应用中经常会用到双击返回键在退出应用的效果,目的是为了防止用户误触返回键而导致退出应用。 通常的写法如下: 首先定义一个变量
longzeqiu
2019/08/14
3.5K0
Android 面试题:为什么 Activity 都重建了 ViewModel 还存在?—— Jetpack 系列(3)
ViewModel 是 Jetpack 组件中较常用的组件之一,也是实现 MVVM 模式或 MVI 模式的标准组件之一。在这篇文章里,我将与你讨论 ViewModel 实用和面试常见的知识点。如果能帮上忙请务必点赞加关注,这对我非常重要。
用户9995743
2022/09/26
1.4K0
Android 面试题:为什么 Activity 都重建了 ViewModel 还存在?—— Jetpack 系列(3)
Android项目开发填坑记-Fragment的onBackPressed
版权声明:本文为[他叫自己Mr.张]的原创文章,转载请注明出处,否则禁止转载。 https://micro.blog.csdn.net/article/details/51228934
他叫自己MR.张
2019/07/01
1.2K0
Fragment响应onBackPressed的三个方案
经常会碰到Fragment需要响应activity的onBackPressed事件,对比下三个不同方案
韦东锏
2021/09/29
2.2K0
抽丝剥茧 Jetpack | Lifecycle 到底解决了什么问题?
Lifecycle(生命周期) 在任何 GUI 编程中都是基石般的存在,Android 也不例外。
路遥TM
2022/03/29
3040
抽丝剥茧 Jetpack | Lifecycle 到底解决了什么问题?
“终于懂了“系列:Jetpack AAC完整解析(二)LiveData 完全掌握!
也就是说,LiveData使得 数据的更新 能以观察者模式 被observer感知,且此感知只发生在 LifecycleOwner的活跃生命周期状态。
胡飞洋
2020/12/15
4.1K0
Fragment回退栈及弹出方法
在上一期分享的文章末尾留了一个课后作业,有去思考如何解决吗?如果已经会了那么恭喜你,如果还不会也没关系,本期一起来学习。 一、回退栈 在前面两期的示例中,当我们完成一些操作后,如果想要回到操
分享达人秀
2018/02/05
4.7K1
Fragment回退栈及弹出方法
Lifecycle:生命周期感知型组件的基础 —— Jetpack 系列(1)
Lifecycle 的主要作用是简化实现生命周期感知型组件的复杂度。 在传统的方式中,需要手动从外部宿主(如 Activity、Fragment 或自定义宿主)中将生命周期事件分发到功能组件内部,这势必会造成宿主代码复杂度增加。例如:
用户9995743
2022/09/26
1.2K0
Lifecycle:生命周期感知型组件的基础 —— Jetpack 系列(1)
Jetpack路由组件学习:深入理解功能强大的Navigation架构之接管系统的返回操作
不管你之前用没用过Jetpack Navigation组件,但是或多或少你也可能听说过它。它是Jetpack库中的一个路由组件。此刻你的脑海中可能会浮现阿里ARouter框架。如果你熟悉ARouter但是对Navigation比较陌生,那么你先简单把它们联系在一起,有个直观的感受。
Android技术干货分享
2021/08/05
1.5K0
Jetpack路由组件学习:深入理解功能强大的Navigation架构之接管系统的返回操作
全网最全:Jetpack AAC(-)解析
原文链接:https://juejin.cn/post/6893870636733890574
程序员小顾
2021/12/07
1.4K0
Navigation深入浅出,到出神入化,再到实战改造(二)
NavDestination 节点的封装类对应nav_graph.xml文件中的 </navigation>, </fragment> </activity>, </dialog>目标节点(即Destination),同时有如四个子类:NavGraph,FragmentNavigator#Destination,ActivityNavigator#Destination,DialogFragmentNavigator#Destination
g小志
2022/03/29
2.2K0
Navigation深入浅出,到出神入化,再到实战改造(二)
Fragment 的过去、现在和将来
Fragment 是 Android 中历史十分悠久的一个组件,它在 API 11 被加入,时至今日已成为 Android 开发中最常用的组件之一。Fragment 有了哪些新特性、修复了哪些问题,都是开发者们十分关心的话题。下面我们就来重新说一说 Fragment —— 不仅仅是说现在的 Fragment,还会回顾它的发展,并让您一瞥它未来的样子。
Android 开发者
2020/06/24
9600
Fragment 的过去、现在和将来
Android Jetpack架构组件(四)之LiveData
LiveData是Jetpack架构组件Lifecycle 库的一部分,是一个可感知生命周期的可观察容器类 (Observable)。与常规的可观察类不同,LiveData 具有生命周期感知能力,这意味着它具有感知应用组件(如 Activity、Fragment 或 Service)的生命周期的能力,并且LiveData仅更新处于活跃生命周期状态的应用组件观察者。
xiangzhihong
2020/12/21
3.6K0
Android-Jetpack笔记-Lifecycles
Lifecycle即生命周期,一些业务场景如三方地图、播放器等,依赖于activity的生命周期,会有类似下面的用法:
Holiday
2020/08/10
3830
Android-Jetpack笔记-Lifecycles
Android实现点击两次返回退出APP
这两天在做一个项目碰到这么个问题,需要主界面点击两次直接退出整个APP而不是返回上一个界面,查找了网上的资料,整合和修改了一下写了这篇博客。
全栈程序员站长
2022/09/07
1.6K0
Android APP 快速 Pad 化实现
如何能在最快的时间内,实现一个最新版本 Android app 的 pad 化呢?从拿到一个大型手机 app 代码开始开发到第一个其全新 pad 版本的发布,我们用了不到3个月时间给出了一份满意的答案。 项目背景 采用最新版本手机 APP(之后称为 MyApp)代码,实现其 Pad 化,为平板和大屏手机用户提供更好的体验。为实现 MyApp 的 Pad 化工作,需要我们首先来了解一下 MyApp 项目经典页面的构成以及 Pad 化后的页面结构的变化。 1.MyApp 页面经典构成 现在主流手机 APP 主页
腾讯Bugly
2018/03/23
2.3K0
Android APP 快速 Pad 化实现
Android Jetpack - Lifecycles
Lifecycles 简介 Lifecycles 即生命周期,属于 Jetpack 架构组件之一的 Lifecycles 组件是可以为其它组件提供生命周期感知能力的一个组件,而具备了生命周期感知能力的组件就叫生命周期感知组件,注意加粗部分多读两遍,我看网上很多文章直接把 Lifecycles 组件叫生命周期感知组件那么什么是生命周期感知能力呢?我们知道四大基础组件有生命周期,能感知这些生命周期的组件就具备了生命周期感知能力,所以我认为以前我们使用的 MVP 模式中的 Presenter 如果它通过接口等方式
SkyRiN
2019/08/08
1.4K0
037android初级篇之Activity的几个重要函数
手机屏幕事件的处理方法onTouchEvent。该方法在View类中的定义,并且所有的View子类全部重写了该方法,应用程序可以通过该方法处理手机屏幕的触摸事件。该方法的签名如下所示。
上善若水.夏
2018/09/28
7760
笔记64 | 个人项目“易来”开发记录《二》处理Fragment中返回的问题
需求描述 问题: 一个WebView放在Fragment中,我们都知道webView有一个goBack()方法,可以通过该方法对网页进行后退处理,由于Fragment本身并没有监听onBackPressed的方法,又处于一个Activity中,Activity除又对后退进行了3秒确定退出处理,所有导致 Fragment中的WebView无法进行goBack(); 需求: 需要在Fragment中监听到返回键,当WebView可以后退网页的时候,进行后退网页,当没有可后退的网页时(首页状态),点击返回调Act
项勇
2018/06/19
5950
推荐阅读
相关推荐
使用OnBackPressedDispatcher处理回退事件
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验