MapFragment in Fragment, альтернативы?

Мне нужна твоя помощь... Я работаю над ней до 3 дней. Мое приложение работает с фрагментами. Один из этих фрагментов должен отображать карту с Google Maps V2 api для Android.

В настоящее время я использую MapFragment, но не удивительно, что фрагмент в фрагменте не является хорошей идеей, но он работает, карта отображается, я могу ее редактировать, но когда я переключаю основной фрагмент и возвращаюсь он.

Вызывается: java.lang.IllegalArgumentException: двоичная строка XML файла # 59: Дубликат id 0x7f070041, тег null или родительский идентификатор 0x7f070040 с другим фрагментом для com.google.android.gms.maps.MapFragment

в android.app.Activity.onCreateView(Activity.java:4252)

на android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:673)

Это причина, когда я перехожу к другому фрагменту и возвращаюсь к тому, который содержит карту. Я ищу до 3 дней, чтобы исправить это, но никаких отличных результатов.

Чтобы возобновить работу, у меня есть Activity, который вызывает фрагмент, содержащий MapFragment в файле макета. Если вам нужно больше, просто спросите:)

Спасибо

Изменить: Вот код для изменения Фрагмента в основной деятельности

private void swtichFragment(Fragment fragment, Bundle bundle)
{
fragment.setBundle(this, bundle);
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.rightFragmentPlaceHolder, fragment);
fragmentTransaction.commit();
mRightFragment = fragment;
}

Ответ 1

Используйте MapView вместо MapFragment в макете фрагмента. Не забудьте вызвать методы жизненного цикла MapView:

  • OnCreate (Bundle)
  • onResume()
  • OnPause()
  • OnDestroy()
  • onSaveInstanceState (Bundle)
  • onLowMemory()

как описано здесь.

Btw. вы не должны использовать MapFragment, только SupportMapFragment и поддержку библиотеки.

Edit:

Если вы переключитесь на поддержку библиотеки, вы можете использовать код из комментария # 1 здесь: http://code.google.com/p/gmaps-api-issues/issues/detail?id=5064#c1

Ответ 2

Для устранения этой ошибки используйте SupportMapFragment:

В макете фрагмента

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

В вашем фрагменте onCreateView

SupportMapFragment mapFragment = (SupportMapFragment) getChildFragmentManager().findFragmentById(R.id.googleMap);

        if (mapFragment != null) {
            mapFragment.getMapAsync(this);
        }

Поскольку ваш макет находится в макете Fragment's, поэтому SupportMapFragment является дочерней компоновкой вашего фрагмента. Следовательно, используйте getChildFragmentManager(), который равен Fragment FragmentManager

Ответ 3

Как описано здесь

Чтобы отобразить MapFragment внутри фрагмента (NestedFragment): На данный момент я считаю, что у вас есть

  • добавлено необходимое разрешение на манифест
  • добавлена ​​служба google play как проект lib
  • ключ api в файле манифеста. 4.

where.xml

 <LinearLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            xmlns:map="http://schemas.android.com/apk/res-auto"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical" >
         <FrameLayout
           android:layout_width="match_parent"
           android:layout_height="0dp"
           android:layout_weight="1.03"
           android:name="com.google.android.gms.maps.SupportMapFragment"
           android:id="@+id/mapwhere" />


          <TextView
           android:layout_width="match_parent"
           android:layout_height="wrap_content"/>

        </LinearLayout>

Класс:

 public class WhereFragment extends SupportMapFragment {

    @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
     {
      super.onCreateView(inflater, container, savedInstanceState);
      View root = inflater.inflate(R.layout.where, null, false); 
      initilizeMap();
      return root;
     }

    private void initilizeMap()
     {
      mSupportMapFragment = (SupportMapFragment) getFragmentManager().findFragmentById(R.id.mapwhere);
      if (mSupportMapFragment == null) {
       FragmentManager fragmentManager = getFragmentManager();
       FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
       mSupportMapFragment = SupportMapFragment.newInstance();
       fragmentTransaction.replace(R.id.mapwhere, mSupportMapFragment).commit();
         }
      if (mSupportMapFragment != null)
      {
       googleMap = mSupportMapFragment.getMap();
       if (googleMap != null)
        googleMap.setOnMapClickListener(new OnMapClickListener()
        {
         @Override
         public void onMapClick(LatLng point)
         {
          //TODO: your onclick stuffs
         }
        });
      }
     }
    }

Документация:

Вложенные фрагменты Теперь вы можете вставлять фрагменты внутри фрагментов. Это полезно для различных ситуаций, в которых вы хотите и повторно используемые компоненты пользовательского интерфейса в компонент пользовательского интерфейса, который сам по себе является динамическим и повторно использовать. Например, если вы используете ViewPager для создания фрагментов которые прокручивают влево и вправо и потребляют большую часть пространства экрана, теперь вы можете вставлять фрагменты на каждую страницу фрагмента.

