Android Java:在 onCreateView() 中返回空视图的片段

Posted

技术标签:

【中文标题】Android Java:在 onCreateView() 中返回空视图的片段【英文标题】:Android Java: Fragments returning null view in onCreateView() 【发布时间】:2013-12-03 21:02:33 【问题描述】:

我目前正在开发一个在 android java 中使用 MVC 设计模式和片段的程序。我已经找到了我的一个片段并让它工作,但是当我复制其他片段以遵循相同的代码结构(具有专门的功能)时,我在 onCreateView 方法中得到一个空指针异常。

我现在在我的垃圾笔记本电脑上,它似乎无法处理 android 仿真,所以我明天可以发布确切的错误代码。不过我有我的源代码,而且我已经用头撞墙了足够长的时间,知道它在哪里坏了。

编辑:我看到了我的问题。我正在通过从每个片段的 View.java 类中调用一个方法来测试我的代码。此方法更新视图中的表。由于视图尚未显示在屏幕上,因此尚未为它们调用 onCreateView()。由于尚未调用 onCreateView(),因此尝试访问视图会导致空指针。有什么好方法可以为我的 MainActivity 中的每个片段调用 onCreateView() 以便我可以及早初始化视图?

(部分工作片段):

    public class DispatchView extends Fragment 
private final List<DispatchModel> models = new ArrayList<DispatchModel>();

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    View view = inflater.inflate(R.layout.dispatchfragment, container,
            false);
    return view;

所有片段,除了 DispatchView,在返回视图时中断。它们返回 null 而不是实际对象。 破碎碎片之一的一部分:

    public class ConnectionsLogView extends Fragment 
private final List<ConnectionsLogModel> models = new ArrayList<ConnectionsLogModel>();

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    View view = inflater.inflate(R.layout.connectionslogfragment,
            container, false);
    return view;

片段被声明和初始化。在我尝试将新的数据条目(类)推送到它们之后,它们(除了 Dispatch MVC 之外的任何一个)中断。 在我的 MainActivity.java 中:

    public class MainActivity extends Activity 
// Declare Tab Variables and fragment objects
private mDMI             app;
ActionBar.Tab            Tab1, Tab2, Tab3, Tab4;
Fragment                 dispatchTab          = new DispatchView();
Fragment                 dispatchLogTab       = new DispatchLogView();
Fragment                 activeConnectionsTab = new ConnectionsView();
Fragment                 connectionLogTab     = new ConnectionsLogView();
DispatchModel            dispatchModel;
DispatchController       dispatchController;
DispatchLogModel         dispatchLogModel;
DispatchLogController    dispatchLogController;
ConnectionsModel         connectionsModel;
ConnectionsController    connectionsController;
ConnectionsLogModel      connectionsLogModel;
ConnectionsLogController connectionsLogController;

public MainActivity() 
    super();


@Override
public void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    app = (mDMI) getApplication();
    dispatchModel = app.getDispatchModel();
    dispatchController = new DispatchController(dispatchTab, dispatchModel);
    dispatchLogModel = app.getDispatchLogModel();
    dispatchLogController = new DispatchLogController(dispatchLogTab,
            dispatchLogModel);
    connectionsModel = app.getConnectionsModel();
    connectionsController = new ConnectionsController(activeConnectionsTab,
            connectionsModel);
    connectionsLogModel = app.getConnLogModel();
    connectionsLogController = new ConnectionsLogController(
            connectionLogTab, connectionsLogModel);
    setContentView(R.layout.activity_main);

已识别 xml 字符串 在我的 R.java 中:

    public static final class layout 
    public static final int activity_login=0x7f030000;
    public static final int activity_main=0x7f030001;
    public static final int connectionsfragment=0x7f030002;
    public static final int connectionslogfragment=0x7f030003;
    public static final int dispatchfragment=0x7f030004;
    public static final int dispatchlogfragment=0x7f030005;

【问题讨论】:

【参考方案1】:

不要那样创建你的片段。而是使用标准的 Android 模式:

public class FeedFragment extends Fragment 
   public FeedFragment() 
     super();
   
   public static FeedFragment newInstance(Context context) 
     if (context != null) 
       sContext = context.getApplicationContext();
      else 
       sContext = YourApp.getInstance().getApplicationContext();
     
     return new FeedFragment();
   
 

那么不要在你的活动中创建它们……

改为在您的 Activity 中使用标准 Android 模式:

    @Override
    protected void onCreate(final Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        FragmentManager fm = getSupportFragmentManager();
        Fragment fragment = fm.findFragmentById(R.id.content_frame);
        if ( fragment == null ) 
            fragment = FeedFragment.newInstance(this);
            fm.beginTransaction()
                    .add(R.id.content_frame, dispatchTab, "DISPATCH_FRAG")
                    .commit();
        
    

要稍后检索片段,您可以这样做……

final FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentByTag("DISPATCH_FRAG);
if (fragment != null) 
   // cast and use your fragment

如果以后需要,您甚至可以存储参考。

关于你的 null 问题,如果没有确切的崩溃/日志,真的很难说。

但是您的代码有点混乱,这可能是原因。片段生命周期很棘手。

【讨论】:

我很好奇,第一个模式与new FragmentSubclass() 相比,除了保留一个可以在整个班级使用的sContext 实例之外,还有什么优势?无论如何它总是返回new FragmentSubclass()... 这被认为是最佳实践,因为 Android 将使用默认构造函数初始化片段。现在没关系,但是如果你添加一个参数你会在不知不觉中破坏它 @JohnnyZ 所说的 ;) 这也是 Android 开发人员认可的标准做法(或者应该如此),它将使未来的您和未来的代码维护者更容易。除非您打算在带有某种适配器的 ViewPager 中使用您的片段,否则构造函数可以是私有的(应该),在这种情况下,您需要一个默认的公共构造函数。使用这种上下文传递的优点是您不会(也不会)将您的片段绑定到包含的活动,而且您永远不会有不正确的上下文硬引用(== 内存泄漏)。【参考方案2】:

我自己修好了。如果视图返回 null,我的更新函数不会尝试将行和条目添加到(不存在的)视图中的(不存在的)表中。我在每个视图中都这样实现:

public void update(final BlockingDeque<Dispatch> dispatches) 
    View view = getView();
    // do not update if the view is null (device is not displaying that
    // fragment)
    if (view != null) 
        TableLayout t = (TableLayout) view.findViewById(R.id.dispatchTable);
        t.removeAllViews();

【讨论】:

以上是关于Android Java:在 onCreateView() 中返回空视图的片段的主要内容,如果未能解决你的问题,请参考以下文章

项目遇到的问题

AsyncTask 在 ViewPager 的每个页面上运行

什么时候为 recyclerView 使用 hasStableIds true?

Fragment和Activity生命周期以及横竖屏切换对生命周期的影响

用于 onActivityCreated 中通用图像加载器的片段中进度条的 NullPointerException

如何在Android中启动JAVA程序