Fragment.onAttach()的mActivity未保留

时间:2015-05-26 17:02:19

标签: android android-fragments rx-java

我已经使用RxJava设置了一个Observable / Subscriber。 Observable在MainActivity中创建。订阅者是名为MyFragment的android.support.v4.app.Fragment。 Observable从RESTful服务获取数据,并将数据存储在设备上的SQLite数据库中。这有效。当其工作完成(需要4或5秒)以使MyFragment已处理onCreate()onCreateView()等时,订阅者MyFragment将通过其实现的onNext()方法通知(此然后从SQLite数据库中读取数据(这也有效)并且应该填充视图(这不起作用)。

问题是我的类成员mActivity在方法loadDataFromSQLite()中为空。我认为我正在学习的教训是,Fragment的任何内容都不能在Fragment类的方法之外完成(从onAttach()onDestroy()

既然如此,我该怎么做?

请参阅下面的代码段:

MyFragment.java

public class MyFragment extends Fragment implements Observer<String> { 

    private Activity mActivity;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        mActivity = activity;
    }

    ...

    @Override
    public void onNext(String string) {
        loadDataFromSQLite();

    }

    public void loadDataFromSQLite() {
        <get data from SQLite>
        // now want to populate view
        // mActivity is null
        mTableLayout = (TableLayout) mActivity.findViewById(R.id.fragment_table_layout);
    }
}    

fragment_table_layout.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/table_wrapper"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">
    <ScrollView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:scrollbars="none"
        tools:ignore="UselessParent">

        <TableLayout
            android:id="@+id/fragment_table_layout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content">
            <!--  fill in data in MyFragment.java -->
        </TableLayout>

    </ScrollView>
</RelativeLayout>

编辑:

我应该添加我还尝试调用getActivity()代替mActivity,但它返回null

2 个答案:

答案 0 :(得分:1)

显然这一行是一个问题:

mTableLayout = (TableLayout) mActivity.findViewById(R.id.fragment_table_layout);

这意味着您正在该片段中投射一个不属于该片段的视图。片段的所有视图管道(包括发现TableLayout)应该在Fragment.onCreateView中完成。稍后您可以在片段中的其他位置使用它们的引用,如下所示:

TableLayout mTableLayout;

@Override
public View onCreateView(LayoutInflater inflater, ...) {
   View view = inflater.inflate(R.layout.fragment_layout, container, false);
   mTableLayout = (TableLayout) view.findViewById(R.id.fragment_table_layout);
   ...
   return view; 
}

另一件事是你不能仅仅因为你希望它需要更长的时间来配置两个进程中的一个来更新另一个进程。这是不可靠的,这是通过调用REST API来更新您不确定已创建的片段的方法。您可以通过调用FragmentManager.executePendingTransactions()来强制创建片段,但是当REST响应到达时片段已经消失,您仍需要做好准备。

同样重要的是要注意保持对活动的引用是个坏主意。您应该始终在片段中使用getActivity。如果在任何时候它返回null,则表示尚未创建或已经销毁了片段锚定到的活动。

答案 1 :(得分:1)

您遇到问题,因为您认为onNext之后会调用onAttach,但正如您已经注意到的那样,情况并非如此。我会说你有两个选择:

  1. 订阅onAttach中的观察点,而不是之前,这样您就可以确保onNext之后会被调用;

  2. onNext中检查活动是否为空,如果是,则保存数据以供日后使用。然后在onAttach检查您是否有数据,如果有,则将其可视化。这样你就可以通过在片段初始化的同时加载数据来节省一些时间,但你必须有一个方法,可以在if (getActivity != null && mData != null) { ... }之内调用两次。

  3. 所以,第一个更优雅,但第二个可能更有效。

    PS。显然,所有findViewById都应该在onCreateView()

    中完成