Anonymous
Anonymous

Reputation: 4900

GoogleMap in fragment goes blank at orientation change

I have a DrawerLayout with a fragment in its main content. This fragment has a GoogleMap in it. When the app starts it works perfectly but on orientation change the map goes blank. I can't figure out why.. Can someone shed some light on this?

Here is the complete code.

MainActivity

public class MainActivity extends FragmentActivity {

    public static FragmentManager mapFragmentManager;
    private DrawerLayout mDrawerLayout;
    private ListView mDrawerList;
    private ActionBarDrawerToggle mDrawerToggle;
    public static Context con;
    private CharSequence mDrawerTitle,mTitle;
    private String[] drawerOptions;
    static TextView corTextView;
    static EditText addressEditText,commentEditText;
    final static int image_pick=100,new_pic=112;
    static ImageView loadPic;
    static Bitmap bitmap;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        con=MainActivity.this;

        //set drawer navigation
        mTitle = mDrawerTitle = getTitle();
        drawerOptions = getResources().getStringArray(R.array.options_array);
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mDrawerList = (ListView) findViewById(R.id.left_drawer);
        mDrawerLayout.setDrawerShadow(R.drawable.drawer_shadow, GravityCompat.START);
        mDrawerList.setAdapter(new ArrayAdapter<String>(this, R.layout.drawer_list_item, drawerOptions));
        mDrawerList.setOnItemClickListener(new DrawerItemClickListener());
        getActionBar().setDisplayHomeAsUpEnabled(true);
        getActionBar().setHomeButtonEnabled(true);
        mDrawerToggle = new ActionBarDrawerToggle(
                this,                  /* host Activity */
                mDrawerLayout,         /* DrawerLayout object */
                R.drawable.ic_drawer,  /* nav drawer image to replace 'Up' caret */
                R.string.drawer_open,  /* "open drawer" description for accessibility */
                R.string.drawer_close  /* "close drawer" description for accessibility */
                ) {
            public void onDrawerClosed(View view) {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }

            public void onDrawerOpened(View drawerView) {
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
            }
        };
        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if (savedInstanceState == null) {
            selectItem(0);
        }

