0

我有主要活动和三个片段(一、二、三)。所有这些片段都扩展了 BaseFragment:

public abstract class BaseFragment extends Fragment {
private Toolbar mToolbar;
private ActionBar mActionBar;

@Override
@CallSuper
public void onAttach(Activity context) {
    super.onAttach(context);

    mToolbar = (Toolbar) getActivity().findViewById(R.id.toolbar);
    mActionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
    //mActionBar.setTitle(setMyTitle());
    //Log.i("BaseFragment", "onAttach = "+getBackStackCount());
    resetToolbarNavigation(getBackStackCount()!=0);
}

//protected abstract String setMyTitle();

@Override
@CallSuper
public void onDetach() {
    super.onDetach();
    Log.i("BaseFragment", "onDetach = " + (getBackStackCount() - 1));
    resetToolbarNavigation((getBackStackCount() - 1 )!= 0);
}

private int getBackStackCount() {
    int b = getActivity().getSupportFragmentManager().getBackStackEntryCount();
    Log.i("BaseFragment", "getBackStackCount = "+b);

    return b;
}

private void resetToolbarNavigation(boolean backNavigationEnabled) {
    mActionBar.setDisplayHomeAsUpEnabled(backNavigationEnabled);
    Log.i("BaseFragment", "resetToolbarNavigation");
    if (backNavigationEnabled) {
        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.i("resetToolbarNavigation", "setNavigationOnClickListener");
                getActivity().onBackPressed();
            }
        });
    }
    else {
        ((StartPageActivity) getActivity()).initToolbar();
        ((StartPageActivity) getActivity()).syncState();
    }
}

}

但是当我点击后退箭头时,我得到了 Exeption

09-22 19:28:13.233    5643-5643/com.test.mylist E/AndroidRuntime﹕ FATAL EXCEPTION: main
java.lang.NullPointerException
        at com.test.exemple.BaseFragment$1.onClick(BaseFragment.java:56)
        at android.view.View.performClick(View.java:2485)
        at android.view.View$PerformClick.run(View.java:9080)
        at android.os.Handler.handleCallback(Handler.java:587)
        at android.os.Handler.dispatchMessage(Handler.java:92)
        at android.os.Looper.loop(Looper.java:130)
        at android.app.ActivityThread.main(ActivityThread.java:3683)
        at java.lang.reflect.Method.invokeNative(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:507)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
        at dalvik.system.NativeStart.main(Native Method)

onBackPressed 在主要活动中

    @Override
public void onBackPressed() {
        getSupportFragmentManager().popBackStack();
        Log.d("StartPageActivity", "onBackPressed " + getSupportFragmentManager().getBackStackEntryCount());

}

你能帮助我吗?错误在哪里?我究竟做错了什么?

4

2 回答 2

1

根据您的评论,这是我认为正在发生的事情。

  1. 您打开片段 1 并resetToolbarNavigation(boolean)onAttach
  2. 您导航到片段 2 并resetToolbarNavigation(boolean)onAttach
  3. 您导航到片段 3 并resetToolbarNavigation(boolean)onAttach
  4. 您单击导航按钮,片段 3 会正确处理它弹出后台堆栈并将您导航回片段 2
    • resetToolbarNavigation(boolean)没有从片段 2 调用,因为片段/活动没有onAttach被破坏并且片段从未分离。
  5. 您按下导航按钮,它再次由未启动的片段 3 处理,因此getActivity()返回null

在此处输入图像描述

您应该尝试在显示片段时设置导航监听器。如果您正确执行片段事务,您应该能够在onResume().

于 2015-09-22T20:42:23.910 回答
1

不知道为什么你会得到那个确切的例外,但是你使用片段的方法在它的设计方式上并不是那么好,这可能会带来这类问题。所以在这里我给你一些建议,在使用片段实现应用程序时对我很有用:

  • 单独的职责:Activity 应该负责它的东西,而 Fragment 应该只负责 Fragment 的功能。为了实现这一点,您可以使用您需要 Activity 实现的方法使您的 Fragment 发布接口,然后在 Fragment 中使用它。例如,在您的代码中,您的片段与活动有很强的关系。方法 resetToolbarNavigation 正在与属于 Activity 的 View 进行交互,请注意该方法没有做任何事情,这是 Fragment 的责任,因此整个方法应该在 Activity 中实现,然后您可以在 BaseFragment 中发布一个接口,例如:

    //Get the instance of the activity implementation 
    private BaseFragmentActions baseFragmentActions;
    //Publish your interface with the methods your Activity will implement 
    public interface BaseFragmentActions {
        public void resetToolbarNavigation(boolean backNavigationEnabled);
    }
    
    //In your onAttach get the implementation from your activity
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
    
        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            baseFragmentActions = (BaseFragmentActions)activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString() + " must implement interface BaseFragmentActions");
        }
    }
    

然后在您的 Activity 中实现该方法并在您的片段中使用它,例如 baseFragmentActions.resetToolbarNavigation(true); 请注意,这种方式 BaseFragment 并不关心活动,只需要求包含它的活动必须实现它需要的方法。为此,您也可以使用 EventBus。

  • 片段之间的事务应该始终在包含它的 Activity 中完成。片段不应该知道/关心应该在之后加载哪个片段。

  • 使用“Activity 知道它是 Fragment,但 Fragment 不知道它是 Activity”的概念

您可以这样做,并且可以在 Fragment 中获得有关您的活动的信息,但这可能会带来像这样的大麻烦。

希望它可以帮助您作为未来设计的概念,对不起我的英语

于 2015-09-22T20:54:54.180 回答