Android DrawerLayout with MapFragment black screen when returning to map

喜欢而已 提交于 2019-12-11 01:04:04

问题


I've been experimenting with android.support.v4.widget.DrawerLayout and have 4 fragments to choose from the drawer. The map initially loads with no problems however when I open the drawer and change fragments I am unable to then go back to the map. I just get a black screen. Logcat is showing the fragment is re-created but yet I get nothing. Just a blank black screen. I can switch between the other fragments with no problem. What am I doing wrong? My project has a Min API of 14.

I load the ExploreMap (a fragment) from MainActivity.java here:

        if (position == 0){
            ExploreMap exMap = new ExploreMap();
            exMap.setRetainInstance(true);
            getFragmentManager().beginTransaction().replace(R.id.content_frame, exMap).commit();
        }

in ExploreMap.java I do the following

public class ExploreMap extends Fragment implements OnInfoWindowClickListener, android.location.LocationListener, OnMapLongClickListener{

 private LocationManager mLocManager;
 private GoogleMap mMap;
 private MapFragment mMapFragment;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        FragmentManager fm = getActivity().getFragmentManager();
        mMapFragment = (MapFragment) fm.findFragmentById(R.id.map);


        if (mMapFragment == null) {
            mMapFragment = MapFragment.newInstance();
            fm.beginTransaction().replace(R.id.map, mMapFragment).commit();
        }


        if (savedInstanceState == null) {
            // First incarnation of this activity.
            mMapFragment.setRetainInstance(true);
        }else {
            // Reincarnated activity. The obtained map is the same map instance in the previous
            // activity life cycle. There is no need to reinitialize it.
            mMap = mMapFragment.getMap();
        }

        createMapIfNeeded();


       return inflater.inflate(R.layout.explore_map_layout, container, false);
    }




    @Override
    public void onResume() {
        super.onResume();
        //create the map
       createMapIfNeeded();  
    }





    private void createMapIfNeeded(){

        if(mLocManager == null){
            mLocManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
            mLocManager.requestLocationUpdates(
                       LocationManager.NETWORK_PROVIDER,
                       MIN_TIME_BW_UPDATES,
                       MIN_DISTANCE_CHANGE_FOR_UPDATES,
                       this);
        }

         //locmanager can return null if no last known locaiton is available.
        location = mLocManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);


        //if a map has not already been instantiated it'll return null
        if(mMap == null){
            //instantiate map
            mMap = mMapFragment.getMap();
            //check it has been instantiated

            if(mMap != null){   
                mMap.setOnMapLongClickListener(this);
                mMap.setOnInfoWindowClickListener(this);
                mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
                mMap.setMyLocationEnabled(true);

                //Manipulate map here (add coordinates/polylines from trip etc etc.)
                UiSettings setting = mMap.getUiSettings();
                setting.setTiltGesturesEnabled(true);
                setting.setRotateGesturesEnabled(true);
                setting.setZoomControlsEnabled(true);
                setting.setMyLocationButtonEnabled(true);

                if(location != null){
                CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 15);
                mMap.animateCamera(cu);
                }
            }
        }  
    }

XML's are as follows

 mainactivity_layout.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">

    <!-- As the main content view, the view below consumes the entire
         space available using match_parent in both dimensions. -->
    <FrameLayout
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <!-- android:layout_gravity="start" tells DrawerLayout to treat
         this as a sliding drawer on the left side for left-to-right
         languages and on the right side for right-to-left languages.
         The drawer is given a fixed width in dp and extends the full height of
         the container. A solid background is used for contrast
         with the content view. -->
    <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>

and exploremap_layout.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >


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

回答1:


After days of beating my head against the wall I figured out the problem, or should I say problemS. tsp suggested using libraries above which works too however I wanted to get this to work with the Google provided android.support.v4.widget.DrawerLayout.

The issue was 2 fold.

  1. I was using nested fragments and I wasn't removing the child (map) fragment when leaving the ExploreMap fragment. My hiearchy is: Activity(DrawerLayout)-->ExploreMap(A Fragment)-->MapFragment. When opening the drawer and changing fragments I was not removing the MapFragment from the ExploreMap(fragment). The original MapFragment instance remained in memory due to setRetainInstance(true). For reasons I still don't fully understand the original instance of the MapFragment would not re-appear once returning to the ExploreMap fragment. To solve this I assign the MapFragment a String tag I called "mapfrag" when it is initially created and set the variable to be public static. Next in the Activity, where the drawer code is to switch fragments, I do a findFragmentByTag() and test if its null, removing the MapFragment if it is not null.

However #1 only gets you half way as it will get the map to reappear when you go back to the ExploreMap however the underlying GoogleMap from the MapFragment kept returning null to me and I couldn't get the map configured at all.

2) I found this post MapFragment return null. Which recommended extending your own MapFragment and implementing an interface to notify when the MapFragment is done being created, pretty much guaranteeing a non-null GoogleMap.

