Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fragment onCreateView and onActivityCreated not being called on rotation

I am working with fragments and pushing new fragments on the backstack but when I rotate the device twice the fragment's onCreateView, onActivityCreated, and so on in the fragment life cycle methods are never called leaving a blank screen. This only occurs when a fragment has been added to the backstack or returning to the first fragment in the backstack.

Here is my activity's fragment handling methods:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // Injection
    MormonChannel.injectActivity(this);

    setDrawerIndicatorEnabled(true);

    // Do not set currentNavigationItem here.
    NavigationItemSelectedEvent.NavigationItem navItem = null;
    Intent intent = getIntent();
    if (intent != null) {
        navItem = (NavigationItemSelectedEvent.NavigationItem)
        intent.getSerializableExtra(EXTRA_NAV_ITEM);
    }

    if (savedInstanceState == null) {
        FragmentManager fm = getSupportFragmentManager();
        fm.beginTransaction().replace(R.id.container, new FeatureListFragment()).commit();
        if (navItem != null) {
            onNavigationItemSelected(new NavigationItemSelectedEvent(navItem));
        } else {
            currentNavigationItem = NavigationItemSelectedEvent.NavigationItem.FEATURES;
        }
    }

}

@Subscribe
public void onNavigationItemSelected(NavigationItemSelectedEvent event) {

    if (currentNavigationItem == event.getNavigationItem()) {
        return;
    }
    FragmentManager fragmentManager = getSupportFragmentManager();
    fragmentManager.popBackStack();
    NavigationItemSelectedEvent.NavigationItem navigationItem = event.getNavigationItem();
    String name = navigationItem.getName();
    switch (navigationItem) {
        default:
        case FEATURES:
            // Nothing needs to be done it is already there.
            break;
        case AUDIO:
            fragmentManager.beginTransaction().replace(R.id.container,
                    CollectionListFragment.newInstance(prefs.getLanguageId(), prefs.getAudioCollectionId()))
                    .addToBackStack
                            (name).commit();
            break;
        case VIDEO:
            fragmentManager.beginTransaction().replace(R.id.container,
                    CollectionListFragment.newInstance(prefs.getLanguageId(), prefs.getVideoCollectionId()))
                    .addToBackStack(name).commit();
            break;
        case RADIO:
            fragmentManager.beginTransaction().replace(R.id.container,
                    CollectionListFragment.newInstance(prefs.getLanguageId(), prefs.getRadioCollectionId()))
                    .addToBackStack(name).commit();
            break;
        case HISTORY:
            fragmentManager.beginTransaction().replace(R.id.container, new HistoryFragment()).addToBackStack(name).commit();
            break;
        case DOWNLOADS:
            fragmentManager.beginTransaction().replace(R.id.container, new DownloadsFragment()).addToBackStack(name).commit();
            break;
        case PLAYLISTS:
            fragmentManager.beginTransaction().replace(R.id.container, new PlaylistFragment()).addToBackStack(name).commit();
            break;
    }
    currentNavigationItem = navigationItem;
}

Here is my CollectionListFragment Code:

 @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    MormonChannel.injectFragment(this);
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View v = inflater.inflate(R.layout.collection_list_fragment, container, false);
    ButterKnife.inject(this, v);
    return v;
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);

    listView.setDividerHeight(0);
    listView.setFastScrollEnabled(true);


    Bundle args = getArguments();
    if (args != null) {
        languageId = args.getLong(ARG_LANGUAGE_ID, -1L);
        collectionId = args.getLong(ARG_COLLECTION_ID, -1L);
        if (args.containsKey(ARG_SORT)) {
            sort = (Sort) args.getSerializable(ARG_SORT);
        }
    }

    if (collectionId == -1L || languageId == -1L) {
        // TODO Implement Empty Collection Text
    } else {
        collection = collectionManager.findByCollectionId(languageId, collectionId);
        getLoaderManager().initLoader(LOADER_ID, null, this);
    }

    titleEvent = new TitleChangeEvent(collection != null ? collection.getTitle() : getString(R.string.app_name));
    bus.post(titleEvent);
}

Manifest for activity:

<activity
    android:name=".activity.MainActivity"
    android:launchMode="singleTask">
    <meta-data
        android:name="android.app.default_searchable"
        android:value=".activity.SearchActivity"/>
</activity>
like image 505
Ge3ng Avatar asked Apr 30 '14 15:04

Ge3ng


People also ask

What are the differences between onCreate () onCreateView () and onActivityCreated () in fragments and what would they each be used for?

The onCreate() is called first, for doing any non-graphical initialisations. Next, you can assign and declare any View variables you want to use in onCreateView() . Afterwards, use onActivityCreated() to do any final initialisations you want to do once everything has completed.

Is onCreate or onCreateView called first?

onCreate() is called to do initial creation of the fragment. onCreateView() is called by Android once the Fragment should inflate a view. onViewCreated() is called after onCreateView() and ensures that the fragment's root view is non-null .

What is the difference between onCreate () and onCreateView () lifecycle methods in fragment?

onCreate is called on initial creation of the fragment. You do your non graphical initializations here. It finishes even before the layout is inflated and the fragment is visible. onCreateView is called to inflate the layout of the fragment i.e graphical initialization usually takes place here.

What is called after onCreateView?

The onActivityCreated() method is called after onCreateView() and before onViewStateRestored() . onDestroyView() : Called when the View previously created by onCreateView() has been detached from the Fragment . This call can occur if the host Activity has stopped, or the Activity has removed the Fragment .


1 Answers

In your CollectionListFragment Code, add call to setRetainInstance() method in the onCreate() method, with true as its argument:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setRetainInstance(true);
    MormonChannel.injectFragment(this);

}

Using setRetainInstance(true) ensures that when configuration changes occur activity will be killed but android will not destroy the fragment it is hosting.

Instead android will save the fragment state and detach the fragment from the activity. Also it wont destroy the fragment and so it wont create it later when hosting activity is created. So fragment will not receive calls to its onDestroy() and onCreate() methods.

like image 85
Nipun Anand Avatar answered Oct 03 '22 02:10

Nipun Anand