Чтобы вставить фрагмент, просто вызовите getChildFragmentManager() на Фрагмент, в который вы хотите добавить фрагмент. Это возвращает FragmentManager, который вы можете использовать, как обычно, из деятельность верхнего уровня для создания транзакций фрагментов. Например, heres некоторый код, который добавляет фрагмент из существующего фрагмента класс:

Фрагмент видеофрагмент = новый VideoPlayerFragment(); Операция FragmentTransaction =. GetChildFragmentManager() BeginTransaction(); transaction.add(R.id.video_fragment, videoFragment).commit(); Из внутри вложенного фрагмента вы можете получить ссылку на родителя фрагмента, вызвав getParentFragment().

Библиотека поддержки Android теперь также поддерживает вложенные фрагменты, поэтому вы могут реализовывать вложенные фрагменты на Android 1.6 и выше.

Примечание. Вы не можете раздувать макет во фрагмент, если этот макет включает a. Вложенные фрагменты поддерживаются только при добавлении к фрагменту динамически.

источник: http://developer.android.com/about/versions/android-4.2.html#NestedFragments

Это также будет исправлено для:

 11-06 11:36:01.509: E/AndroidRuntime(6309): FATAL EXCEPTION: main
    11-06 11:36:01.509: E/AndroidRuntime(6309): android.view.InflateException: Binary XML file line #9: Error inflating class fragment
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:710)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:752)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:760)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:760)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:760)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.rInflate(LayoutInflater.java:760)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.inflate(LayoutInflater.java:495)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at com.abc.android.ui.WhereFragment.onCreateView(WhereFragment.java:60)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.support.v4.app.Fragment.performCreateView(Fragment.java:1500)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682)
    11-06 11:36:01.509: E/AndroidRuntime(6309):  at a ...

Ответ 4

В вашем классе

      SupportMapFragment mSupportMapFragment;
      private GoogleMap googleMap;
      int ZOOM_LEVEL=15;

      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
       View mTrackView = inflater
            .inflate(R.layout.mylayout, container, false);
        mSupportMapFragment = SupportMapFragment.newInstance();
        FragmentTransaction fragmentTransaction = getChildFragmentManager().beginTransaction();
        fragmentTransaction.add(R.id.mapwhere, mSupportMapFragment);
        fragmentTransaction.commit();

        return mTrackView;
    }

      @Override
      public void onStart() {
        // TODO Auto-generated method stub
          super.onStart();

        if(mSupportMapFragment!=null){

            googleMap = mSupportMapFragment.getMap();
            if(googleMap!=null){
            googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
            googleMap.getUiSettings().setMyLocationButtonEnabled(false);
            googleMap.setMyLocationEnabled(false);


            CameraUpdate cameraUpdate = CameraUpdateFactory.newLatLngZoom(
                    new LatLng(12.12122,
                        17.22323), ZOOM_LEVEL);
            googleMap.animateCamera(cameraUpdate);
              }
            }
      }

mylayout.xml

    <LinearLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:map="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center"
        android:orientation="vertical" >
     <FrameLayout
       android:layout_width="match_parent"
       android:layout_height="0dp"
       android:layout_weight="1.03"

       android:id="@+id/mapwhere" />


      <TextView
       android:layout_width="match_parent"
       android:layout_height="wrap_content"/>

    </LinearLayout>

Ответ 5

После многих ошибок я наконец сделал это, вот мой класс фрагментов MapView: -

import android.content.Context;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.GoogleMap.OnMapClickListener;
import com.google.android.gms.maps.MapFragment;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
import com.serveroverload.yago.R;

/**
 * @author 663918
 *
 */
public class HomeFragment extends Fragment implements LocationListener {
    // Class to do operations on the Map
    GoogleMap googleMap;
    private LocationManager locationManager;

    public static Fragment newInstance() {
        return new HomeFragment();
    }

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

        // setuping locatiomanager to perfrom location related operations
        locationManager = (LocationManager) getActivity().getSystemService(
                Context.LOCATION_SERVICE);

        // Requesting locationmanager for location updates
        locationManager.requestLocationUpdates(
                LocationManager.NETWORK_PROVIDER, 1, 1, this);

        // To get map from MapFragment from layout
        googleMap = ((MapFragment) getActivity().getFragmentManager()
                .findFragmentById(R.id.map)).getMap();

        // To change the map type to Satellite
        // googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);

        // To show our current location in the map with dot
        // googleMap.setMyLocationEnabled(true);

        // To listen action whenever we click on the map
        googleMap.setOnMapClickListener(new OnMapClickListener() {

            @Override
            public void onMapClick(LatLng latLng) {
                /*
                 * LatLng:Class will give us selected position lattigude and
                 * longitude values
                 */
                Toast.makeText(getActivity(), latLng.toString(),
                        Toast.LENGTH_LONG).show();
            }
        });

        changeMapMode(3);