and WHAMMY!! you have a working google map in googles drawer layout. Here is my complete working code.

MainActivity.java
 if (position == 0){
                exMap = new ExploreMap();
                exMap.setRetainInstance(true);
                getFragmentManager().beginTransaction().replace(R.id.content_frame, exMap).commit();
            }
            if(position == 1){  
                //remove map frag here instead of in explore map
                Fragment f = getFragmentManager().findFragmentByTag("mapfrag");
                if(f != null){
                     getFragmentManager().beginTransaction().remove(f).commit();
                }

                Ms fragment = new Ms();
                getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit(); 
            }
            if(position == 2){
                Fragment f = getFragmentManager().findFragmentByTag("mapfrag");
                if(f != null){
                     getFragmentManager().beginTransaction().remove(f).commit();
                }
                Settings fragment = new Settings();
                getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit(); 
            }
            if(position == 3){
                Fragment f = getFragmentManager().findFragmentByTag("mapfrag");
                if(f != null){
                     getFragmentManager().beginTransaction().remove(f).commit();
                }
                About fragment = new About();
                getFragmentManager().beginTransaction().replace(R.id.content_frame, fragment).commit(); 
            }

in ExploreMap.java

public class ExploreMap extends Fragment implements MyMapFragment.MapCallback,  OnInfoWindowClickListener, android.location.LocationListener, OnMapLongClickListener{

     private LocationManager mLocManager;
     private GoogleMap mMap;
     public static MyMapFragment mMapFragment;

@Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View v = inflater.inflate(R.layout.explore_map_layout, container, false); 


            FragmentManager fm = getActivity().getFragmentManager();
            mMapFragment = (MyMapFragment) fm.findFragmentById(R.id.map_framelayout);


            if (mMapFragment == null) {
                mMapFragment = new MyMapFragment();
                mMapFragment.setRetainInstance(true);
                mMapFragment.setMapCallback(this);
                fm.beginTransaction().replace(R.id.map_framelayout, mMapFragment,"mapfrag").commit();
            }

            createMapIfNeeded();

            return v;
        }



        @Override
        public void onMapReady(GoogleMap map) {
            createMapIfNeeded();
        }   

private void createMapIfNeeded(){

            if(mLocManager == null){
                mLocManager = (LocationManager) getActivity().getSystemService(Context.LOCATION_SERVICE);
                mLocManager.requestLocationUpdates(
                           LocationManager.NETWORK_PROVIDER,
                           MIN_TIME_BW_UPDATES,
                           MIN_DISTANCE_CHANGE_FOR_UPDATES,
                           this);
            }

             //locmanager can return null if no last known locaiton is available.
            location = mLocManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);


            //if a map has not already been instantiated it'll return null
            if(mMap == null){
                //instantiate map
                mMap = mMapFragment.getMap();


                //check it has been instantiated
                if(mMap != null){
                    mMap.setOnMapLongClickListener(this);
                    mMap.setOnInfoWindowClickListener(this);
                    mMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
                    mMap.setMyLocationEnabled(true);

                    //Manipulate map here (add coordinates/polylines from trip etc etc.)
                    UiSettings setting = mMap.getUiSettings();
                    setting.setTiltGesturesEnabled(true);
                    setting.setRotateGesturesEnabled(true);
                    setting.setZoomControlsEnabled(true);
                    setting.setMyLocationButtonEnabled(true);

                    if(location != null){
                    CameraUpdate cu = CameraUpdateFactory.newLatLngZoom(new LatLng(location.getLatitude(), location.getLongitude()), 15);
                    mMap.animateCamera(cu);
                    }
                }
            }  
        }

and now MyMapFragment.java

public class MyMapFragment extends MapFragment{



      private MapCallback callback;

      public static interface MapCallback
      {
         public void onMapReady(GoogleMap map);
      }

      public void setMapCallback(MapCallback callback)
      {
        this.callback = callback;
      }

      @Override public void onActivityCreated(Bundle savedInstanceState)
      {
          super.onActivityCreated(savedInstanceState);
         if(callback != null) callback.onMapReady(getMap());     
      }


}

CHEERS!!!




回答2:


I hope this will work for you: https://github.com/jfeinstein10/SlidingMenu https://play.google.com/store/apps/details?id=com.slidingmenu.example&hl=en




回答3:


Easy workaround for this issue found on a mail thread. This solved my issue. Use relative layout and place this transparent view directly over your map fragment. Example :

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

    <fragment
      android:id="@+id/map"
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      class="com.google.android.gms.maps.SupportMapFragment"/>

    <View
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:background="@android:color/transparent" />
</RelativeLayout>


来源:https://stackoverflow.com/questions/19441061/android-drawerlayout-with-mapfragment-black-screen-when-returning-to-map

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!