I'm trying to build a NavigationView with one Activity and as many Fragments as nav items: first item tapped --> first fragment loads a random remote image; second/third item tapped --> other fragments are loaded. My goal is, while switching back to first item, showing the already downloaded image instead of fetching for a new picture.
activity_main.xml
<android.support.v4.widget.DrawerLayout
(.....)
android:id="@+id/drawer_layout">
<!-- This LinearLayout represents the contents of the screen -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<!-- The ActionBar displayed at the top -->
<include
layout="@layout/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<!-- The main content view where fragments are loaded -->
<FrameLayout
(......)
android:id="@+id/flContent"/>
</LinearLayout>
<!-- The navigation drawer that comes from the left -->
<android.support.design.widget.NavigationView
(.......)
android:id="@+id/nvView" />
MainActivity
public class MainActivity extends AppCompatActivity {
Fragment homeFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//......
setupDrawerContent(nvDrawer);
if (findViewById(R.id.flContent) != null && savedInstanceState == null) {
homeFragment = new HomeFragment();
getSupportFragmentManager().beginTransaction().add(R.id.flContent, homeFragment, "homeFragment").commit();
}
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
getSupportFragmentManager().putFragment(outState, "homeFragment", homeFragment);
}
private void setupDrawerContent(NavigationView navigationView) {
navigationView.setNavigationItemSelectedListener(
new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
selectDrawerItem(menuItem);
return true;
}
}
);
}
public void selectDrawerItem(MenuItem menuItem) {
// Create a new fragment and specify the item to show based on
// position
Fragment fragment = null;
Class fragmentClass = null;
switch(menuItem.getItemId()) {
case R.id.nav_first_fragment:
fragmentClass = HomeFragment.class;
break;
case R.id.nav_second_fragment:
fragmentClass = SecondFragment.class;
break;
default:
fragmentClass = HomeFragment.class;
}
try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
// Insert the fragment by replacing any existing fragment
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
// Highlight the selected item, update the title, and close the drawer
menuItem.setChecked(true);
setTitle(menuItem.getTitle());
mDrawer.closeDrawers();
}
}
HomeFragment
public class HomeFragment extends Fragment {
private static final String TAG = "HomeFragment";
public HomeFragment() {
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
// ......
View fragmentView = inflater.inflate(R.layout.home_fragment, container, false);
if (savedInstanceState == null) {
// FETCH RANDOM IMAGE
}else {
// RESTORE IT (but always null)
}
return fragmentView;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putSerializable(/*SOME DATA*/);
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null) {
// ALWAYS NULL
}
}
}
I found this answer but I don't know how to do it since I just have a reference to a FrameLayout.
Tracking lifecycle methods I noticed that MainActivity in aways active so it never calls onSaveInstanceState and I don't know how to use Bundle within my HomeFragment to restore the savedInstanceState in onCreateView. Do you have any hints to share? Many thanks
When you replace a fragment with another one, the previous fragment (being replaced), is destroyed and whatever data it had in its non-static member variables is lost.
If you want to retain the image for a fragment, you can use a bitmap cache to store your images, but that will work only if you load the same image for your fragment. If you are loading random images and want to load the same image the next time you instantiate the same fragment (so you want your Home fragment to always load the same image it loaded the first time it was instantiated), then you need to persist that data. There are several ways to do it, you can use a static variable in your Home fragment to hold the URL for the image, you could store it in SharedPreferences, you could pass it to the Activity so the activity would then pass it back to the Home fragment when it creates again, and so on. Pick the solution that best fits your needs.