我的DrawerLayout主要内容包含一个片段。这个片段里面有一个GoogleMap。应用程序启动时,它可以正常工作,但在方向更改时,地图会变为空白。我无法弄清楚为什么......有人可以对此有所了解吗?
这是完整的代码。
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>
答案 0 :(得分:1)
当LayoutInflator对视图进行膨胀时,它使用当前的Context在View对象中创建引用
view = (View) inflater.inflate(R.layout.map_fragment, container, false);
问题在于您的静态视图字段:
private static View view;
方向改变(即屏幕旋转)导致活动重新开始,调用&#39; onCreate()&#39;方法再次启动一个新的活动实例和非保留的碎片。
当Activity重新启动并调用onCreate()方法时,您的代码会创建LocationFragment()的新实例。
当创建一个新的Fragment,但是你的静态视图字段包含对前一个Fragment的视图的引用时,视图中的Context将保留对旧Fragment的Context的死引用。因此,您不应使用静态视图字段来保存参考
解决此问题的最简单方法是使视图字段非静态
private View view;
此外,由于您使用同步方法加载地图,因此会遇到性能问题:
mMap = ((SupportMapFragment) mapFragmentManager.findFragmentById(R.id.location_map)).getMap();
相反,你应该使用
((SupportMapFragment)mapFragmentManager.findFragmentById(R.id.location_map)).getMapAsync(this);
并使您的LocationFragment
班级实施OnMapReadyCallback
这会在加载地图时将屏幕留空,但会在加载地图时保存屏幕不会阻塞或冻结
如果您如此倾向,可以在LocationFragment
上使用 setRetainInstance()来解决此问题,这会导致片段在轮换时不重绘,并且您可以保留相同的GoogleMaps对象和View。要保留Fragment实例,请在片段的onCreate()
方法中添加setRetainInstance(true)
public class LocationFragment extends Fragment {
....
protected void onCreate(Bundle saved) {
super.onCreate(saved);
setRetainInstance(true);
...
}
并在您的活动中,替换
mapFragmentManager = getSupportFragmentManager();
android.app.FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, new LocationFragment()).commit();
带
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);