Android DrawerLayout с черным экраном MapFragment при возврате на карту

Я экспериментировал с android.support.v4.widget.DrawerLayout и у меня есть 4 фрагмента на выбор из ящика. Карта изначально загружается без проблем, однако, когда я открываю ящик и меняю фрагменты, я не могу вернуться к карте. У меня просто черный экран. Logcat показывает, что фрагмент воссоздан, но я ничего не получаю. Просто пустой черный экран. Я могу переключаться между другими фрагментами без проблем. Что я делаю неправильно? В моем проекте минимальный API равен 14.

Я загружаю ExploreMap (фрагмент) из MainActivity.java здесь:

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

в ExploreMap.java я делаю следующее

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 выглядит следующим образом

 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>

и 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>

person kev    schedule 18.10.2013    source источник


Ответы (3)


После нескольких дней биения головой о стену я понял проблему, или, лучше сказать, проблему. tsp предложил использовать библиотеки выше, которые тоже работают, однако я хотел, чтобы это работало с предоставленным Google android.support.v4.widget.DrawerLayout.

Проблема была в 2 раза.

  1. Я использовал вложенные фрагменты и не удалял дочерний фрагмент (карту) при выходе из фрагмента ExploreMap. Моя иерархия такова: Activity(DrawerLayout)-->ExploreMap(A Fragment)-->MapFragment. При открытии ящика и изменении фрагментов я не удалял MapFragment из ExploreMap (фрагмент). Исходный экземпляр MapFragment остался в памяти из-за setRetainInstance(true). По причинам, которые я до сих пор не совсем понимаю, исходный экземпляр MapFragment не появится снова после возвращения к фрагменту ExploreMap. Чтобы решить эту проблему, я назначаю MapFragment строковый тег, который я назвал «mapfrag» при его первоначальном создании, и устанавливаю переменную public static. Затем в действии, где код ящика предназначен для переключения фрагментов, я делаю findFragmentByTag() и проверяю, является ли это null, удаляя MapFragment, если он не равен нулю.

Однако # 1 дает вам только половину пути, поскольку он заставит карту снова появиться, когда вы вернетесь к ExploreMap, однако базовый GoogleMap из MapFragment продолжал возвращать мне значение null, и я вообще не мог настроить карту.

2) Я нашел этот пост MapFragment return null. В котором рекомендуется расширить свой собственный MapFragment и реализовать интерфейс для уведомления о завершении создания MapFragment, что в значительной степени гарантирует ненулевой GoogleMap.

и БУМ!! у вас есть рабочая карта Google в макете ящика Google. Вот мой полный рабочий код.

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);
                    }
                }
            }  
        }

а теперь 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());     
      }


}

ВАШЕ ЗДОРОВЬЕ!!!

person kev    schedule 25.10.2013

Я надеюсь, что это сработает для вас: https://github.com/jfeinstein10/SlidingMenu https://play.google.com/store/apps/details?id=com.slidingmenu.example&hl=en

person shivang Trivedi    schedule 18.10.2013
comment
Спасибо за рекомендацию, однако я не вижу, чем использование вышеуказанного будет отличаться от использования предоставленного Google android.support.v4.widget.DrawerLayout. Функциональность та же, и я бы предположил, что получу тот же результат. Вы успешно использовали эту библиотеку, чтобы получить фрагмент карты внутри ящика? - person kev; 18.10.2013
comment
Я изо всех сил пытаюсь скомпилировать пример приложения. Я импортировал пример и зависимую библиотеку, однако пример проекта не может разрешить R. Был ли обычно чистый проект и т. Д., Но нет. Я заметил, что в зависимых библиотеках есть ../ABS, который не разрешается, но я не знаю, где он находится и что это такое. Есть идеи? - person kev; 20.10.2013

Простое решение этой проблемы, найденное в почтовой ветке. Это решило мою проблему. Используйте относительную компоновку и поместите этот прозрачный вид прямо поверх вашего фрагмента карты. Пример :

<?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>
person Rasika Perera    schedule 12.06.2014