片段的onCreateView()会导致我的应用崩溃

时间:2013-03-15 16:13:38

标签: android fragment

我遇到了一个奇怪的问题。我在一个拥有主机FragmentActivity的应用程序中使用Fragments,我在其中实现了构建Fragments的内部class FragmentPagerAdapater并将它们放入我的activity的标签中。

在应用程序中,我需要将一个Object从我的Activity传递给Fragments。我不确定这样做的正确方法是什么,所以我即兴创作,并在片段中找到了静态片段newInstance(Object obj)。此方法只调用默认的Fragment构造函数并设置实例变量以在Fragment中保存Object。

现在在Fragment的createView()方法中,我使用实例的Object信息来填充布局。这可以在应用程序启动时正常工作,但是当我将屏幕方向从纵向更改为横向(或相反)时,应用程序崩溃。日志指示createView()中实例对象上的NullPointerException。我觉得我在生命周期中遗漏了一些东西,但我找不到答案。有没有什么特别的做法,我的片段会保存他们的实例变量,无论如何?

这是一个代码示例,可帮助您了解问题所在:

public class MyFragment extends Fragment {

private Object obj;

public static MyFragment newInstance(Object obj) {
    MyFragment fragment = new MyFragment();
    fragment.setObject(obj);
    return fragment;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.layout_fragment, container, false);
    MyType res = ((Type) (obj)).getSomething(); // This line causes the crash because obj is null when I switch to another orientation

    // I Do something with res to fill rootView

    return rootView;
}

private void setObject(Object obj) {
    this.obj = obj;
}
}


// In the Activity I simply create the Fragment using
MyFragment fragment = MyFragment.newInstance(myObjectToPass);

感谢您的帮助!

2 个答案:

答案 0 :(得分:2)

当方向切换时(当Android决定重新创建Fragment时),现有的Fragment将被销毁,然后重新创建。

但是,当Android重新创建Fragment时,它不会调用您的自定义newInstance()方法。它使用空的无参数构造函数。

这意味着您的Fragment 不会对您想要的任何自定义Object具有非空引用,从而导致NPE被抛出。

您需要找到一种方法来传递Object。如果Object是简单数据Object,请考虑通过setArguments()方法传递其字段或将其序列化。

MyFragment fragment = new MyFragment();
Bundle data = new Bundle();
data.putString ("key_string", "your string here");
fragment.setArguments (data);

您还可以创建一个查询对象活动的interface。例如:

public class MyFragment extends Fragment {

  public interface ObjectProvider
  {
    public CustomObject getCustomObject();
  }

  private ObjectProvider provider;

  @Override
  public void onAttach (Activity activity)
  {
    super.onAttach(activity);
    try{
      provider = (ObjectProvider) activity;//get an instance of the ObjectProvider
    }
    catch (ClassCastException e)
    {
      e.printStackTrace();
      throw new RuntimeException ("This isn't an ObjectProvider.");
    }
  }

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    View rootView = inflater.inflate(R.layout.layout_fragment, container, false);

    provider.getCustomObject().getSomething(); 

    return rootView;
  }
}

然后你的Activity需要实现界面:

public class MainActivity implements MyFragment.ObjectProvider{

 @Override
 public CustomObject getCustomObject()
 {
   return new CustomObject();
 }
} 

答案 1 :(得分:1)

您也可以使用setRetainInstance(true),如下所示:

public static MyFragment newInstance(Object obj) {
    MyFragment fragment = new MyFragment();
    fragment.setObject(obj);
    fragment.setRetainInstance(true);
    return fragment;
}

这将使您的对象在方向更改中保持不变,只需确保该对象没有对活动上下文的引用,否则您将发生内存泄漏。