Android Fragemnt重叠

1、闲聊

        今天测试突然给我提出了一个bug,我特么当时就懵逼了!What?什么鬼?写一个项目结构写出来了一个bug!然后我就去看,我越看越懵逼这样写没错啊!我实在看不出来,算了看一下生命周期吧!好吧,写一个测试dome,来打印一下生命周期:

onCreate: --------------------
onAttachFragment: --------------------Tab1Fragment{8626570 #0 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{ec4200f #1 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{5e0689c #2 id=0x7f0b006c tab3}
onSaveInstanceState: --------------------
onAttachFragment: --------------------Tab1Fragment{9d97288 #0 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{fab6421 #1 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{701e046 #2 id=0x7f0b006c tab3}
onCreate: --------------------
onAttachFragment: --------------------Tab1Fragment{2dd30cc #3 id=0x7f0b006c tab1}
onRestoreInstanceState: --------------------
onAttachFragment: --------------------Tab2Fragment{6d41f15 #4 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{907d22a #5 id=0x7f0b006c tab3}
onSaveInstanceState: --------------------
onAttachFragment: --------------------Tab1Fragment{6649791 #0 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{a28e6f6 #1 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{20d7af7 #2 id=0x7f0b006c tab3}
onAttachFragment: --------------------Tab1Fragment{d3ecd64 #3 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{5aa1bcd #4 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{b747c82 #5 id=0x7f0b006c tab3}
onCreate: --------------------
onAttachFragment: --------------------Tab1Fragment{420d4e8 #6 id=0x7f0b006c tab1}
onRestoreInstanceState: --------------------

        自大了,光看肯定看不出毛病的!有了生命周期我们就可以了解原理咯。可以看出来我每次进入后台时都会执行onSaveInstanceState方法,
我每次从后台回到页面时会依次执行:onAttachFragmentonCreateonSaveInstanceState这三个我需要的方法!到了这里我的想法是onSaveInstanceState这个方法在onAttachFragmentonCreate这两个方法的后面,我个人肯定不愿意在这里取出数据,因为我出现的这个bug是在活动销毁后才会出现的bug!每次肯定会走onCreate,所以我更愿意在onCreate方法中取出数据,但是这个东西的看你们的喜好,onAttachFragment这个方法中取出Fragment也是非常方便的,至少比onCreate方便,如:

@Override
public void onAttachFragment(Fragment fragment) {
    super.onAttachFragment(fragment);
    if (null != fragment && fragment instanceof Tab3Fragment) {
        tab3Fragment = (Tab3Fragment) fragment;
    }
    Log.d(TAG, "onAttachFragment: --------------------" + fragment);
}

在看一下在onCreate中取数据:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test_fragment);
    if (null != savedInstanceState) {
        FragmentManager fragmentManager = getFragmentManager();
        Fragment fragment = fragmentManager.findFragmentByTag(tabs[1]);
        if (null != fragment && fragment instanceof Tab1Fragment) {
            tab1Fragment = (Tab1Fragment) fragment;
        }
    }
}

        可以看出来了吧,onCreate方法中要多一个步奏来获取fragment,好了就聊到这儿!我们开始说具体怎样解决这个问题。

2、解决问题

        解决问题的方法肯定不止一种,这里我只说一种:我这里在使用FragmentTransaction(Fragment管理器)的时候,为每一个需要添加显示的Fragment打上一个 #tag 标记,再退出后台情况下,活动被销毁后,通过FragmentTransaction去取出对应 tag 存储的 Fragment,当然我这儿还存了一个索引值:index(退出后台时,显示的第几个fragment)!那就上代码了:


退出时保存 index:
@Override
protected void onSaveInstanceState(Bundle outState) {
    super.onSaveInstanceState(outState);
    outState.putInt(tabs[0], index);
    Log.d(TAG, "onSaveInstanceState: --------------------");
}

从新进入页面时,取出状态及fragment:
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_test_fragment);
    Log.d(TAG, "onCreate: --------------------");
    if (null != savedInstanceState) {
        index = savedInstanceState.getInt(tabs[0], 1);
        FragmentManager fragmentManager = getFragmentManager();
        Fragment fragment = fragmentManager.findFragmentByTag(tabs[1]);
        if (null != fragment && fragment instanceof Tab1Fragment) {
            tab1Fragment = (Tab1Fragment) fragment;
        }
        fragment = fragmentManager.findFragmentByTag(tabs[2]);
        if (null != fragment && fragment instanceof Tab2Fragment) {
            tab2Fragment = (Tab2Fragment) fragment;
        }
        fragment = fragmentManager.findFragmentByTag(tabs[3]);
        if (null != fragment && fragment instanceof Tab3Fragment) {
            tab3Fragment = (Tab3Fragment) fragment;
        }
    }
    showTab(index);
    init();
}

我们现在再来看一看生命周期:
onCreate: --------------------
onAttachFragment: --------------------Tab1Fragment{c577bb3 #0 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{61d116e #1 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{ec4200f #2 id=0x7f0b006c tab3}
onSaveInstanceState: --------------------
onAttachFragment: --------------------Tab1Fragment{facae2b #0 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{9d97288 #1 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{fab6421 #2 id=0x7f0b006c tab3}
onCreate: --------------------
onRestoreInstanceState: --------------------
onSaveInstanceState: --------------------
onAttachFragment: --------------------Tab1Fragment{6d41f15 #0 id=0x7f0b006c tab1}
onAttachFragment: --------------------Tab2Fragment{907d22a #1 id=0x7f0b006c tab2}
onAttachFragment: --------------------Tab3Fragment{d9781b #2 id=0x7f0b006c tab3}
onCreate: --------------------
onRestoreInstanceState: --------------------

        现在这个东西看着就非常清晰了吧!再也没有多次创建fragment了,那么这问题就算圆满解决了!

3、源码

public class TestFragmentActivity extends AppCompatActivity {
    private static final String TAG = "TestFragmentActivity";
    private Tab1Fragment tab1Fragment;
    private Tab2Fragment tab2Fragment;
    private Tab3Fragment tab3Fragment;
    private int index = 1;
    private String[] tabs = {"index", "tab1", "tab2", "tab3"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test_fragment);
        Log.d(TAG, "onCreate: --------------------");
        if (null != savedInstanceState) {
            index = savedInstanceState.getInt(tabs[0], 1);
            FragmentManager fragmentManager = getFragmentManager();
            Fragment fragment = fragmentManager.findFragmentByTag(tabs[1]);
            if (null != fragment && fragment instanceof Tab1Fragment) {
                tab1Fragment = (Tab1Fragment) fragment;
            }
            fragment = fragmentManager.findFragmentByTag(tabs[2]);
            if (null != fragment && fragment instanceof Tab2Fragment) {
                tab2Fragment = (Tab2Fragment) fragment;
            }
            fragment = fragmentManager.findFragmentByTag(tabs[3]);
            if (null != fragment && fragment instanceof Tab3Fragment) {
                tab3Fragment = (Tab3Fragment) fragment;
            }
        }
        showTab(index);
        init();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putInt(tabs[0], index);
        Log.d(TAG, "onSaveInstanceState: --------------------");
    }

    @Override
    public void onAttachFragment(Fragment fragment) {
        super.onAttachFragment(fragment);
        Log.d(TAG, "onAttachFragment: --------------------" + fragment);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        Log.d(TAG, "onRestoreInstanceState: --------------------");
    }

    private void init() {
        findViewById(R.id.tv_tab1).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showTab(1);
            }
        });
        findViewById(R.id.tv_tab2).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showTab(2);
            }
        });
        findViewById(R.id.tv_tab3).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                showTab(3);
            }
        });
    }

    private void showTab(int index) {
        this.index = index;
        // 开启一个Fragment事务
        FragmentTransaction transaction = getFragmentManager().beginTransaction();
        hideFragment(transaction);
        switch (index) {
            case 1:
                if (null == tab1Fragment) {
                    tab1Fragment = new Tab1Fragment();
                    transaction.add(R.id.fragment, tab1Fragment, tabs[index]);
                } else {
                    transaction.show(tab1Fragment);
                }
                break;
            case 2:
                if (null == tab2Fragment) {
                    tab2Fragment = new Tab2Fragment();
                    transaction.add(R.id.fragment, tab2Fragment, tabs[index]);
                } else {
                    transaction.show(tab2Fragment);
                }
                break;
            case 3:
                if (null == tab3Fragment) {
                    tab3Fragment = new Tab3Fragment();
                    transaction.add(R.id.fragment, tab3Fragment, tabs[index]);
                } else {
                    transaction.show(tab3Fragment);
                }
                break;
        }
        transaction.commit();
    }

    private void hideFragment(FragmentTransaction transaction) {
        if (null != tab1Fragment) {
            transaction.hide(tab1Fragment);
        }
        if (null != tab2Fragment) {
            transaction.hide(tab2Fragment);
        }
        if (null != tab3Fragment) {
            transaction.hide(tab3Fragment);
        }
    }
}

        至此问题已解决!有问题即时反馈,谢谢!

