Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MapFragment: bad performance after using the back button

I have a performance issue when using MapFragment together with the action bar menu.

The bug emerges when three conditions are met

  1. Have a MapFragment instantiated.
  2. Trigger a fragment transaction from the options menu, replacing the map fragment with another fragment.
  3. Hit the back button and return to the map fragment. The performance is now noticeably degraded. Panning and zooming is very jerky.

Opening the options menu again and dismissing it again fixes the issue.

The behavior does not arise when

  • Triggering the fragment replacement from a view button instead from the options menu.
  • Triggering the fragment replacement right in onCreate()
  • replacing the blank fragment with MapFragment from the options menu
  • calling popBackStack from the options menu
  • using a ListFragment instead of a MapView

Minimal working example (requires access to Google Maps API):

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;

import com.google.android.gms.maps.MapFragment;

public class MapFragmentBugActivity extends Activity {
    Fragment mMapFragment;
    String MAP = "Map";
    String BLANK = "Blank";

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_fragment_bug);
        mMapFragment = new MapFragment();
        getFragmentManager().beginTransaction()
                .replace(R.id.main, mMapFragment)
                .commit();
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(MAP);
        menu.add(BLANK);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Fragment fragment;

        if (item.getTitle().equals(MAP)) {
            fragment = mMapFragment;
        } else {
            fragment = new Fragment();
        }

        getFragmentManager()
                .beginTransaction()
                .replace(R.id.main, fragment)
                .addToBackStack(null)
                .commit();

        return true;
    }
}

Activity layout, nothing special

<?xml version="1.0" encoding="utf-8"?>

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/main"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:clickable="true" />
like image 443
Otto Allmendinger Avatar asked Aug 07 '14 11:08

Otto Allmendinger


1 Answers

The fragment transaction is performed before the options menu is closed, this causes the weird behavior.

Instead of directly performing the fragment transaction, post it on the Handler. Once the options menu is closed, then the fragment transaction will be performed.

Try this :

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    final Fragment fragment;

    if (item.getTitle().equals(MAP)) {
        fragment = mMapFragment;
    } else { 
        fragment = new Fragment();
    } 

    Handler handler = new Handler();
    handler.post(new Runnable() {

        @Override
        public void run() {
            getFragmentManager()
            .beginTransaction()
            .replace(R.id.main, fragment)
            .addToBackStack(null)
            .commit();    
        }

    });     

    return true;
}
like image 124
Manish Mulimani Avatar answered Nov 17 '22 22:11

Manish Mulimani