        //load main content
        mapFragmentManager = getSupportFragmentManager();
        android.app.FragmentManager fragmentManager = getFragmentManager();
        fragmentManager.beginTransaction().replace(R.id.content_frame, new LocationFragment()).commit();

    }

    @Override
    protected void onStop() {
        super.onStop();
        try{
            MainActivity.mapFragmentManager.beginTransaction().remove(MainActivity.mapFragmentManager.findFragmentById(R.id.location_map)).commit();
        }catch(Exception e){}
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.main, menu);
        return super.onCreateOptionsMenu(menu);
    }


    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_websearch).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle.onOptionsItemSelected(item)) {
            return true;
        }
        switch(item.getItemId()) {
        case R.id.action_websearch:
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }


    private class DrawerItemClickListener implements ListView.OnItemClickListener {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            selectItem(position);
        }
    }

    private void selectItem(int position) {
                    mDrawerList.setItemChecked(position, true);
        mDrawerLayout.closeDrawer(mDrawerList);
    }

    @Override
    public void setTitle(CharSequence title) {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }


    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggls
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    public static class LocationFragment extends Fragment{
        public LocationFragment() { }

        private static View view;
        private static GoogleMap mMap;

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

            if(view==null){
                view = (View) inflater.inflate(R.layout.map_fragment, container, false);
            }
            corTextView = (TextView)view.findViewById(R.id.cor_location_tv);
            addressEditText = (EditText)view.findViewById(R.id.address_location_tv);
            commentEditText = (EditText)view.findViewById(R.id.commentEditText);

            Button sendButton = (Button)view.findViewById(R.id.send_button);
            sendButton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    sendData();
                }
            });

            loadPic = (ImageView)view.findViewById(R.id.load_pic_img);
            loadPic.setOnClickListener(new View.OnClickListener() {

                @Override
                public void onClick(View v) {
                    AlertDialog.Builder builder =  new AlertDialog.Builder(con);
                    final CharSequence[] items = {"Take Pic Now","Load From Gallery"};
                    builder.setItems(items, new OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            switch (which){
                            case 0: takePicture(); break;
                            case 1: pickPicture(); break;
                            }
                        }
                    });
                    builder.show();
                }
            });

            setUpMapIfNeeded(); 

            return view;
        }


        @Override
        public void onActivityResult(int requestCode, int resultCode, Intent data) {
            // TODO Auto-generated method stub
            super.onActivityResult(requestCode, resultCode, data);
            if(resultCode==Activity.RESULT_OK){
                Uri source = data.getData();
                String imagepath = F.getRealPathFromURI(getActivity(), source);
                bitmap=F.getMiniThumbnailFromPath(con.getContentResolver(), imagepath);
                loadPic.setImageDrawable(new BitmapDrawable(con.getApplicationContext().getResources(),bitmap));
                loadPic.setScaleType(ImageView.ScaleType.FIT_CENTER);
            }
        }

        /***** Sets up the map if it is possible to do so *****/
        public static void setUpMapIfNeeded() {
            // Do a null check to confirm that we have not already instantiated the map.
            if (mMap == null) {
                // Try to obtain the map from the SupportMapFragment.
                mMap = ((SupportMapFragment) mapFragmentManager.findFragmentById(R.id.location_map)).getMap();
                // Check if we were successful in obtaining the map.
                if (mMap != null)
                    setUpMap();
            }
        }


        private static void setUpMap() {
            mMap.setMyLocationEnabled(true);
            LocationManager locationManager = (LocationManager) con.getSystemService(LOCATION_SERVICE);
            Criteria criteria = new Criteria();
            String provider = locationManager.getBestProvider(criteria, true);
            Location location = locationManager.getLastKnownLocation(provider);

            if(location!=null){
                locationChanged(location);
            }
            locationManager.requestLocationUpdates(provider, 20000, 0,listener );
        }


       public void sendData(){
            String comment= commentEditText.getText().toString();
            String address = addressEditText.getText().toString();
            if(address.equals("") || address.length()<5){
                Toast.makeText(con, "Type an address...", Toast.LENGTH_SHORT).show();
            }
            else if(bitmap ==null || bitmap.isRecycled()){
                Toast.makeText(con, "Load a picture..", Toast.LENGTH_SHORT).show();
            }
            else{
                //send data
            }
       }

       public static void setAddressFromCoordinates(double latitude, double longitude){
           corTextView.setText("Latitude:" +  latitude  + ", Longitude:"+ longitude );  
           String address = F.translateCoordinatesToAddress(con, latitude, longitude);
           if(!addressEditText.getText().toString().equals("") && address.equals("")){}
           else{addressEditText.setText(address);}
       }


       public static void locationChanged(Location location){
            double latitude = location.getLatitude();
            double longitude = location.getLongitude();     

            mMap.moveCamera(CameraUpdateFactory.newLatLng(new LatLng(latitude, longitude)));
            mMap.animateCamera(CameraUpdateFactory.zoomTo(15));
            setAddressFromCoordinates(latitude,longitude);

            mMap.clear();
            mMap.addMarker(new MarkerOptions().position(new LatLng(latitude, longitude)).title("My Home").snippet("Home Address"));
            mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(new LatLng(latitude, longitude), 13));

           CameraPosition cameraPosition = new CameraPosition.Builder()
           .target(new LatLng(latitude, longitude))      // Sets the center of the map to location user
           .zoom(17)                   // Sets the zoom
           .bearing(90)                // Sets the orientation of the camera to east
           .tilt(40)                   // Sets the tilt of the camera to 30 degrees
           .build();                   // Creates a CameraPosition from the builder
           mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
       }




      public static LocationListener listener = new LocationListener(){
        @Override
        public void onLocationChanged(Location location) {
            locationChanged(location);
        }
        @Override
        public void onStatusChanged(String provider, int status, Bundle extras) { }
        @Override
        public void onProviderEnabled(String provider) { }
        @Override
        public void onProviderDisabled(String provider) { }
      };


        public void takePicture(){
            Intent cameraIntent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
            startActivityForResult(cameraIntent, new_pic);
        }
        public void pickPicture(){
            startActivityForResult(new Intent(Intent.ACTION_PICK, android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI), image_pick);
        }


    }


}

activity_main.xml

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

   <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

   <ListView
        android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>
</android.support.v4.widget.DrawerLayout>

map_fragment.xml

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:orientation="vertical"
    android:paddingLeft="5dp"
    android:paddingRight="5dp"
     android:layout_height="wrap_content" >

