2012-12-16 3 views
14

L'esecuzione di un esempio leggermente modificato di Google Maps genera BadParcelableException nel codice di Google Maps. La classe LatLng è parcelable ma non può essere trovata. Sembra che il codice di Google Maps stia cercando di non trovare l'oggetto che non è stato parcellizzato da esso. In quali casi il problema?BadParcelableException in google maps code

package com.example.mapdemo; 

import com.google.android.gms.maps.GoogleMap; 
import com.google.android.gms.maps.MapView; 
import com.google.android.gms.maps.model.LatLng; 
import com.google.android.gms.maps.model.MarkerOptions; 

import android.os.Bundle; 

public class RawMapViewDemoActivity extends android.support.v4.app.FragmentActivity { 
    private MapView mMapView; 

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

     mMapView = (MapView) findViewById(R.id.map); 
     mMapView.onCreate(savedInstanceState); 
    } 

    @Override 
    public void onSaveInstanceState(Bundle outState) { 
     super.onSaveInstanceState(outState); 
     mMapView.onSaveInstanceState(outState); 

     outState.putParcelable("marker", new LatLng(0, 0)); 
    } 

    @Override 
    protected void onRestoreInstanceState(Bundle savedInstanceState) { 
     super.onRestoreInstanceState(savedInstanceState); 

     LatLng ll = savedInstanceState.getParcelable("marker"); 
    } 
} 

...

FATAL EXCEPTION: main 
java.lang.RuntimeException: Unable to start activity 
    ComponentInfo{com.example.mapdemo/com.example.mapdemo.RawMapViewDemoActivity}: 
    android.os.BadParcelableException: ClassNotFoundException when unmarshalling: 
    com.google.android.gms.maps.model.LatLng 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1647) 
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1663) 
    at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:2832) 
    at android.app.ActivityThread.access$1600(ActivityThread.java:117) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:935) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:130) 
    at android.app.ActivityThread.main(ActivityThread.java:3683) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:507) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597) 
    at dalvik.system.NativeStart.main(Native Method) 

Caused by: android.os.BadParcelableException: 
ClassNotFoundException when unmarshalling: com.google.android.gms.maps.model.LatLng 
    at android.os.Parcel.readParcelable(Parcel.java:1958) 
    at android.os.Parcel.readValue(Parcel.java:1846) 
    at android.os.Parcel.readMapInternal(Parcel.java:2083) 
    at android.os.Bundle.unparcel(Bundle.java:208) 
    at android.os.Bundle.getBundle(Bundle.java:1078) 
    at com.google.android.gms.maps.internal.MapStateHelper 
     .getParcelableFromMapStateBundle(MapStateHelper.java:41) 
    at maps.y.ae.a(Unknown Source) 
    at maps.y.bm.onCreate(Unknown Source) 
    at com.google.android.gms.maps.internal.IMapViewDelegate$Stub 
     .onTransact(IMapViewDelegate.java:66) 
    at android.os.Binder.transact(Binder.java:279) 
    at com.google.android.gms.maps.internal.IMapViewDelegate$a$a 
     .onCreate(Unknown Source) 
    at com.google.android.gms.maps.MapView$b.onCreate(Unknown Source) 
    at com.google.android.gms.internal.c$3.a(Unknown Source) 
    at com.google.android.gms.internal.i.b(Unknown Source) 
    at com.google.android.gms.maps.MapView$a.a(Unknown Source) 
    at com.google.android.gms.maps.MapView$a.a(Unknown Source) 
    at com.google.android.gms.internal.c.a(Unknown Source) 
    at com.google.android.gms.internal.c.onCreate(Unknown Source) 
    at com.google.android.gms.maps.MapView.onCreate(Unknown Source) 
    at com.example.mapdemo.RawMapViewDemoActivity 
     .onCreate(RawMapViewDemoActivity.java:40) 
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047) 
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611) 
    ... 12 more 
+0

dove è la linea RawMapViewDemoActivity.java:40 nel codice –

+0

mMapView.onCreate (savedInstanceState); Mi dispiace, ho modificato il codice per brevità. – user1611728

+0

se si commenta 'mMapView.onCreate (savedInstanceState);' linea allora funziona o no? –

risposta

0

ho trovato una soluzione (un pò). Nel luogo in cui accade, prova a farlo per la seconda volta. Ottiene sempre l'eccezione e la seconda volta il problema non sembra avvenire in questo luogo. Questo ha funzionato per me.

try { 
    mapIntent.putExtra(Intents.EXTRA_LATLNG, new LatLng(
     store.getLatitude(), store.getLongitude())); 
} catch (BadParcelableException e) { 
    mapIntent.putExtra(Intents.EXTRA_LATLNG, new LatLng(
     store.getLatitude(), store.getLongitude())); 
} 
0

Ho trovato una soluzione più semplice a questo. Fornendo il vostro frammento o class loader di attività per il pacchetto prima che perfoming qualsiasi operazione in quanto tale:

savedInstanceState.setClassLoader(getClass().getClassLoader()); 

Questo non sembra funzionare quando passa direttamente nella MapFragment o onCreateView di MapView o onCreate però, quindi dovrete manualmente pacchi fuori CameraPosition della mappa e passa un fascio nullo in quelle funzioni.

+0

Hai un esempio della soluzione che hai descritto? – speedynomads

12

Ho provato le due risposte precedenti senza successo, ma ho trovato un'altra soluzione:

