《一个Android工程的从零开始》-7、base(六) BaseFragment的运用

2024-05-16 14:08

本文主要是介绍《一个Android工程的从零开始》-7、base(六) BaseFragment的运用,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

先扯两句

说实话,昨天的部分BaseFragment就应该已经结束掉了,不过没有具体的应用掩饰,所以今天就再写一篇BaseFragment的基本应用,不过命名为BaseFragment的运用,但其实都是在说的Fragment的一些基本知识点以及BaseActivity中添加的封装方法,用于添加Fragment。
还是先上我的git库,然后开始正文。
MyBaseApplication (https://github.com/BanShouWeng/MyBaseApplication)

正文

前面已经说过了,这部分主要是对Activity如何调用Fragment进行的封装,不过由于还没有具体实现某一个APP的功能,所以这里只是集成一下最基本的Fragment调用,还没有涉及到ViewPager的部分,虽然也不难,奈何我太懒啊。

Fragment启动方式

在需要创建 Fragment的位置,一般我们都先用FrameLayout占位,随后再通过对应的FragmentTransaction的方法将Fragment放置到FrameLayout中,而使用的方法分为以下两类。

1、add、show、hide

使用方法

看到这个标题不要误会,这并不是说有在1中有三种启动方法,这三个方法放在一起完全是因为他们是个组合,每一个的功能也大家完全可以从字面理解,add(添加)、show(展示)、hide(隐藏)。
首先,我们需要先添加要显示的Fragment,然后需要其显示的时候,调用show方法显示我们要呈现的Fragment(调用show方法之前显示的是你最后add的Fragment),而hide则是将对应的Fragment隐藏起来。
当然,可能会有人问,既然调用show方法则会显示对应的Fragment,那么其他的自然也处于hide的状态,为什么还要去调用这个方法,岂不是多此一举吗?
不过Google怎么可能犯这么傻的错误,既然是设置了这个方法,那么肯定是有用处的,至于什么用呢,那就是当我们使用Fragment的时候,偶尔会有需要我们监听当前Fragment是否显示的操作,而当我们使用了show的时候,是不调用onCreate或者是onResume方法的,所以这个时候我们很难使用Fragment生命周期相关的方法去判断其显隐性,但是当执行show或hide方法时候,却会执行Fragment中的onHiddenChanged方法,其参数是一个boolean值——boolean hidden,所以我们通过调用这个方法,判断hidden的true/false就可以完成显隐性对应的操作,下面贴出来我这个方法的代码:

    @Overridepublic void onHiddenChanged(boolean hidden) {super.onHiddenChanged(hidden);if (hidden) {showToast("隐藏了");} else {showToast("显示了");}}

大家再看看效果:

这里写图片描述

咳咳,关于布局,大家就忍一下啊,等后面完成具体功能的时候,我好好设计一下,这里就偷个懒。不过大家应该可以看到,随着Fragment的隐藏/显示,方法中的Toast确实也随着执行了。
当然,我们在工程中使用的时候,show方法就不用想了,肯定只能有一个,谁也不会设计成同一个Fragment的地方,同一个时间显示两个Fragment吧,当然,如果谁遇到这么一个设计,我只能默默为你节哀(同一个Activity中是可以存在多个Fragment的,这个不再考虑范围内,我的意思是一个FrameLayout占位的地方不会同时显示两个Fragment)。
但是add与hide就不一定一次处理几个了,add很简单能理解,例如首页的布局中,就会运用到Fragment,毕竟都是常用界面,我们在初始化的时候自然都要添加完,调用的时候显示就可以,所以很显然,我们需要同时操作多个(谁如果一定要用的时候再添加也不是不可以,只是作为一个懒人,那么做还得各种判断状态,多麻烦)
而hide,一般情况下,肯定是将show的hide掉就可以了,但是为什么我也将其算到不一定处理几个了呢,只存在一种情况,那就是前面说的add的时候,我们为了能够在onHiddenChanged方法中监听各个Fragment的显隐性,所以那些没有显示的就需要在创建之后hide掉。
所以这部分在BaseActivity中集成的方法如下:

    /*** 添加Fragment** @param containerViewId 对应布局的id* @param fragments       所要添加的Fragment,可以添加多个*/public void addFragment(int containerViewId, Fragment... fragments) {if (fragments != null) {FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();for (int i = 0; i < fragments.length; i++) {transaction.add(containerViewId, fragments[i]);}transaction.commitAllowingStateLoss();}}/*** 显示Fragment** @param fragment 所要显示的Fragment*/public void showFragment(Fragment fragment) {if (fragment != null) {getSupportFragmentManager().beginTransaction().show(fragment).commitAllowingStateLoss();}}/*** 隐藏Fragment** @param fragments 所要隐藏的Fragment,可以添加多个*/public void hideFragment(Fragment... fragments) {if (fragments != null) {FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();for (int i = 0; i < fragments.length; i++) {transaction.hide(fragments[i]);}transaction.commitAllowingStateLoss();}}

其中Fragment… fragments是可变长参数,可以传入大于等于0个同类型参数,这里的意思就是我们可以不传,或者传入任意个Fragment,且生成的是一个字符串。
不过,作为一个懒人嘛,既然前面已经说到了,hide只有在add刚刚添加完之后才可能会多次调用hide,那么我们就直接将这部分hide集成到刚刚add地方岂不是更省事,也就是除了最后一个添加的之外,其他的都设置成hide,修改后的add/hide方法如下:

    /*** 添加Fragment** @param containerViewId 对应布局的id* @param fragments       所要添加的Fragment,可以添加多个*/public void addFragment(int containerViewId, Fragment... fragments) {if (fragments != null) {FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();for (int i = 0; i < fragments.length; i++) {transaction.add(containerViewId, fragments[i]);if (i != fragments.length - 1){transaction.hide(fragments[i]);}}transaction.commitAllowingStateLoss();}}/*** 隐藏Fragment** @param fragment 所要隐藏的Fragment,可以添加多个*/public void hideFragment(Fragment fragment) {if (fragment != null) {getSupportFragmentManager().beginTransaction().hide(fragment).commitAllowingStateLoss();}}

这样在使用的时候直接调用即可,也可以避免“…”的形式如果忘记传参也不会报错的情况,降低出错的可能性。

存在问题

正因为我们是将所需要的一次性都加载完成,所以开发出的APP,在后台运行的过程中,一旦某个Fragment被回收了,那么再次运行的时候,都会出现空指针异常。目前采取的方式一般都是后台运行一段时间后,再次打开则重启APP,例如:高德地图;而没有处理的一般都会卡死,用户只能强制关闭APP,再重新打开,例如:赶集网(或许过段时间再看的时候,也做了处理,但是至少现在还是有卡死的问题的,虽然不确定一定是Fragment引起的,但大家可以参考一下出问题的效果)

2、replace

这个就没有之前那么复杂,还需要三个方法才能完成对应的功能,而是只有一个方法就可以完成,那就是replace。当然,其作用也很好理解,就是替换。而其效果看上去与上面的方法相同,但是实际上却是不同的。
使用add、show、hide的时候,我们是在FrameLayout中生成了多层的Fragment,然后将我们要显示的拿到最上面,其他的都在下面无论隐藏或者不隐藏,都是存在的。
而replace则不同它相当于执行了remove之后,再去执行add方法,也就是先将上一个Fragment删除掉之后,再重新添加一个Fragment方法,所以无论调用多少次replace,都相当于我们只是在FrameLayout中放了一层Fragment,这种情况下,再出现上述的丢失Fragment导致空指针的情况,虽然还是无法避免,但概率绝对会减少许多。
因为每次都是创建的新的Fragment,所以我们就不需要监听onHiddenChanged方法了,我们只需要监听对应的生命周期就可以完成创建或销毁的操作。
代码如下:

    /*** 替换Fragment** @param containerViewId 对应布局的id* @param fragment        用于替代原有Fragment的心Fragment*/public void replaceFragment(int containerViewId, Fragment fragment) {if (fragment != null) {getSupportFragmentManager().beginTransaction().replace(containerViewId, fragment).commitAllowingStateLoss();}}
存在问题

正因为它是先remove了上一个Fragment,再重新add新的Fragment,所以每次调用的时候都需要重新加载整个Fragment,因此相对而言会更耗费资源,如果不常使用的Fragment,没有问题,如果是ViewPager或者首页这种会经常访问的,建议不要使用这个方法。

至于为什么这里我使用的是commitAllowingStateLoss而不是commit,大家可以参考一下丿北纬91度灬的源码分析commitAllowingStateLoss() 和commit()的区别

BaseFragment的调用

好了,在前面的内容都搞定了以后,我们终于到了本篇博客的起因,也是本篇博客最没有什么技术含量的部分了。
我们就将上面Gif图对应的代码贴出来就可以了,大家看一下:

package com.banshouweng.mybaseapplication.ui.fragment;import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.View;import com.banshouweng.mybaseapplication.R;
import com.banshouweng.mybaseapplication.base.BaseFragment;
import com.banshouweng.mybaseapplication.ui.activity.TestActivity;/*** 《一个Android工程的从零开始》** @author 半寿翁* @博客:* @CSDN http://blog.csdn.net/u010513377/article/details/74455960* @简书 http://www.jianshu.com/p/1410051701fe*/
public class MineFragment extends BaseFragment {@Overridepublic void onViewCreated(View view, @Nullable Bundle savedInstanceState) {super.onViewCreated(view, savedInstanceState);setBaseContentView(R.layout.fragment_mine);//设置title文本setTitle("MineFragment");//设置返回拦截setBaseBack(new OnClickBackCallBack() {@Overridepublic void clickBack() {startActivity(TestActivity.class);}});//设置功能键,以及点击方法回调监听setBaseRightIcon1(R.mipmap.add, "更多", new OnClickRightIcon1CallBack() {@Overridepublic void clickRightIcon1() {showLoadDialog();}});setBaseRightIcon2(R.mipmap.more, "更多", new OnClickRightIcon2CallBack() {@Overridepublic void clickRightIcon2() {hideLoadDialog();}});}@Overridepublic void onHiddenChanged(boolean hidden) {super.onHiddenChanged(hidden);if (hidden) {showToast("隐藏了");} else {showToast("显示了");}}
}

很遗憾的是,这个里面有一个方法没有用,那就是hideLoadDialog(),主要原因还是在CustomProgressDialog中设置了setCanceledOnTouchOutside(false)(dialog弹出后点击物理返回键Dialog消失,但是点击屏幕不会消失)这个属性。不过其他效果都还是可以实现的。也就是按钮的显示,其中返回键返回键拦截跳转的是TestActivity,而MainActivity中的拦截跳转的是NetWorkActivity。为了与上面MainActivity的Title做区分,右侧的图片位置也做了交换,下面我们来看一下效果。

这里写图片描述

附录

《一个Android工程的从零开始》- 目录

这篇关于《一个Android工程的从零开始》-7、base(六) BaseFragment的运用的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


原文地址:
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.chinasem.cn/article/995126

相关文章

Android kotlin中 Channel 和 Flow 的区别和选择使用场景分析

《Androidkotlin中Channel和Flow的区别和选择使用场景分析》Kotlin协程中,Flow是冷数据流,按需触发,适合响应式数据处理;Channel是热数据流,持续发送,支持... 目录一、基本概念界定FlowChannel二、核心特性对比数据生产触发条件生产与消费的关系背压处理机制生命周期

Android ClassLoader加载机制详解

《AndroidClassLoader加载机制详解》Android的ClassLoader负责加载.dex文件,基于双亲委派模型,支持热修复和插件化,需注意类冲突、内存泄漏和兼容性问题,本文给大家介... 目录一、ClassLoader概述1.1 类加载的基本概念1.2 android与Java Class

Android DataBinding 与 MVVM使用详解

《AndroidDataBinding与MVVM使用详解》本文介绍AndroidDataBinding库,其通过绑定UI组件与数据源实现自动更新,支持双向绑定和逻辑运算,减少模板代码,结合MV... 目录一、DataBinding 核心概念二、配置与基础使用1. 启用 DataBinding 2. 基础布局

Android ViewBinding使用流程

《AndroidViewBinding使用流程》AndroidViewBinding是Jetpack组件,替代findViewById,提供类型安全、空安全和编译时检查,代码简洁且性能优化,相比Da... 目录一、核心概念二、ViewBinding优点三、使用流程1. 启用 ViewBinding (模块级

Swagger在java中的运用及常见问题解决

《Swagger在java中的运用及常见问题解决》Swagger插件是一款深受Java开发者喜爱的工具,它在前后端分离的开发模式下发挥着重要作用,:本文主要介绍Swagger在java中的运用及常... 目录前言1. Swagger 的主要功能1.1 交互式 API 文档1.2 客户端 SDK 生成1.3

Android学习总结之Java和kotlin区别超详细分析

《Android学习总结之Java和kotlin区别超详细分析》Java和Kotlin都是用于Android开发的编程语言,它们各自具有独特的特点和优势,:本文主要介绍Android学习总结之Ja... 目录一、空安全机制真题 1:Kotlin 如何解决 Java 的 NullPointerExceptio

详解如何使用Python从零开始构建文本统计模型

《详解如何使用Python从零开始构建文本统计模型》在自然语言处理领域,词汇表构建是文本预处理的关键环节,本文通过Python代码实践,演示如何从原始文本中提取多尺度特征,并通过动态调整机制构建更精确... 目录一、项目背景与核心思想二、核心代码解析1. 数据加载与预处理2. 多尺度字符统计3. 统计结果可

CSS引入方式和选择符的讲解和运用小结

《CSS引入方式和选择符的讲解和运用小结》CSS即层叠样式表,是一种用于描述网页文档(如HTML或XML)外观和格式的样式表语言,它主要用于将网页内容的呈现(外观)和结构(内容)分离,从而实现... 目录一、前言二、css 是什么三、CSS 引入方式1、行内样式2、内部样式表3、链入外部样式表四、CSS 选

MyBatisX逆向工程的实现示例

《MyBatisX逆向工程的实现示例》本文主要介绍了MyBatisX逆向工程的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学... 目录逆向工程准备好数据库、表安装MyBATisX插件项目连接数据库引入依赖pom.XML生成实体类、

Android NDK版本迭代与FFmpeg交叉编译完全指南

《AndroidNDK版本迭代与FFmpeg交叉编译完全指南》在Android开发中,使用NDK进行原生代码开发是一项常见需求,特别是当我们需要集成FFmpeg这样的多媒体处理库时,本文将深入分析A... 目录一、android NDK版本迭代分界线二、FFmpeg交叉编译关键注意事项三、完整编译脚本示例四