《一个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

相关文章

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

Android实现任意版本设置默认的锁屏壁纸和桌面壁纸(两张壁纸可不一致)

客户有些需求需要设置默认壁纸和锁屏壁纸  在默认情况下 这两个壁纸是相同的  如果需要默认的锁屏壁纸和桌面壁纸不一样 需要额外修改 Android13实现 替换默认桌面壁纸: 将图片文件替换frameworks/base/core/res/res/drawable-nodpi/default_wallpaper.*  (注意不能是bmp格式) 替换默认锁屏壁纸: 将图片资源放入vendo

Android平台播放RTSP流的几种方案探究(VLC VS ExoPlayer VS SmartPlayer)

技术背景 好多开发者需要遴选Android平台RTSP直播播放器的时候,不知道如何选的好,本文针对常用的方案,做个大概的说明: 1. 使用VLC for Android VLC Media Player(VLC多媒体播放器),最初命名为VideoLAN客户端,是VideoLAN品牌产品,是VideoLAN计划的多媒体播放器。它支持众多音频与视频解码器及文件格式,并支持DVD影音光盘,VCD影

poj 2431 poj 3253 优先队列的运用

poj 2431: 题意: 一条路起点为0, 终点为l。 卡车初始时在0点,并且有p升油,假设油箱无限大。 给n个加油站,每个加油站距离终点 l 距离为 x[i],可以加的油量为fuel[i]。 问最少加几次油可以到达终点,若不能到达,输出-1。 解析: 《挑战程序设计竞赛》: “在卡车开往终点的途中,只有在加油站才可以加油。但是,如果认为“在到达加油站i时,就获得了一

android-opencv-jni

//------------------start opencv--------------------@Override public void onResume(){ super.onResume(); //通过OpenCV引擎服务加载并初始化OpenCV类库,所谓OpenCV引擎服务即是 //OpenCV_2.4.3.2_Manager_2.4_*.apk程序包,存

从状态管理到性能优化:全面解析 Android Compose

文章目录 引言一、Android Compose基本概念1.1 什么是Android Compose?1.2 Compose的优势1.3 如何在项目中使用Compose 二、Compose中的状态管理2.1 状态管理的重要性2.2 Compose中的状态和数据流2.3 使用State和MutableState处理状态2.4 通过ViewModel进行状态管理 三、Compose中的列表和滚动

Android 10.0 mtk平板camera2横屏预览旋转90度横屏拍照图片旋转90度功能实现

1.前言 在10.0的系统rom定制化开发中,在进行一些平板等默认横屏的设备开发的过程中,需要在进入camera2的 时候,默认预览图像也是需要横屏显示的,在上一篇已经实现了横屏预览功能,然后发现横屏预览后,拍照保存的图片 依然是竖屏的,所以说同样需要将图片也保存为横屏图标了,所以就需要看下mtk的camera2的相关横屏保存图片功能, 如何实现实现横屏保存图片功能 如图所示: 2.mtk

android应用中res目录说明

Android应用的res目录是一个特殊的项目,该项目里存放了Android应用所用的全部资源,包括图片、字符串、颜色、尺寸、样式等,类似于web开发中的public目录,js、css、image、style。。。。 Android按照约定,将不同的资源放在不同的文件夹中,这样可以方便的让AAPT(即Android Asset Packaging Tool , 在SDK的build-tools目

Android fill_parent、match_parent、wrap_content三者的作用及区别

这三个属性都是用来适应视图的水平或者垂直大小,以视图的内容或尺寸为基础的布局,比精确的指定视图的范围更加方便。 1、fill_parent 设置一个视图的布局为fill_parent将强制性的使视图扩展至它父元素的大小 2、match_parent 和fill_parent一样,从字面上的意思match_parent更贴切一些,于是从2.2开始,两个属性都可以使用,但2.3版本以后的建议使

Android Environment 获取的路径问题

1. 以获取 /System 路径为例 /*** Return root of the "system" partition holding the core Android OS.* Always present and mounted read-only.*/public static @NonNull File getRootDirectory() {return DIR_ANDR