BadParcelableException в коде google maps
Запуск слегка измененного примера Google Maps выбрасывает BadParcelableException
в коде Google Maps. Класс LatLng
является простым, но его невозможно найти. Кажется, что код Google Maps пытается отделить объект, который не был разделен им. В каких случаях проблема?
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
Ответы
Ответ 1
Просто чтобы добавить к существующим ответам здесь, я удалил свои Parcels из сохраненного состояния перед вызовом mapView.onCreate
, и он работал нормально.
Однако после добавления ViewPager
в мой фрагмент я не понял, что BadParcelableException
вернулся, а код сделал это для производства. Оказывается, что ViewPager
также сохраняет свое состояние и, поскольку он является частью Библиотеки поддержки, Карта Google не может найти класс, чтобы отделить его.
Итак, я решил инвертировать процесс, вместо того, чтобы удалять Parcels из Bundle, о котором я знал, я решил создать новый Bundle для копирования карты только из состояния карты.
private final static String BUNDLE_KEY_MAP_STATE = "mapData";
@Override
public void onSaveInstanceState(Bundle outState) {
// Save the map state to it 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;
}
Ответ 2
Я пробовал два предыдущих ответа без успеха, но нашел другое обходное решение:
При сохранении состояния будьте осторожны, чтобы переслать вызов MapView.onSaveInstanceState перед добавлением данных в Bundle (вы сделали это хорошо):
@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) );
}
При восстановлении состояния в onCreate/onRestore проверьте, не расслоен ли пакет, если да, получите вашу посылку, а затем удалите ее из пакета перед пересылкой вызова:
@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();
}
Ответ 3
Эта проблема была отправлена на code.google.com здесь в случае, если вы хотите ее запустить.
В то же время мне удалось обойти эту проблему, просто добавив свой Parcelable в Bundle, прежде чем добавлять его в финальный пакет onSaveInstanceState. Это работает, потому что Bundle является известным классом встроенным ClassLoader MapView.
Я создал два очень маленьких метода использования, чтобы сделать это для меня. Здесь код
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);
}
Я изменил код в одном из предыдущих сообщений, чтобы использовать мое временное решение. Вот как я его использую.
@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();
}
Это должно работать на любой пользовательский Parcelable, который вы используете в своем проекте.
Ответ 4
Я нашел обходное решение (kinda). В том месте, где это происходит, просто попробуйте сделать это во второй раз. Он всегда ловит Исключение, и во второй раз проблема, похоже, не происходит в этом месте. Это сработало для меня.
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()));
}
Ответ 5
Я нашел более простое обходное решение. Предоставление загрузчика Fragment или Activity класса перед выполнением любых операций как таковых:
savedInstanceState.setClassLoader(getClass().getClassLoader());
Это не работает при передаче непосредственно в MapFragment или MapView onCreateView или onCreate, поэтому вам придется вручную выставить карту CameraPosition и передать нулевой пакет в эти функции.
Ответ 6
У меня также было исключение BadParcelableException, когда я покидал свое приложение (FragmentActivity с вкладками и фрагментом на каждой вкладке). Я решил это, позвонив сначала mapmpvMap.onSaveInstanceState(outState);
, а затем super.onSaveInstanceState(outState);