<LinearLayout 
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical"
    >

    <ImageView
        android:id="@+id/load_pic_img"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:layout_width="120dp"
        android:layout_height="120dp"
        android:src="@drawable/take_pic" />

    <TextView
        android:layout_gravity="center"
        android:textColor="#376682"
        android:gravity="center"
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Chosen Problem Category"
        android:textAppearance="?android:attr/textAppearanceSmall" />


    <Button
        android:id="@+id/button1"
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="5dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Select Problem Category" />


    <TextView
        android:id="@+id/relative_info_title"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Relative Information"
        android:textAppearance="?android:attr/textAppearanceSmall" />
    <EditText
        android:id="@+id/commentEditText"
        android:gravity="center"
        android:hint="write your comment..."
        android:layout_gravity="center_horizontal"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium" />

    <TextView
        android:id="@+id/aproximate_address_title"
        android:layout_marginLeft="15dp"
        android:layout_marginTop="10dp"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Aproximate Address"
        android:textAppearance="?android:attr/textAppearanceSmall" />





    <TextView 
        android:id="@+id/cor_location_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <EditText 
        android:id="@+id/address_location_tv"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:hint="if address not found type it..."
        />
    <fragment
        android:id="@+id/location_map"
        android:layout_width="match_parent"
        android:layout_height="150dp"
        class="com.google.android.gms.maps.SupportMapFragment" />


    <Button
        android:id="@+id/send_button"
        android:background="#01b19f"
        android:layout_marginTop="10dp"
        android:layout_marginLeft="20dp"
        android:layout_marginRight="20dp"
        android:layout_marginBottom="20dp"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Send" />

    </LinearLayout>
</ScrollView>

Upvotes: 0

Views: 639

Answers (2)

Will Passidomo
Will Passidomo

Reputation: 47

When the LayoutInflator inflates the view, it uses the current Context to create a reference in the View object

view = (View) inflater.inflate(R.layout.map_fragment, container, false);

The problem lies in your static View field:

private static View view;

Orientation changes (i.e screen rotation) cause the activity to restart, calling the 'onCreate()' method again and starting a new Instance of the Activity and non-retained Fragments.

When the Activity restarts and the onCreate() method is called, your code creates a new instance of the LocationFragment().

When a new Fragment is created, but your static view field contains reference to the previous Fragment's View, the Context in the view will hold a dead reference to the old Fragment's Context. Therefore, you should not be using a static View field to save the reference

The easiest way to fix this would be to make view field non-static

private View view;

Furthermore you will run into performance issues with this because you are using a synchronous method to load the map:

mMap = ((SupportMapFragment) mapFragmentManager.findFragmentById(R.id.location_map)).getMap();

Instead, you should be using

((SupportMapFragment)mapFragmentManager.findFragmentById(R.id.location_map)).getMapAsync(this);

and make your LocationFragment class implement OnMapReadyCallback

This will leave the screen blank while the map is loading, but will save the screen from blocking or freezing while the map is loading

If you are so inclined, you can solve this problem by using setRetainInstance() on your LocationFragment, which will cause the fragment to not redraw on rotation, and for you to keep the same GoogleMaps object and View. To retain the Fragment instance, in the onCreate() method of your fragment add setRetainInstance(true)

public class LocationFragment extends Fragment {
....
protected void onCreate(Bundle saved) {
super.onCreate(saved);
setRetainInstance(true);
...
}

and in your Activity, replace

mapFragmentManager = getSupportFragmentManager();
    android.app.FragmentManager fragmentManager =      getFragmentManager();
    fragmentManager.beginTransaction().replace(R.id.content_frame, new     LocationFragment()).commit();

with

String TAG = "LocationFrag";
Fragment locationFragment = getSupportedFragmentManager().findFragmentByTag(TAG);

if (locationFragment != null && locationFragment instanceof LocationFragment) {
    getSupportedFragmentManager().replace(R.id.content_frame, locationFragment, TAG); 
}
getSupportedFragmentManager().replace(R.id.content_frame, new LocationFragment(), TAG);

Upvotes: 2

xxxzhi
xxxzhi

Reputation: 481

why you want use the static map filed?

private static GoogleMap mMap;

try to remove all of you static mark, use object filed.

private GoogleMap mMap;
private View view;
...

Hope this can help you.

Upvotes: 1

Related Questions