MapView all'interno del Frammento specificato il bambino ha già un genitore
-
12-11-2019 - |
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 nuovoFrameLayout
- 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.
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);
}