0

I have main activity and three fragment (one, two, three). And all this fragments extands 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();
    }
}

}

But when i click back arrow i got 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 inside main activity

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

}

Can you help me? Where is the error? What am I doing wrong?

one_man
  • 135
  • 2
  • 14
  • which line is 56 in BaseFragment? – Jon Sep 22 '15 at 20:00
  • getActivity().onBackPressed(); – one_man Sep 22 '15 at 20:02
  • `getActivity()` must be returning null. Are you sure an activity is attached? – Jon Sep 22 '15 at 20:09
  • When I open the program displayed fragment 1 then moves to fragment 2 and then moves to fragment 3. When i click back 3->2 all work but when 2->1 dont work this error... And i open only fragment 1 and 2(2->1 )too work good. But it dont work when i have 3 and more fragments.........Excellent English!)))) – one_man Sep 22 '15 at 20:27

2 Answers2

1

Here's what I think is happening based on your comments.

  1. you open to fragment 1 and resetToolbarNavigation(boolean) gets called from onAttach
  2. you navigate to fragment 2 and resetToolbarNavigation(boolean) gets called from onAttach
  3. you navigate to fragment 3 and resetToolbarNavigation(boolean) gets called from onAttach
  4. you click the navigation button and fragment 3 handles it properly popping the backstack and navigating you back to fragment 2
    • resetToolbarNavigation(boolean) is not called from onAttach on fragment 2 because the fragment/activity wasn't destroyed and the fragment was never detached.
  5. you press the navigation button and it is handled by fragment 3 again which isn't started so getActivity() returns null

enter image description here

You should try setting the on navigation listener when the fragment displayed. If you are performing your fragment transactions correctly, you should be able to do this in onResume().

Jon
  • 9,156
  • 9
  • 56
  • 73
1

Not sure why you're getting that exact exception, but your approach to use the fragment is not so good in the way it's designed and that could bring this type of problems. So here I leave you some advices that has been useful to me when implementing apps with fragments:

  • Separate responsibilities: Activity should take care of it's stuff and Fragment should only be responsible for Fragment's functionalities. To achieve this you could make your Fragment publish interfaces with the methods you need the Activity implements and then just use it in the Fragment. For example in your code you have strong relations in your fragment form your Activity. Method resetToolbarNavigation is interacting with Views that belong to the Activity, notice that method is not doing nothing that is Fragment responsibility, so that entire method should be implemented in the activity, then you can publish a interface in your BaseFragment for example:

    //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");
        }
    }
    

Then in your Activity just implement the method and use it in your fragment like baseFragmentActions.resetToolbarNavigation(true); Notice that this way BaseFragment doesn't care about the activity, just ask that the activity that contain it have to implement the methods it needs. To achieve this you can use EventBus too.

  • The transactions between fragments should be done always in the Activity that contain it. A Fragment should not know/cares about which Fragment should be loaded after.

  • Use the concept "Activity knows it's Fragments but Fragment don't know it's Activity"

You can do it this way and you can have information of your Activity in your Fragment but that could bring bigs headaches like this one.

Hope it helps you as concept for future design and sorry for my English

labreu
  • 444
  • 4
  • 13
  • So I have to create a method in the middle fragment and implements this interface in my activity? Inside activity realize Override method..... – one_man Sep 23 '15 at 16:06
  • Yes for example your activity should implement that interface: public class MyActivity extends Activity implements BaseFragmentActions and then override the methods for that interface in your activity, then in your fragment you have in baseFragmentActions access to that implementations so you can use it, but there is not reference to the activity that's the nice part of it – labreu Sep 23 '15 at 16:12
  • You are well familiar with the structure of android. Could you see it http://stackoverflow.com/questions/32543292/gray-line-inside-cardview – one_man Sep 23 '15 at 16:34
  • if you can look there http://stackoverflow.com/questions/35514833/android-fragment-lige-cycle-and-up-arrow it's some problem with you answer – one_man Feb 19 '16 at 20:55