Reputation: 4900
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
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
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