Estoy tratando de mostrar un MapView dentro de un fragmento (el uso de la hackeado biblioteca de compatibilidad). El siguiente ha funcionado bien en el pasado:

  • fragmento del onCreateView() simplemente devuelve una nueva FrameLayout
  • fragmento del onActivityCreated() obtiene el MapView de la Actividad y la añade a su punto de vista de la jerarquía de
  • onDestroyView() quita el MapView desde su punto de vista de la jerarquía de

Ahora me gustaría que el fragmento de utilizar un diseño definido en xml para que yo pueda tener alguna otra interfaz de usuario de cosas. Poner el MapView elemento en el archivo de diseño siempre se bloquea, por lo que estoy haciendo de esta manera:

map_screen_fragment.xml

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


    <FrameLayout
        android:id="@+id/map_container"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent" >
    </FrameLayout>

</LinearLayout>

Mi MapScreenActivity contiene los MapView, y el fragmento de llamadas getMapView(), para no quedar en el «no se puede tener más de un MapView» tema:

MapScreenActivity.java

public class MapScreenActivity extends FragmentActivity {
    protected Fragment fragment;
    protected MapView mapView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.single_pane_empty);

        if (savedInstanceState == null) {
            fragment = new MapScreenFragment();

            getSupportFragmentManager().beginTransaction().add(R.id.root_container, fragment)
                    .commit();
        }
    }

    public MapView getMapView() {
        if (mapView == null) {
            mapView = new MapView(this, getResources().getString(R.string.maps_api_key));
        }

        return mapView;
    }
}

MapScreenFragment.java

public class MapScreenFragment extends Fragment {
    protected ViewGroup mapContainer;
    protected MapView mapView;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle args) {
        View root = inflater.inflate(R.layout.map_screen_fragment, container);
        mapContainer = (ViewGroup) root.findViewById(R.id.map_container);
        return root;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);

        mapView = ((MapScreenActivity) getActivity()).getMapView();
        mapView.setClickable(true);
        mapView.setBuiltInZoomControls(true);

        mapContainer.addView(mapView);

    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        mapContainer.removeView(mapView);
    }   

}

En teoría, esto debería todos funcionan de la misma manera como la new FrameLayout método descrito por primera vez. Sin embargo, me sale esto cada vez que:

02-24 18:01:28.139: E/AndroidRuntime(502): FATAL EXCEPTION: main
02-24 18:01:28.139: E/AndroidRuntime(502): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.mapfragment/com.example.mapfragment.MapScreenActivity}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.ActivityThread.access$1500(ActivityThread.java:117)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:931)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.os.Handler.dispatchMessage(Handler.java:99)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.os.Looper.loop(Looper.java:130)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.ActivityThread.main(ActivityThread.java:3683)
02-24 18:01:28.139: E/AndroidRuntime(502):  at java.lang.reflect.Method.invokeNative(Native Method)
02-24 18:01:28.139: E/AndroidRuntime(502):  at java.lang.reflect.Method.invoke(Method.java:507)
02-24 18:01:28.139: E/AndroidRuntime(502):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
02-24 18:01:28.139: E/AndroidRuntime(502):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
02-24 18:01:28.139: E/AndroidRuntime(502):  at dalvik.system.NativeStart.main(Native Method)
02-24 18:01:28.139: E/AndroidRuntime(502): Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.view.ViewGroup.addViewInner(ViewGroup.java:1976)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.view.ViewGroup.addView(ViewGroup.java:1871)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.view.ViewGroup.addView(ViewGroup.java:1828)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.view.ViewGroup.addView(ViewGroup.java:1808)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.support.v4.app.NoSaveStateFrameLayout.wrap(Unknown Source)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.support.v4.app.FragmentManagerImpl.moveToState(Unknown Source)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.support.v4.app.BackStackRecord.run(Unknown Source)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.support.v4.app.FragmentManagerImpl.execPendingActions(Unknown Source)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.support.v4.app.FragmentActivity.onStart(Unknown Source)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1129)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.Activity.performStart(Activity.java:3791)
02-24 18:01:28.139: E/AndroidRuntime(502):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1620)
02-24 18:01:28.139: E/AndroidRuntime(502):  ... 11 more

He probado la eliminación de la MapView de su padre antes de volver de getMapView(), y que todavía se bloquea. Yo realmente no entiendo por qué este enfoque no funciona, ningún tipo de ayuda sería apreciada.

OriginalEl autor Karakuri | 2012-02-25

