Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preload some fragment when the app starts

I have an Android application with a navigation drawer. My problem is that some fragment takes few second to load (parser, Map API). I would like to load all my fragment when the app starts.

I'm not sure if it is possible or a good way to do it, but I was thinking of create an instance of each of my fragments in the onCreate method of the main activity. Then, when the user select a fragment in the navigation drawer, I use the existing instance instead of creating a new one.

The problem is that it does not prevent lag the first time I show a specific fragment. In my opinion, the reason is that the fragment constructor does not do a lot of operation.

After searching the web, I can't find an elegant way to "preload" fragment when the application starts (and not when the user select an item in the drawer).

Some post talks about AsyncTask, but it looks like MapFragment operation can't be executed except in the main thread (I got an exception when I try: java.lang.IllegalStateException: Not on the main thread).

here is what I've tried so far:

mFragments = new Fragment[BasicFragment.FRAGMENT_NUMBER];
mFragments[BasicFragment.HOMEFRAGMENT_ID] = new HomeFragment();
mFragments[BasicFragment.CAFEFRAGMENT_ID] = new CafeFragment();
mFragments[BasicFragment.SERVICEFRAGMENT_ID] = new ServiceFragment();
mFragments[BasicFragment.GOOGLEMAPFRAGMENT_ID] = new GoogleMapFragment();

When an item is selected in the nav drawer:

private void selectItem(int position) {

    Fragment fragment = mFragments[position];

    // here, I check if the fragment is null and instanciate it if needed

    FragmentManager fragmentManager = getFragmentManager();
    FragmentTransaction ft = fragmentManager.beginTransaction();
    ft.replace(R.id.content_frame, fragment);
    ft.commit();

    mDrawerList.setItemChecked(position,true);
    mDrawerLayout.closeDrawer(mDrawerList);
}

I also tried this solution; it allows to prevent a fragment from being loaded twice (or more), but it does not prevent my app from lag the first time I show it. That's why I try to load all fragments when the application starts (using a splash-screen or something) in order to prevent further lags.

Thanks for your help / suggestion.

like image 332
DavidL Avatar asked Oct 19 '22 14:10

DavidL


2 Answers

You can put your fragments in ViewPager. It preloads 2 pages(fragments) by default. Also you can increase the number of preloaded pages(fragments)

mViewPager.setOffscreenPageLimit(int numberOfPreloadedPages);

However, you will need to rewrite your showFragment method and rewrite back stack logic.

like image 56
Michael Katkov Avatar answered Oct 27 '22 11:10

Michael Katkov


One thing you can do is load the resources in a UI-less fragment by returning null in in Fragment#onCreateView(). You can also call Fragment#setRetainInstance(true) in order to prevent the fragment from being destroyed.

This can be added to the FragmentManager in Activity#onCreate(). From there, Fragments that you add can hook in to this resource fragment to get the resources they need.

So something like this:

public class ResourceFragment extends Fragment {
   public static final String TAG = "resourceFragment";

   private Bitmap mExtremelyLargeBitmap = null;

   @Override
   public View onCreateView(ViewInflater inflater, ViewGroup container, Bundle savedInstanceState) {
     return null;
  }

  @Override
  public void onStart() {
     super.onStart();
     new BitmapLoader().execute();
  }

  public Bitmap getExtremelyLargeBitmap() {
     return mExtremelyLargeBitmap;
  }

  private class BitmapLoader extends AsyncTask<Void, Void, Bitmap> {
      @Override
      protected Bitmap doInBackground(Void... params) {
          return decodeBitmapMethod();
      }

      @Override
      protected void onPostExecute(Bitmap result) {
          mExtremelyLargeBitmap = result;
      }
  }
}

Add it to the fragment manager in the Activity first thing. Then, whenever you load your other Fragments, they merely have to get the resource fragment from the fragment manager like so:

public class FakeFragment extends Fragment {

   @Override
   public View onCreateView(ViewInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        final ResourceFragment resFragment = getFragmentManager().findFragmentByTag(ResourceFragment.TAG);
        Bitmap largeBitmap = resFragment.getBitmap();
        if (largeBitmap != null) {
            // Do something with it.
        }
   }
}

You will probably have to make a "register/unregister" listener set up because you will still need to wait until the resources are loaded, but you can start loading resources as soon as possible without creating a bunch of fragments at first.

like image 37
DeeV Avatar answered Oct 27 '22 11:10

DeeV