        // googleMap.setSatellite(true);
        googleMap.setTrafficEnabled(true);
        googleMap.setBuildingsEnabled(true);
        googleMap.setMyLocationEnabled(true);

        return v;
    }

    private void doZoom() {
        if (googleMap != null) {
            googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(
                    new LatLng(18.520430, 73.856744), 17));
        }
    }

    private void changeMapMode(int mapMode) {

        if (googleMap != null) {
            switch (mapMode) {
            case 0:
                googleMap.setMapType(GoogleMap.MAP_TYPE_NONE);
                break;

            case 1:
                googleMap.setMapType(GoogleMap.MAP_TYPE_NORMAL);
                break;

            case 2:
                googleMap.setMapType(GoogleMap.MAP_TYPE_SATELLITE);
                break;

            case 3:
                googleMap.setMapType(GoogleMap.MAP_TYPE_TERRAIN);
                break;

            case 4:
                googleMap.setMapType(GoogleMap.MAP_TYPE_HYBRID);
                break;

            default:
                break;
            }
        }
    }

    private void createMarker(double latitude, double longitude) {
        // double latitude = 17.385044;
        // double longitude = 78.486671;

        // lets place some 10 random markers
        for (int i = 0; i < 10; i++) {
            // random latitude and logitude
            double[] randomLocation = createRandLocation(latitude, longitude);

            // Adding a marker
            MarkerOptions marker = new MarkerOptions().position(
                    new LatLng(randomLocation[0], randomLocation[1])).title(
                    "Hello Maps " + i);

            Log.e("Random", "> " + randomLocation[0] + ", " + randomLocation[1]);

            // changing marker color
            if (i == 0)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_AZURE));
            if (i == 1)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_BLUE));
            if (i == 2)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_CYAN));
            if (i == 3)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_GREEN));
            if (i == 4)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_MAGENTA));
            if (i == 5)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_ORANGE));
            if (i == 6)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_RED));
            if (i == 7)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_ROSE));
            if (i == 8)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_VIOLET));
            if (i == 9)
                marker.icon(BitmapDescriptorFactory
                        .defaultMarker(BitmapDescriptorFactory.HUE_YELLOW));

            googleMap.addMarker(marker);

            // Move the camera to last position with a zoom level
            if (i == 9) {
                CameraPosition cameraPosition = new CameraPosition.Builder()
                        .target(new LatLng(randomLocation[0], randomLocation[1]))
                        .zoom(15).build();

                googleMap.animateCamera(CameraUpdateFactory
                        .newCameraPosition(cameraPosition));
            }
        }

    }

    /*
     * creating random postion around a location for testing purpose only
     */
    private double[] createRandLocation(double latitude, double longitude) {

        return new double[] { latitude + ((Math.random() - 0.5) / 500),
                longitude + ((Math.random() - 0.5) / 500),
                150 + ((Math.random() - 0.5) * 10) };
    }

    @Override
    public void onLocationChanged(Location location) {

        if (null != googleMap) {
            // To get lattitude value from location object
            double latti = location.getLatitude();
            // To get longitude value from location object
            double longi = location.getLongitude();

            // To hold lattitude and longitude values
            LatLng position = new LatLng(latti, longi);

            createMarker(latti, longi);

            // Creating object to pass our current location to the map
            MarkerOptions markerOptions = new MarkerOptions();
            // To store current location in the markeroptions object
            markerOptions.position(position);

            // Zooming to our current location with zoom level 17.0f
            googleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(position,
                    17f));

            // adding markeroptions class object to the map to show our current
            // location in the map with help of default marker
            googleMap.addMarker(markerOptions);
        }

    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderEnabled(String provider) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onProviderDisabled(String provider) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onDestroyView() {
        // TODO Auto-generated method stub
        super.onDestroyView();

        locationManager.removeUpdates(this);

        android.app.Fragment fragment = getActivity().getFragmentManager()
                .findFragmentById(R.id.map);
        if (null != fragment) {
            android.app.FragmentTransaction ft = getActivity()
                    .getFragmentManager().beginTransaction();
            ft.remove(fragment);
            ft.commit();
        }
    }


}

Мой Xml файл выглядит так: -

<?xml version="1.0" encoding="utf-8"?>
<fragment xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.MapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

Результат выглядит следующим образом: -

введите описание изображения здесь

Самое важное, что нужно отметить, что DO Not Mix app.Fragment с v4.Fragments else приложение сильно сработает.

Как вы можете видеть, я использовал app.Fragment для прикрепления и удаления фрагмента MapView

Надеюсь, что это поможет кому-то

Ответ 6

В вашем файле макета

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

В вашем фрагменте onCreate(), ссылка на фрагмент карты в файле макета фрагмента, используя childFragmentManager

// Obtain the SupportMapFragment and get notified when the map is ready to be used.
        val mapFragment: SupportMapFragment = childFragmentManager.findFragmentById(R.id.map) as SupportMapFragment
        // Set callback on the fragment
        mapFragment.getMapAsync(this)