How to improve fragment loading speed?

25,848

Solution 1

I'm using a very hackish but effective way in my application, but it works good. My mapFragment is not displayed right after the app launches! Otherwise this would not make sense.

Put this in your launcher activity's onCreate:

    // Fixing Later Map loading Delay
    new Thread(new Runnable() {
        @Override
        public void run() {
            try {
                MapView mv = new MapView(getApplicationContext());
                mv.onCreate(null);
                mv.onPause();
                mv.onDestroy();
            }catch (Exception ignored){

            }
        }
    }).start();

This will create a mapview in an background thread (far away from the ui) and with it, initializes all the google play services and map data.

The loaded data is about 5MB extra.

If someone has some ideas for improvements feel free to comment please !


Java 8 Version:

// Fixing Later Map loading Delay
new Thread(() -> {
    try {
        MapView mv = new MapView(getApplicationContext());
        mv.onCreate(null);
        mv.onPause();
        mv.onDestroy();
    }catch (Exception ignored){}
}).start();

Solution 2

Just to add to @Xyaren's answer, I needed it to work for SupportFragment which seemed to require some extra steps. Have your activity implement OnMapReadyCallback.

In your onCreate:

new Thread(() -> {
    try {
        SupportMapFragment mf = SupportMapFragment.newInstance();
        getSupportFragmentManager().beginTransaction()
                .add(R.id.dummy_map_view, mf)
                .commit();
        runOnUiThread(() -> mf.getMapAsync(SplashActivity.this));
    }catch (Exception ignored){
        Timber.w("Dummy map load exception: %s", ignored);
    }
}).start();

You'll have to implement this:

@Override
public void onMapReady(GoogleMap googleMap) {
    // Do nothing because we only want to pre-load map.
    Timber.d("Map loaded: %s", googleMap);
}

and in your activity layout:

<FrameLayout
    android:id="@+id/dummy_map_view"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:visibility="gone"/>

It needs to go through all the steps including the transaction for Google Play Services to download the map data.

Solution 3

I had been running into this problem a lot too... Turns out the biggest culprit was having a debugging session attached to my app's process. The maps stuff in my app ran much faster and more smoothly when I disconnected the debugger, or just unplugged the USB cable.

Check out my related post here: First launch of Activity with Google Maps is very slow

Share:
25,848
Haifeng Zhang
Author by

Haifeng Zhang

When performance matters, professionals practice. My Site | haifzhan[at]gmail[dot]com My YouTube Channel

Updated on October 09, 2020

Comments

  • Haifeng Zhang
    Haifeng Zhang over 3 years

    Performance Enhancement:

    Previously I saved ALL images in drawable folder, this might be the reason why the map first loads slow, when draw the markers on screen, the image may not fit the screen size. Now I saved images in drawable-mdpi, drawable-hdpi and so on, the app works smoother than before. Hope it helps

    Original Question:

    I created a map in a fragment, the source code can be found below.

    The map fragment is sluggish when the first time it loads. If I go any other fragment and click the map fragment again, it loads fast and no slug anymore.

    Can anyone tell me what is going on here? Thanks!

    fragment_map.xml, id is map

    <?xml version="1.0" encoding="utf-8"?>
    <fragment xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:map="http://schemas.android.com/apk/res-auto"
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="com.google.android.gms.maps.SupportMapFragment" />
    

    MyMapFragment.java (contains onCreateView and setUpMapIfNeeded)

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        try {
            rootView = inflater.inflate(R.layout.fragment_map, container, false);
        } catch (InflateException e) {
        /* map is already there, just return view as it is */
            Log.e(TAG, "inflateException");
        }
    
        setUpMapIfNeeded();
         
        return rootView;
    }
    
    
    public void setUpMapIfNeeded() {
        // Do a null check to confirm that we have not already instantiated the fragment_map.
        if (myMap == null) {
            // Try to obtain the fragment_map from the SupportMapFragment.
            myMap = ((SupportMapFragment) MainActivity.fragmentManager.findFragmentById(R.id.map)).getMap();
            // Check if we were successful in obtaining the fragment_map.
            if (myMap != null) {
                setUpMap();
            }
        }
    }
    
  • Haifeng Zhang
    Haifeng Zhang over 9 years
    Thanks for your quick reply, it is still slow when i comment out setUpMap
  • cybersam
    cybersam over 9 years
    getMap() can be slow. So, the call to getMap() should also be handled by the AsyncTask. I have edited my answer.
  • Haifeng Zhang
    Haifeng Zhang over 9 years
    what's the difference between getMap() in my fragment and handled by a AsyncTask? If I put it into asynctask, how do i know the getMap() is ready other than null?
  • cybersam
    cybersam over 9 years
    I've put more info in my answer.
  • Haifeng Zhang
    Haifeng Zhang over 9 years
    thanks for your help, i tried asynctask, does not help
  • Kenneth
    Kenneth over 9 years
    I've also tried this without luck. It doesn't appear to use any time on the UI thread, at least not directly from the getMap-call.
  • theblang
    theblang over 9 years
    I've tested, this slow load has nothing to do with getMap. The delay happens somewhere between onViewCreated and onStart in this code.
  • guy_m
    guy_m over 8 years
    You're awesome. I've been trying to fix it for some time now, thought it's a non-related animation thing even. It's not hacking for me, it's pre-loading, I love it:)
  • guy_m
    guy_m over 8 years
    Actually, I would gladly give you a bounty on this. is it OK to start a bounty just for this, or is it "against the rules"? Asking seriously..
  • Xyaren
    Xyaren over 8 years
    I'm glad I was able to help :) I think the bounty is possible but I'm not an expert for this question.
  • Cruncher
    Cruncher over 8 years
    I wouldn't even call this hakish
  • marmor
    marmor over 8 years
    this works great on Android 5.1, on a device running 4.0.4 this crashes with: RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
  • Xyaren
    Xyaren over 8 years
    Try running the Runnable on the UI Thread by using runOnUiThread() instead of new Thread().start()
  • Pelanes
    Pelanes almost 8 years
    I've put this trick code on my BaseApplication class onCreate() to load playservices every time the app starts because in my app maps will be loaded at any time. I have reduced my mapFragment loading time from 980ms to 311ms, great. Thanks
  • raditya gumay
    raditya gumay almost 8 years
    use this mapView.getMapAsync(this);
  • Langusten Gustel
    Langusten Gustel over 7 years
    Haha, if you dont ignore the exception you get an java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
  • Xyaren
    Xyaren over 7 years
    welll that's why its a workaround. Still does it's job.
  • Jemshit Iskenderov
    Jemshit Iskenderov about 7 years
    2 things i have noticed. 1) It is still slow when you don't use new Thread() 2) It is still slow when you use new Thread() and use other lifecycle methods mapView.onStart(), mapView.onStop ...
  • Jemshit Iskenderov
    Jemshit Iskenderov about 7 years
    Just noticed error that @LangustenGustel has written, which make code stuck at mv.onCreate(null); and rest is not even executed! Now changed code to mapView.getMapAsync(this); after mapView.onCreate(null); without new Thread(). And in onMapReady() callback i close launcher screen
  • us2956
    us2956 about 6 years
    Map doesn't loaded.
  • murki
    murki almost 6 years
    FWIW I opened a bug against Google: issuetracker.google.com/issues/80147879 Feel free to star it if you think they should address this at the root of the problem
  • Vahid
    Vahid about 3 years
    or just unplugged the USB cable this helped me a lot