4 Comentarios

  1. 15

    No estoy seguro de si este es el mismo problema que estaban teniendo, pero resulta que al inflar está bien, siempre y cuando no se adjunte a la raíz.

    Por ejemplo, usted necesita para hacer algo como esto:

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    return inflater.inflate(R.id.my_layout, container, false);
    }

    Si usted no puede añadir que el pasado false argumento de la inflate() llamada, entonces usted va a obtener la IllegalStateException.

    Creo que lo que está sucediendo es que sin el extra false argumento, su neumático de la vista de árbol se une a la raíz de la vista (container) y, a continuación, cuando la Actividad se inicia, el sistema intenta agregar en la vista de árbol para el root de nuevo. De ahí el error.

    Ha sido un tiempo desde que volví a ese proyecto, pero los fragmentos fueron bastante nuevo para mí en el tiempo, así que sospecho que esto es en realidad la respuesta correcta.
    Gracias por esto, no se dio cuenta de lo que estaba pasando hasta que mostró que el último argumento 🙂
    Buena idea, gracias por eso. 🙂

    OriginalEl autor Scott W

  2. 1

    Después de probar multitud de cosas, terminé haciendo esto:

    La raíz de vista he vuelto onCreateView() es creado mediante programación, no se infla. Sin embargo, al inflar otros puntos de vista y la adición de ellos como los niños a la programación-creado a raíz de vista no parece causar ningún tipo de problemas.

    Sombrero a nadie ahí fuera que puede averiguar lo que está detrás de este extraño comportamiento. Espero que esto puede ser útil a los demás.

    EDITAR

    Ha sido un tiempo desde que he revisado este tema, pero por lo que recuerdo, este no trabajo para mí…

    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
    return inflater.inflate(R.layout.some_layout, container, false);
    }

    … mientras que este sería trabajo para mí…

    private ViewGroup mapContainer;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
    mapContainer = new LinearLayout(getActivity());
    return mapContainer;
    }

    … y más tarde en onActivityCreated() me gustaría obtener un MapView de la actividad y agregarlo como un niño de mapContainer. Si quería otros puntos de vista (como tal vez un encabezado encima de la MapView), podría inflar ellos por separado y añadir a mapContainer, como este fragmento de código muestra.

    private ViewGroup mapContainer;
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saved) {
    mapContainer = new LinearLayout(getActivity());
    mapContainer.setOrientation(LinearLayout.VERTICAL);
    View headerView = inflater.inflate(R.layout.some_layout, mapContainer, false);
    mapContainer.addView(headerView);
    return mapContainer;
    }
    Podría publicar un ejemplo por favor?

    OriginalEl autor Karakuri

  3. 0

    Esto es lo que ha funcionado para mí…
    Cuando me cambié fragmentos hice

    if (mapContainer.getChildAt(0) != null){
    mapContainer.removeViewAt(0);
    }

    Yo no he puesto eso en mi onDestroy() o onPause() métodos. Yo hice eso cuando me cambié de los fragmentos. Por alguna razón mi fragmento no estaba llamando onPause().

    En mi onResume() método que yo hice

    mapContainer.addView(mapView);

    y todo lo que funciona para mí. No más IllegalStateExceptions.

    OriginalEl autor Kenny C

  4. 0

    [ACTUALIZACIÓN]
    Escribí una pequeña biblioteca, maceración todos estos LocalActivityManager juntos soluciones: https://github.com/coreform/android-tandemactivities

    [old post]
    Usted debe

    mapContainer.removeView(mapView);

    antes de

    mapContainer.addView(mapView);

    para evitar ese tipo de excepción.

    …como literalmente en la línea de antes.

    ACEPTAR, de seguimiento después de los comentarios:

    Intente esto:

    if(mapView.getParent() != null) {
    mapContainer.addView(mapView);
    }
    Lo he probado así y no funciona. Todavía da exactamente el mismo error.
    También he intentado variaciones en ((ViewGroup) mapView.getParent()).removeView(mapView), y nada de eso funciona bien.
    trate de averiguar lo que la madre de tu MapView ya está conectado. si su padre que la intención de añadir a la ya, luego se agrega de forma que usted podría manejar el caso con la lógica o de un try/catch declaración. Yo ue la solución que he publicado en los comentarios de este hilo: nextlevelandroid.com/?p=114 (comentarios por lindo) que funciona y lo que no requieren cada friggen FragmentActivity para extender MapActivity!
    por favor, comparta su código para entender fácilmente. He pasado por muchos puestos, pero no podía encontrar una solución fácil.
    hola voy a tratar de armar una casa, ejemplo genérico…pero por ahora estoy muy ocupado asistiendo a google IO! XD

    OriginalEl autor straya

Dejar respuesta

Please enter your comment!
Please enter your name here