更新片段以响应Android Navigation Drawer交互

Adr*_*nzi 7 android android-fragments navigation-drawer

我正在处理的Android应用程序只有一个MainActivity,应用程序的每个屏幕都实现为Fragment.每个片段在MainActivity中实例化为私有类变量:

public class MainActivity extends Activity implements MainStateListener {

   private FragmentManager fm = getFragmentManager();
   private BrowseFragment browseFragment = BrowseFragment.newInstance();

...
Run Code Online (Sandbox Code Playgroud)

有一个"片段帧"可以加载每个屏幕片段.在应用程序中切换屏幕时,会调用此代码来加载片段:

FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.frag_frame, incoming);
ft.addToBackStack(null);
ft.commit();
fm.executePendingTransactions();
Run Code Online (Sandbox Code Playgroud)

每个屏幕片段都有一个监听器,使片段能够调用MainActivity中的各种方法:

public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mainStateListener = (MainStateListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement MainStateListener");
    }
}
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是从MainActivity中退出的导航抽屉更新片段的一个方面.导航抽屉必须更新片段,并使用此代码执行此操作:

        navigationDrawer.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
                browseFragment.doSomethingOnBrowserFragment();
            }
        });
Run Code Online (Sandbox Code Playgroud)

在您更改方向之前,情况正常.然后当前屏幕片段加载正常(browseFragment).但是当你单击导航抽屉导致doSomethingOnBrowserFragment()方法执行时,由于mainStateListener对象本身(在browseFragment中附加)为null,我得到一个空指针异常.根据我对Fragment生命周期的了解,这个变量不应该为null,因为onAttach()方法首先执行任何操作并设置mainStateListener变量.此外,如果我在该browserFragment上有一个使用mainStateListener对象的按钮(在方向更改后),单击该按钮永远不会出现此空指针问题.

堆栈跟踪:

08-04 16:23:28.937  14770-14770/co.openplanit.totago E/AndroidRuntime? FATAL EXCEPTION: main
    Process: co.openplanit.totago, PID: 14770
    java.lang.NullPointerException
            at co.openplanit.totago.MapFragment.enableOfflineMode(MapFragment.java:489)
            at co.openplanit.totago.MainActivity.setMapMode(MainActivity.java:663)
            at co.openplanit.totago.MainActivity.itineraryMapDrawerSelectItem(MainActivity.java:610)
            at co.openplanit.totago.MainActivity.access$200(MainActivity.java:52)
            at co.openplanit.totago.MainActivity$5.onItemClick(MainActivity.java:420)
            at android.widget.AdapterView.performItemClick(AdapterView.java:299)
            at android.widget.AbsListView.performItemClick(AbsListView.java:1158)
            at android.widget.AbsListView$PerformClick.run(AbsListView.java:2957)
            at android.widget.AbsListView$3.run(AbsListView.java:3850)
            at android.os.Handler.handleCallback(Handler.java:733)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:136)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:606)
            at dalvik.system.NativeStart.main(Native Method)
Run Code Online (Sandbox Code Playgroud)

在我看来,问题可能是使用导航抽屉实际上是与browseFragment生命周期交互并导致它分离或什么.

任何关于如何解决这个问题的建议都将非常感激.

jt-*_*son 1

我认为可能发生的情况是,您的活动的 browserFragment 可能与片段管理器显示的 BrowseFragment 不同(如果您单击该片段中的按钮,它似乎工作正常,正如您所说)。

在旋转时,活动将为您的 browserFragment 变量创建一个新的 BrowseFragment 实例(未附加到活动) -每次创建活动时都会运行private BrowseFragment browserFragment = BrowseFragment.newInstance(),但片段管理器将重用现有的您的变量未指向的 BrowseFragment 实例。重用的 BrowseFragment 将被附加并运行该代码来更新 mainStateListener,未使用的新 browserFragment 将不会附加到活动,除非您运行添加它的fragmentTransaction - 因此其中的 mainStateListener 将为 null(未初始化)。

您最好使用片段标签并根据片段管理器中的标签获取片段,而不是创建片段并将其存储在变量中,然后在旋转后尝试访问该变量。

IE

private static final String BROWSE_TAG = "browseFrag";

ft.replace(R.id.frag_frame, browseFragment, BROWSE_TAG);

navigationDrawer.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
        Fragment browseFragment = fm.findFragmentByTag(BROWSE_TAG);
        if (browseFragment != null) {
            browseFragment.doSomethingOnBrowserFragment();
        }
   }
});
Run Code Online (Sandbox Code Playgroud)