Quando si salva lo Stato, fare attenzione a inoltrare la chiamata MapView.onSaveInstanceState prima di aggiungere i vostri dati per il Bundle (avete fatto bene) :

@Override 
public void onSaveInstanceState(Bundle outState) { 

    // Forward the call BEFORE adding our LatLng array, else it will crash : 
    _mapView.onSaveInstanceState(outState); 

    // Put your Parcelable in the bundle: 
    outState.putParcelableArray("myLatLng", new LatLng(0, 0)); 
} 

Quando si ripristina lo stato in onCreate/OnRestore, controllare se il pacchetto non è nullo, in tal caso, ottenere il vostro pacchetto, e quindi rimuoverlo dal bundle prima di inoltrare la chiamata:

@Override 
public void onCreate(Bundle savedInstanceState) { 

    // If the bundle is not null, get your Parcelable : 
    LatLng myLatLng = null; 
    if(savedInstanceState != null) { 

     myLatLng = (LatLng) savedInstanceState.getParcelable("myLatLng"); 

     // Remove your Parcelable from the bundle, else it will crash : 
     savedInstanceState.remove("myLatLng"); 
    } 

    // Forward the call : 
    _mapView.onCreate(savedInstanceState); 
    setUpMapIfNeeded(); 
} 
+0

Questa correzione funziona per me! grazie – Sulfkain

+0

Mi hai salvato la vita! :) – IlyaEremin

0

Ho anche ricevuto una badParcelableException mentre lasciavo la mia app (FragmentActivity con schede e un frammento in ogni scheda). Ho risolto questo problema chiamando il primo mapmpvMap.onSaveInstanceState(outState); e poi super.onSaveInstanceState(outState);

3

Questo problema è stato archiviato su code.google.com here nel caso in cui si desideri eseguirlo.

Nel frattempo sono riuscito a risolvere questo problema aggiungendo semplicemente il mio Parcelable a un pacchetto prima di aggiungerlo al pacchetto finale di OnSaveInstanceState. Questo funziona perché un pacchetto è una classe nota dal ClassLoader interno di MapView.

Ho creato due metodi utilissimi per farlo. Ecco il codice

public static Parcelable unbundleParcelable(String key, Bundle src) { 
    Bundle b = src.getBundle(key); 
    if (b != null) { 
     return b.getParcelable("bundle_parcelable_util_key"); 
    } 
    return null; 
} 

public static void bundleParcelable(String key, Bundle dest, Parcelable parcelable) { 
    Bundle b = new Bundle(); 
    b.putParcelable("bundle_parcelable_util_key", parcelable); 
    dest.putBundle(key, b); 
} 

Ho modificato il codice in uno dei post precedenti per utilizzare la mia soluzione temporanea. Ecco come lo uso.

@Override 
public void onSaveInstanceState(Bundle outState) { 

    // Forward the call BEFORE adding our LatLng array, else it will crash : 
    _mapView.onSaveInstanceState(outState); 

    // Put your Parcelable in the bundle: 
    bundleParcelable("myLatLng", outState, new LatLng(0, 0)); 
} 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    // Forward the call : 
    _mapView.onCreate(savedInstanceState); 

    LatLng myLatLng = null; 
    if(savedInstanceState != null) { 
     // Extract your Parcelable 
     myLatLng = (LatLng) unbundleParcelable("myLatLng", savedInstanceState); 
    } 

    setUpMapIfNeeded(); 
} 

Questo dovrebbe funzionare per qualsiasi Parcelable personalizzato che si utilizza nel progetto.

+0

Perfetto, la tua risposta ha funzionato. –

+0

Beh, sono contento che il codice sia stato utile a qualcuno. Saluti! –

31

Giusto per aggiungere alle risposte esistenti qui, avevo rimosso i miei Parcel dallo stato salvato prima di chiamare mapView.onCreate e funzionava correttamente.

Tuttavia dopo aver aggiunto uno ViewPager al mio frammento non mi ero reso conto che il BadParcelableException era stato restituito e il codice lo ha reso in produzione. Si scopre che lo ViewPager salva anche il suo stato e, poiché fa parte della libreria di supporto, la mappa di Google non riesce a trovare la classe in cui non può essere selezionata.

Così ho deciso di invertire la procedura, invece di rimuovere Parcels dal pacchetto che conoscevo, ho optato per creare un nuovo pacchetto per la mappa che copi solo lo stato della mappa.

private final static String BUNDLE_KEY_MAP_STATE = "mapData"; 

@Override 
public void onSaveInstanceState(Bundle outState) { 
    // Save the map state to it's own bundle 
    Bundle mapState = new Bundle(); 
    mapView.onSaveInstanceState(mapState); 
    // Put the map bundle in the main outState 
    outState.putBundle(BUNDLE_KEY_MAP_STATE, mapState); 
    super.onSaveInstanceState(outState); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.fragment_map, container, false); 
    mapView = (MapView) view.findViewById(R.id.mapView); 
    mapView.getMapAsync(this); 

    Bundle mapState = null; 
    if (savedInstanceState != null) { 
     // Load the map state bundle from the main savedInstanceState 
     mapState = savedInstanceState.getBundle(BUNDLE_KEY_MAP_STATE); 
    } 

    mapView.onCreate(mapState); 
    return view; 
} 
+0

Sembra esserci una discussione in corso su questo a: https://code.google.com/p/gmaps-api-issues/issues/detail?id=6237#c9 Questa è una risposta ragionevole e ha funzionato bene per me –

+0

Grazie mille! Ha funzionato perfettamente !! –