方向改变后无法与 Fragment 正确通信

Posted

技术标签:

【中文标题】方向改变后无法与 Fragment 正确通信【英文标题】:Cannot communicate with Fragment correctly after orientation change 【发布时间】:2015-01-18 22:25:13 【问题描述】:

在使用 FragmentPagerAdapter 时,我无法确定片段之间的正确通信方式。

在某些情况下,我有一个使用 FragmentPagerAdapter 托管两个片段的 Activity。片段 A 有一个按钮,按下它会更改片段 B 中的文本。

一切都按预期工作,除了在方向更改后按下按钮时,我在片段 B 中更改的 EditText 上出现空指针异常。经过几天的调试后,看起来当我在片段 B 中调用该方法时将文本更改为可能是 Fragment 的旧实例。

代码如下:

我的 Activity 中的内部类 FragmentPagerAdapter:

public class MyPagerAdapter extends FragmentPagerAdapter 

    public MyPagerAdapter (FragmentManager fm) 
        super(fm);
    

    @Override
    public Fragment getItem(int i) 
        switch (i) 
            case 0:
                return fragmentA;
            case 1:
                return fragmentB;
        
        return null;
    

    @Override
    public int getCount() 
        return tabs.length;
    

    @Override
    public CharSequence getPageTitle(int position) 
        return tabs[position];
    

片段在活动的 onCreate 方法中被实例化,如下所示:

FragmentA fragmentA; //Declared outside of onCreate
FragmentB fragmentB; //Declared outside of onCreate

fragmentA = FragmentA.newInstance();
fragmentB = FragmentB.newInstance();

在我按下按钮的Fragment中,我设置了如下界面:

@Override
public void onAttach(Activity activity) 
    super.onAttach(activity);
    try 
        testTextInterface = (TestTextInterface) activity;
     catch (ClassCastException e) 
        throw new ClassCastException(activity.toString()
                + " must implement testTextInterface");
    

然后,当我按下按钮时,我有一个 OnClickListener 会触发以下代码:

testTextInterface.onTextChanged("Some test text");

依次调用Activity中的以下方法:

@Override
public void onTextChanged(String testText) 
    fragmentB.updateText(testText); 


最后是 FragmentB 中的那个方法:

private void updateText(String incomingText)
    myEditText.setText(incomingText);

就是这样,在我旋转设备导致重新创建 Activity 之前,它运行良好。然后当我按下按钮时,myEditText 视图在 updateText 方法中的 FragmentB 中为空。

2 天来我一直在试图找出原因,所以我想知道是否有人能发现我哪里出错了或指出我在哪里可能会注意到导致问题的正确方向?

【问题讨论】:

如何将片段附加到活动中?在 oncreate?如果是这样,当您旋转设备时,将使用不为空的包调用 onCreate。因此,您应该检查savedInstanceState 是否为空,然后才附加片段。此外,我将摆脱 onAttach 回调和您在片段中保留的对活动的引用。相反,当您需要在活动中调用侦听器时,只需在片段本身中执行getActivity() 还有一件事,在适配器中,您是否也将实例保留在片段中,而不是创建新片段?如果是这样,请检查this answer。 我自己不会手动附加片段,我相信 FragmentPagerAdapter 会在 getItem 方法中自动完成? 【参考方案1】:

问题在于,当您旋转时,android 会为您创建片段的新实例,但您不会获得对这些新实例的引用。在您的活动中不保留对片段的引用会更安全,而是在需要时使用 findFragmentByTag。

@Override
public void onTextChanged(String testText) 
    Fragment fragmentB = getFragmentManager().findFragmentByTag("FragmentB");
    fragmentB.updateText(testText);

当然,请确保在 XML 或代码中设置片段的标记。

【讨论】:

问题是我认为我不能将它与 FragmentPAgerAdapter 一起使用,因为 Fragment 没有 ID? 如果您对每种类型的片段只有一个实例,那么您需要做的就是在调用 newInstance 之后立即设置一个 ID 或标签。这样您就知道 FragmentA 或 FragmentB 的每个实例都将具有您分配给它的标签或 ID。 Android 将在轮换后重新创建 Fragment 后维护 Fragment 标签和 ID。【参考方案2】:

我同意 Bruce 的观点,但如果您确实需要在 Activity 中保留对片段的引用,您可以执行以下操作:

在你的活动中,实现一个方法,比如说“setFragmentInstance”。

在您的片段中,覆盖 onActivityCreated 方法,您可以在该方法中将活动转换为您的活动(如果片段始终留在该活动中)并调用该 setFragmentInstance 方法,或者您也可以在片段中添加一个接口,实现它的activity并调用onActivityCreated中接口的方法来设置fragment实例。

我之前也问过一个类似的问题,但很快我就明白了,见DialogFragment members becomes null after screen rotation

【讨论】:

以上是关于方向改变后无法与 Fragment 正确通信的主要内容,如果未能解决你的问题,请参考以下文章

Fragment与Activity生命周期关系

Android Fragment 深度解析

Fragment和DialogFragment生命周期关系

fragment与activity及两个fragment之间的跳转实现

Android Fragment

方向改变后如何获取屏幕高度?