Fragment的一些坑

创建实例

一般情况下我们创建Fragment可能都是像下面的做法:

OneFragment fragment = new OneFragment();

如果在创建时需要传递参数的话就是

OneFragment fragment = new OneFragment(xxx);

这样的话一般情况下是没问题的,但是一些特殊情况会出现问题。
比如当屏幕旋转内存吃紧时,Activity会被回收重新创建Activity,依附在Activity上的Fragment也会跟着重新创建,Fragment会调用默认的无参构造函数,这会导致无法执行有参构造函数进行初始化工作。

解决方法:
newInstance的方法创建Fragment实例,然后在创建时把参数放在Bundle里边,setArguments()传进去,然后在onCreate()方法里边取出来。
这样即使出现上述的特殊情况,也能在onCreate()方法里把 参数取出来进行初始化工作。

public static OneFragment newInstance(int args){
     OneFragment oneFragment = new OneFragment();

    Bundle bundle = new Bundle();
    bundle.putInt("someArgs", args);

    oneFragment.setArguments(bundle);
    return oneFragment;
}

@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    Bundle bundle = getArguments();
    int args = bundle.getInt("someArgs");
}

通信方式

通常存在3种通信场景:

  1. Activity 操作内嵌的Fragment
  2. Fragment 操作宿主Activity
  3. Fragment 操作同级的 Fragment

一般的情况下:

  1. 我们在Activity中创建的 Fragment,所以自然会持有Fragment对象实例,或者通过findFragmentById()findFragmentByTag()方法都能获取到Fragment对象实例,所以可以操作到Fragment
  2. Fragment通过getActivity()方法可以获取到宿主Activity对象,进而可以操作宿主Activity
  3. 既然通过getActivity()方法就可以获取到Activity,那自然也就可以操作其他的Fragment对象

问题:
虽然上述方法可以解决所有的通信问题,但会造成代码逻辑紊乱的情况,不符合高内聚低耦合的编程思想。
Fragment做好自己的事情即可,所有涉及到Fragment之间的控制显示等操作,应该由Activity统一管理。

解决方法:
通过对外开放接口的形式,将Fragment对Activity的一些操作,由Activity来管理。相当于Fragment操作Activity,但是Fragment只提供一个接口,让Activity自个自觉的把Fragment需要操作的方法放进去。

实现方式如下:

public class OneFragment extends Fragment implements View.OnClickListener{

    public interface IOneFragmentClickListener{
        void onOneFragmentClick();
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View contentView = inflater.inflate(R.layout.fragment_one, null);
        contentView.findViewById(R.id.edt_one).setOnClickListener(this);
        return contentView;
    }

    @Override
    public void onClick(View v) {
        if (getActivity() instanceof IOneFragmentClickListener){
             ((IOneFragmentClickListener) getActivity()).onOneFragmentClick();
        }
    }

}

只要在宿主 Activity 实现 Fragment 定义的对外接口 IOneFragmentClickListener,便可以实现 Fragment 调用 Activity 的功能。

也可以这样:

public class OneFragment extends Fragment implements View.OnClickListener{
    
    private IOneFragmentClickListener clickListener;

    public interface IOneFragmentClickListener{
        void onOneFragmentClick();
    }

    public void setClickListener(IOneFragmentClickListener clickListener) {
        this.clickListener = clickListener;
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View contentView = inflater.inflate(R.layout.fragment_one, null);
        contentView.findViewById(R.id.edt_one).setOnClickListener(this);
        return contentView;
    }

    @Override
    public void onClick(View v) {
        clickListener.onOneFragmentClick();
    }

}

原理是一样的,只是相比第一种方式,需要在宿主 Activity 中额外添加一步监听设置:

oneFragment.setClickListener(this);

Fragment重叠问题

原因:

  • 情况1:重复创建实例导致重叠
    一般情况下我们是在ActivityonCreate()FragmentonCreateView()里加载Fragment,如果遇到页面重启的情况(比如屏幕旋转、内存回收、更换字体等情况被强杀重启),由于系统的保存机制,会自动帮我们保存Fragment的状态,然后重启以后帮我们恢复,但是在我们的onCreate()或onCreateView()方法内又重新创建add了一次,所以导致重叠

  • 情况2:没有保存mHidden状态导致重叠
    mHidden参数用于保存Fragment显示状态(mHidden=ture代表隐藏,mHidden=false代表显示),比如你有2个Fragment,一个为ture状态,一个是false状态,此时遇到界面重启的情况,系统会自动帮你恢复Fragment,这时由于mHidden状态没有保存,所有的Fragment默认mHidden都是false(即显示状态),所以会导致重叠
    </br>

情况 2
在v4-24.0.0+ 开始,官方修复了上述 没有保存mHidden的问题,所以如果你在使用24.0.0+的v4包,即可不考虑情况 2 的问题。
但是! 如果你用的不是V4包的Fragment,而是android.app.Fragment包的Fragment,那么问题依然是存在的!

解决办法:

  • 情况1:
    直接在Fragment的onCreate()内加个判断:
//为空说明是首次加载,不是页面重启的情况
if (savedInstanceState == null){
    //进行初始化工作
}

</br>

  • 情况2:
    手动维护一个变量mSupportHidden,用于保存每个Fragment自己的显示状态,结合情况1、2的解决办法代码:
public class BaseFragment extends Fragment {
    private static final String STATE_SAVE_IS_HIDDEN = "STATE_SAVE_IS_HIDDEN";

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
    ...
    if (savedInstanceState != null) {
        boolean isSupportHidden = savedInstanceState.getBoolean(STATE_SAVE_IS_HIDDEN);

        FragmentTransaction ft = getFragmentManager().beginTransaction();
        if (isSupportHidden) {
            ft.hide(this);
        } else {
            ft.show(this);
        }
        ft.commit();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        ...
        outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
    }
}

remove()方法不能出栈

还需实践踩坑...

getActivity()空指针

还需实践踩坑...

多个Fragment同时出栈的深坑BUG

还需实践踩坑...

深坑 Fragment转场动画(仅分析v4包下的Fragment)

还需实践踩坑...

参考
Fragment全解析系列(一):那些年踩过的坑

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容