Domanda

Sto cercando di mostrare una MapView all'interno di un frammento (utilizzando la hacked libreria di compatibilità).Il seguito ha lavorato bene in passato:

  • frammento onCreateView() restituisce semplicemente un nuovo FrameLayout
  • frammento onActivityCreated() ottiene la MapView dall'Attività e aggiunge che a suo avviso la gerarchia
  • onDestroyView() rimuove la MapView dalla sua vista gerarchia

Ora vorrei che il frammento di utilizzare un layout definiti in xml in modo che io possa avere qualche altra UI roba.Mettere il MapView elemento nel file di layout, si blocca sempre, quindi lo faccio in questo modo:

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>

Il mio MapScreenActivity detiene l'attuale MapView, e il frammento di chiamate getMapView(), così non corro il "non può avere più di una MapView" problema:

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

}

In teoria, questo dovrebbe tutte funzionano allo stesso modo come il new FrameLayout il metodo descritto per la prima volta.Tuttavia, ottenere questo ogni volta:

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

Ho tentato di rimuovere il MapView dal padre prima di tornare da getMapView(), e che si blocca ancora.Io davvero non capisco perché questo approccio non funziona, qualsiasi aiuto sarebbe apprezzato.

È stato utile?

Soluzione

Non sono sicuro se questo è lo stesso problema si era verificato, ma si scopre che il gonfiaggio è ok, finché non allegare alla radice.

Per esempio, avete bisogno di fare qualcosa di simile a questo:

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

Se non si riesce ad aggiungere che lo scorso false argomento inflate() chiamata, allora si otterrà il IllegalStateException.

Penso che quello che sta accadendo è che senza l'extra false argomento, il tuo gonfiato vista ad albero è collegato il root view (container) e poi, quando l'Attività è iniziata, il sistema tenta di aggiungere la vista ad albero per il root di nuovo.Quindi l'errore.

Altri suggerimenti

Dopo aver provato una moltitudine di cose, ho finito di fare questo:

La radice di vista sono tornato in onCreateView() creato a livello di programmazione, non si gonfia.Tuttavia, gonfiaggio altre viste e l'aggiunta di loro come bambini a livello di programmazione creato radice vista non sembra causare alcun problema.

Di cappello per qualcuno là fuori che può capire cosa c'è dietro questo strano comportamento.Speriamo che questo possa essere utile ad altri.

MODIFICA

E ' stato un po da quando ho rivisitato questo argomento, ma mi sembra di ricordare, questo non il lavoro per me...

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

...considerando che questo sarebbe il lavoro per me...

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

...e poi in onActivityCreated() Mi piacerebbe avere una MapView dall'attività e aggiungerlo come un bambino di mapContainer.Se volevo altre opinioni (come forse un'intestazione sopra la MapView), Ho potuto gonfiare separatamente e aggiungerli al mapContainer, come questo frammento di codice mostra.

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

Questo è ciò che ha funzionato per me...Ogni volta che ho acceso frammenti che ho fatto

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

Non ho messo nel mio onDestroy() o onPause() metodi.L'ho fatto ogni volta che ho acceso frammenti.Per qualche motivo il mio frammento non era chiamata onPause().

Nel mio onResume() metodo che ho fatto

mapContainer.addView(mapView);

e tutto funziona per me.Non più IllegalStateExceptions.

[AGGIORNAMENTO] Ho scritto una piccola biblioteca, schiacciando tutti questi LocalActivityManager insieme delle soluzioni: https://github.com/coreform/android-tandemactivities

[vecchio post] Si dovrebbe

mapContainer.removeView(mapView);

prima di

mapContainer.addView(mapView);

per evitare una tale eccezione.

...come letteralmente la linea prima.

OK, follow-up dopo i commenti:

Prova questo:

if(mapView.getParent() != null) {
    mapContainer.addView(mapView);
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top