Android横屏开发的老梗---Fragment切换混乱重叠问题

今天工作开发之时遇到的一个老梗,老恶心了,好在下班前解决了。今晚按耐不住拔掉老梗舒畅的心和大家分享一下,希望大家以后在横屏开发碰到类似的问题可以快速解决。

Android横屏开发的老梗---Fragment切换混乱重叠问题。首先和大家回顾一下Activity的生命周期,如下图:


Activity的创建会先调用OnCreat(),启动OnStar(),然后显示在界面上OnResume();未完全遮住Activity时调用OnPause(),如被DialogActivity遮住MainActivity;被完全遮住时调用OnStop(),停止Activity,当重新启动时则调用OnRestart();Activity销毁时就调用OnDestroy()。为什么和大家扯这么久Activity的生命周期呢,我们的问题不是“Android横屏开发的老梗---Fragment切换混乱重叠问题”吗?好了,在切入正题之前再和大家说一个问题,当我们要把Activity从竖屏切换到横屏时,Activity会被OnDestroy()销毁掉,再重新创建。这就是我今晚写这篇文章的主要原因了。

Android默认显示是竖屏显示的,所以我们先要设置它为横屏显示,有两种方法:

第一种修改Activity的onResume方法
@Override
protected void onResume() {
 /**
  * 设置为横屏
  */
 if(getRequestedOrientation()!=ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE){
  setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
 }
 super.onResume();
}

第二种在配置文件中对Activity节点添加android:screenOrientation属性(landscape是横向,portrait是纵向)
android:launchMode="singleTask" android:screenOrientation="landscape">

这里我是通过点击不同RadioButton来切换不同的fragment,然后采用hide()和show()来进行隐藏和显示对应的fragment布局,代码我就不贴了,涉及到保密协议问题,网上有很多例子自己去度娘吧,哈哈。这里说一下为什么用hide()和show()的原因,这是属于程序本身优化的问题,hide()和show()这两个方法被调用时只是隐藏和显示,并不会把我们已经实例出来的fragment对象给销毁掉。这就不同于replace()替换方法,虽然两者看起来效果一样没什么区别,但是replace()会销毁掉切换之前的fragment对象,显示切换之后的fragment对象。这样我们之前的fragment布局里的数据也会被清理掉,当我们又切换回来时,相当于重新实例出一个新的fragment对象,数据重新加载,这无形中就增加了虚拟机的运行负荷,程序运行的速度。好了,按照前面的思路我给大家展示一下大致布局显示的图片,在模拟器上运行的效果,如下图:

    

看起来很正常并没有什么错乱问题出现,那是因为很多模拟器上并没有锁屏这一功能,我用的是海马玩模拟器就没有这一功能,当下到真机上测试时当锁屏后就会出现重叠问题了,如下图:

  

以上这些图片是自己画出来的并未是自己工作时写出来的UI,怕被抓到泄密把柄啊,只能用类似场景图来补充了。为什么锁屏后会造成这种fragment布局重叠的问题?主要原因是锁屏后,Activity会默认由横屏切换回竖屏,当我们又重新解锁回到Activity时,Activity从竖屏又切换到了横屏(前文我们设置了强制横屏),所以导致了Activity被杀死重新创建,但是fragment的对象却没有被杀死,Activity重新创建后fragment相当于再一次实例化了一个对象,所以锁屏之前所显示的fragment布局就像个鬼魂似得一直占据右边的布局,成了右边布局的background一样,一切换其他fragment就会重叠在一起。那我们要怎么解决这个问题,复用Activity的被杀死之前的fragment对象就可以解决这样的重叠问题。怎么复用,因为Activity中OnSaveInstanceState(Bundle outState)中把fragment的对象都存进了Bundle的对象里了,这样就很简单了,我们从OnCreat(Bundle savedInstanceState)方法中就可以找回我们的之前的fragment对象了。当然这之前我们还要做一件事就是每次实例化fragment的对象前先给他设置个tag,通过FragmentTransaction对象的add(int containerViewId, Fragment fragment, String tag)方法里面的第三个参数就可以给fragment设置tag了,然后在OnCreat(Bundle savedInstanceState)方法中,FragmentTransaction对象通过findFragmentByTag(String tag)方法找到fragment对象,再进行复用就OK了,代码如下

private FragmentManager mFragmentManager;
private FragmentTransaction mTransaction;
private Fragment[] fragments = {new WorkFragment(),new BuyFragment(),new PercentageFragment(),new SettingFragment()};
@Override
protected void onCreate(Bundle savedInstanceState){
			.
			.
			.
    mFragmentManager = getSupportFragmentManager();
    mTransaction = mFragmentManager.beginTransaction();
    if (savedInstanceState!=null){
        for (int i = 0;i<fragments.length;i++){
            fragments[i] = mFragmentManager.findFragmentByTag(""+i);
        }
    }else {
        for (int i = 0;i<fragments.length;i++){
            mTransaction.add(R.id.fragment_layout,fragments[i],""+i);
            mTransaction.hide(fragments[i]);
        }
    }
    mTransaction.show(fragments[0]);
    mTransaction.commit();
}

还有很多同学喜欢用一个BaseActivity继承Activity的,这里可以用接口回调,这里就不贴了,你们研究哈。

补充一点,好像有另一个方法可以解决锁屏后阻止Activity从横屏切换回竖屏,在androidmanifest.xml中的activit元素加入这个属性 android:configChanges="orientation|keyboardHidden" 就能避免,具体没试过,有兴趣的同学可以试试。

总结:写了这么多,自己来总结一下,Android横屏开发的老梗---Fragment切换混乱重叠问题,会发生这种问题主要是:第一、对Activity生命周期的理解不够深刻。第二、fragment的复用。写这篇东西也浪费了不少时间,但感觉还是值得,和大家分享自己碰到的一些问题,感觉自己的路还很长啊,加油吧

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值