Android TextView控件发生重叠时,通常是因为布局层级不当、尺寸计算错误或者设置了不合适的位置参数导致的。以下是几个可能导致TextView重叠的情况以及解决方法: 1. **Layout嵌套**:检查TextView是否位于其他控件内,比如LinearLayout、RelativeLayout或其他自定义布局里。如果两个TextView都在同一层并且有相同的大小和位置,它们可能会重叠。调整子视图的`layout_margin`、`padding`或`android:layout_weight`属性来防止重叠。 2. **LayoutParams**:确保TextView的LayoutParams设置正确。例如,使用`android:layout_height="wrap_content"`可以自动适应内容高度,避免因为文字内容变化而引起的高度冲突。 3. **MeasureSpec**:在FlexboxLayout等支持动态测量的布局中,如果测量策略不当也可能导致重叠。检查MeasureSpec参数,尤其是宽度方向的测量。 4. **Gravity**:检查TextView的`android:gravity`属性,确保它不会影响到相邻元素,特别是垂直方向上。 5. **响应式设计**:在不同屏幕密度或大小下,如果未适配好,大字体的小屏设备可能会出现重叠。使用dp单位而不是sp,并考虑使用`wrap_content`或`match_parent`结合权重(weight)。 6. **绝对定位**:若TextView使用了`android:layout_alignParentBottom`或`android:layout_below`等绝对定位,注意其目标视图的相对位置。 要修复重叠,你可以逐个排查以上因素并做相应的调整。如果需要更具体的帮助,提供具体的代码片段将有助于确定问题所在。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值