What if onAttach() is not overridden inside the fragment code?

Viewed 1113

According to fragment lifecycle onAttach() is called before onCreate() so that it assigns hosting activity to the fragment. So, I wanted to know what if it is not overridden. Does a default definition for all the fragment callbacks already exists?

2 Answers

From the documentation:

void onAttach (Activity activity)

called once the fragment is associated with its activity. This method was deprecated in API level 23. Use onAttach(Context) instead.

If you override this method you must call through to the superclass implementation.

void onAttach (Context context)

Called when a fragment is first attached to its context. onCreate(Bundle) will be called after this.

This is a lifecyle design for the fragment. There is nothing wrong when you don't override the method.

Does a default definition for all the fragment callbacks already exists?

No, you need to create the fragment callback by yourself. onAttach() method is usually overriden to make sure the parent activity of the fragment is implementing the fragment callback. Something like this (read more at Communicating with Other Fragments):

public class HeadlinesFragment extends ListFragment {
    OnHeadlineSelectedListener mCallback;

    // Container Activity must implement this interface
    public interface OnHeadlineSelectedListener {
        public void onArticleSelected(int position);
    }

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

        // This makes sure that the container activity has implemented
        // the callback interface. If not, it throws an exception
        try {
            mCallback = (OnHeadlineSelectedListener) context;
        } catch (ClassCastException e) {
            throw new ClassCastException(context.toString()
                    + " must implement OnHeadlineSelectedListener");
        }
    }

    ...
}

When the parent activity is not implementing OnHeadlineSelectedListener, the application will crash and throwing must implement OnHeadlineSelectedListener. Hence it will preventing you introducing a logic error in your code.


UPDATE

What the purpose of onAttach()?

According to fragment lifecycle onAttach() is called before onCreate() so that it assigns hosting activity to the fragment.

What the meaning of that actually?

Simple answer: It's a lifecyle of Fragment where we can know when the Fragment has been attached to it's parent activity.

More details:

From the the following source code of onAttach():

/**
 * Called when a fragment is first attached to its context.
 * {@link #onCreate(Bundle)} will be called after this.
 */
@CallSuper
public void onAttach(Context context) {
    mCalled = true;
    final Activity hostActivity = mHost == null ? null : mHost.getActivity();
    if (hostActivity != null) {
        mCalled = false;
        onAttach(hostActivity);
    }
}

/**
 * @deprecated Use {@link #onAttach(Context)} instead.
 */
@Deprecated
@CallSuper
public void onAttach(Activity activity) {
    mCalled = true;

}

We will see nothing except the documentation about our previous question and mHost.

on the source code of Fragment at https://github.com/android/platform_frameworks_base/blob/master/core/java/android/app/Fragment.java#L435, we can know that the mhost is actually a FragmentHostCallback:

// Activity this fragment is attached to.
FragmentHostCallback mHost;

But if we scanning through all the source code Fragment, we won't get any clue where the mhost is initialized.

We know that from the Fragment lifecyle diagram that the lifecyle is start when the fragment is added:

enter image description here

Programatically, we add the Fragment with:

FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

ExampleFragment fragment = new ExampleFragment();
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();

Checking the FragmentManager source code at line 1200 to 1229 from method moveToState():

void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
}

we have the following code:

f.mHost = mHost;
f.mParentFragment = mParent;
f.mFragmentManager = mParent != null
        ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();

// If we have a target fragment, push it along to at least CREATED
// so that this one can rely on it as an initialized dependency.
if (f.mTarget != null) {
    if (mActive.get(f.mTarget.mIndex) != f.mTarget) {
        throw new IllegalStateException("Fragment " + f
                + " declared target fragment " + f.mTarget
                + " that does not belong to this FragmentManager!");
    }
    if (f.mTarget.mState < Fragment.CREATED) {
        moveToState(f.mTarget, Fragment.CREATED, 0, 0, true);
    }
}

dispatchOnFragmentPreAttached(f, mHost.getContext(), false);
f.mCalled = false;
f.onAttach(mHost.getContext());
if (!f.mCalled) {
    throw new SuperNotCalledException("Fragment " + f
            + " did not call through to super.onAttach()");
}
if (f.mParentFragment == null) {
    mHost.onAttachFragment(f);
} else {
    f.mParentFragment.onAttachFragment(f);
}

Now we know that mHost and onAttach() of Fragment is initialized and called by the FragmentManager.

Nothing happens if you don't call OnAttach(). It is a lifecycle method provided to you if want to do something when the fragment is attached to its activity or context.

However, the fragment class does have a default implementation of OnAttach (which doesn't do anything). If you are curious, check out the source code.

Related