用Fragment的Hide()与Show()来代替Fragment的Replace()。

这篇博客探讨了在Android开发中如何使用Fragment的Hide和Show方法来替代Replace,以保留Fragment的状态,避免每次切换时重新加载数据。作者通过实例说明了Fragment的替换过程,指出Replace操作会导致数据丢失,并提出使用hide()和show()能更有效地管理Fragment的状态,特别是在处理如用户信息等需要持久化的数据时。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

用Fragment的Hide()与Show()来代替Fragment的Replace()吧!

本博客由博主原创,未经允许,不得转载

fragment简介

Fragment说它是一种轻量级的Activity一点也不为过,安卓3.0以后,它迅速崛起,简易的操作与良好的可维护性很快受到了广大安卓爱好者的喜爱,笔者对于Fragment也有过一定时间的研究,最近开发的一些app也是基于Fragment搭建的整体框架。

Fragment的替换

笔者在决定写博客之前,上网查了一些有关Fragment切换的一些资料,大体对于网上针对于这个技术点的博客来说,大多说的还不够清晰,恰巧最近一个做平板开发的朋友问到这个问题,我整理了一下,希望以下资料可以对安卓学习的朋友有所帮助。
我们都知道,安卓在替换Fragment的时候,实际上做了两件事情:

1.将原有的Fragment移除。

getFragmentManager().beginTranstation().remove(fragment);

2.添加新的Fragment。
getFragmentManager().beginTransaction().add(containerViewId, fragment);

这两步操作已经可以完美的实现了Fragment的来回切换(注意不要忘了commit()).但是这里就出了一个问题:我如何保存Fragment的当前状态!

笔者先前写过一个小Demo,大致的内容是将QQ服务器返还的用户头像与姓名设置到Fragment的相应文本上。那么这里问题来了,每当我切换到其他的Fragment时,再切换回来,QQ的用户头像和姓名不见了!
那么此时肯定有人会说,Fragment依赖于Activity存在,我们直接保存当前界面的现场不就可以了。
不!这样不行!因为方法根本不会被调用!
原因很简单,因为onSaveInstanceState的调用遵循一个重要原则,即当系统“未经你许可”时销毁了你的activity,则 onSaveInstanceState会被系统调用,这是系统的责任,因为它必须要提供一个机会让你保存你的数据(当然你不保存那就随便你了)。
至于onRestoreInstanceState方法,需要注意的是,onSaveInstanceState方法和 onRestoreInstanceState方法“不一定”是成对的被调用的,onRestoreInstanceState被调用的前提 是,activity A“确实”被系统销毁了,而如果仅仅是停留在有这种可能性的情况下,则该方法不会被调用,例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行。

试想一下,实际开发中,我们获取到的第三方用户信息是要提交到服务器上的,难道我们每加载一次展现用户信息的Fragment就要请求一次服务器?

当然不可能这样,因为这样不仅会浪费用户大量的流量,还会出现加载延迟的一系列情况,甚至是用户的登录信息还未展现出来,用户的私人信息已经在其他界面展示了。

因此,我们迫切希望能有一个更好的方法,完美的解决这一类问题。

Fragment 的hide()和Show(),在进行Fragment的切换时,并不是Fragment的remove()和add(),而只是单纯的将Fragment显示和隐藏。

以下是笔者写的一个最简单易懂代码

这个是主界面的代码,我创建了一个RadioGruop,里面有三个RadioButton,点击不同的单选按钮跳转到不同的Fragment:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/ll"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_above="@+id/rg" 
        android:orientation="vertical">
    </LinearLayout>

    <RadioGroup
        android:id="@+id/rg"
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:background="#000000"
        android:gravity="center"
        android:orientation="horizontal" >

        <RadioButton
            android:id="@+id/rb1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1" />

        <RadioButton
            android:id="@+id/rb2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1" />

        <RadioButton
            android:id="@+id/rb3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1" />
    </RadioGroup>

</RelativeLayout>

这是fragment01的代码,为了在最简单的情况下更直观的展示效果,我只是给每一Fragment设置不同的背景颜色。
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FFFF00"
    android:orientation="vertical" >
</LinearLayout>

这是fragment02的代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF0000"
    android:orientation="vertical" >
</LinearLayout>

这是fragment03的代码
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#FF00FF"
    android:orientation="vertical" >
</LinearLayout>

fragment01.xml对应的实体类,里面不进行任何操作,只是最简单的加载xml布局文件,fragment02与fragment03也是一样
public class Fragment01 extends Fragment{   
    @Override
    public View onCreateView(LayoutInflater inflater,  ViewGroup container,Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment01, container,false);
        return view;
    }
}

现在我们看主类中的操作,我在这里会把思路全部理一遍,最后把完整代码贴上去,作为一个安卓开发人员,笔者认为思路才是解决问题最重要的东西。

①:声明需要的对象,这一步不要多说了。
private Fragment01 fragment01 = new Fragment01();;  
private Fragment02 fragment02;  
private Fragment03 fragment03;  
private FragmentManager manager;    
private RadioGroup rg;
我在这里将fargment01创建出来的原因是为了让界面启动时加载某一个fragment,这点读者可以自行设定。当然如果不想在这里设置,在radioButtononCheckListener()中设定也可以,如果在onCheckListener()设定这点读者不是很明白,接下来的代码会慢慢解释。

②:找到控件,初始化对象,这点也不必多言。
    manager = getSupportFragmentManager();
    rg = (RadioGroup) findViewById(R.id.rg);
    rg.check(R.id.rb1);
    rg.setOnCheckedChangeListener(this);
    manager.beginTransaction().add(R.id.ll,fragment01).commit();
    这里默认选中rb1,因此读者就可以在rb1的监听中设置加载fragment01 
③:接下来便是重点,Fragmenthide()show()的核心代码。
    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {
    //隐藏Fragment
        hideFragments();
        switch (checkedId) {
        case R.id.rb1:
            if (fragment01 != null) {               manager.beginTransaction().show(fragment01).commit();
                return;
            }创建
            //我们只在第一次创建时将Fragmen添加进activity,接下来这步操作边不会执行,只是执行fragment的hide和show
            manager.beginTransaction().add(R.id.ll, fragment01).commit();
            break;
        case R.id.rb2:
            if (fragment02 != null) {
                manager.beginTransaction().show(fragment02).commit();
                return;
            }
            fragment02 = new Fragment02();
            manager.beginTransaction().add(R.id.ll, fragment02).commit();
            break;
        case R.id.rb3:
            if (fragment03 != null) {
                manager.beginTransaction().show(fragment03).commit();
                return;
            }
            fragment03 = new Fragment03();
            manager.beginTransaction().add(R.id.ll, fragment03).commit();
            break;
        }
    }

隐藏fragment的代码如下,在选中rb1时创建所有的fragment,只创建一个对象,以后Fragment全是复用,减小内存开销,然后将所有的Fragment隐藏,然后再onCreate方法内将默认展示的Fragment显示出来
    private void hideFragments() {
        if (fragment01 != null) {
            manager.beginTransaction().hide(fragment01).commit();
        }
        if (fragment02 != null) {
            manager.beginTransaction().hide(fragment02).commit();
        }
        if (fragment03 != null) {
            manager.beginTransaction().hide(fragment03).commit();
        }

    }
这就是Fragment的hide()与show()的逻辑代码,笔者将其尽力简化,以达到最简单易懂且效果显著。

本博客由博主原创,未经允许,不得转载

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值