Proguard вызывает RuntimeException (Unmarshalling неизвестный тип кода) в классе Parcelable
Я получаю это исключение, если оставляю свое приложение и открываю его через некоторое время. Моя основная деятельность состоит из ViewPager с тремя различными фрагментами. Я также делаю некоторые вещи в классе приложений, которые, как я думаю, не связаны с проблемой.
Это исключение:
RuntimeException (@Parcel: readValue: 2065) {Невозможно начать работу ComponentInfo {com.emu/com.emu.ActivityMain}: java.lang.RuntimeException: Parcel [email protected]: Unmarshalling неизвестный код типа 2131361816 при смещении 332}
Я вижу, что это исключение происходит на телефонах пользователей в Google Analytics. Все они одинаковы, кроме числа после readValue и шестнадцатеричного числа после @, которые составляют 2065 и 419526d0 в вышеописанном исключении.
Исключением не указывается какая-либо строка кода. Я искал об этом, и, похоже, это связано с неправильным написанием посылки. Хотя у меня нет никакой посылки в моей MainActivity. Я не знаю, что может это сделать.
--- ИЗМЕНИТЬ ------------------------------------------- -----------------------------
Я воспроизвел исключение. Это происходит, когда приложение выложено с помощью кнопки "домой" и очищается от памяти после открытия другого приложения, использующего всю память. При запуске снова происходит исключение. До сих пор я думал, что закрытие приложения из недавней задачи или из DDMS имеет тот же эффект, но, по-видимому, это не так.
@EricWoodruf помог мне найти этот пакет где-то в импортированной библиотеке. Я нахожу посылку в PagerSlidingTabStrip, которую я загрузил из Интернета. Это код, связанный с посылкой, но я действительно не знаю, что здесь не так:
public class PagerSlidingTabStrip extends HorizontalScrollView
{
@Override
public void onRestoreInstanceState(Parcelable state)
{
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());
currentPosition = savedState.currentPosition;
requestLayout();
}
@Override
public Parcelable onSaveInstanceState()
{
Parcelable superState = super.onSaveInstanceState();
SavedState savedState = new SavedState(superState);
savedState.currentPosition = currentPosition;
return savedState;
}
static class SavedState extends BaseSavedState
{
int currentPosition;
public SavedState(Parcelable superState)
{
super(superState);
}
private SavedState(Parcel in)
{
super(in);
currentPosition = in.readInt();
}
@Override
public void writeToParcel(Parcel parcel, int flags)
{
super.writeToParcel(parcel, flags);
parcel.writeInt(currentPosition);
}
public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>()
{
@Override
public SavedState createFromParcel(Parcel in)
{
return new SavedState(in);
}
@Override
public SavedState[] newArray(int size)
{
return new SavedState[size];
}
};
}
}
---- ИЗМЕНИТЬ 2 ----------------------------------------- ------------------------
После того, как я смог воспроизвести проблему, я узнал, что это происходит только в Artifact, подписанном моим ключом и предостерегаемым! Проблема с отладкой не вызывает проблем!
Я отключил proguard на артефакте, и он работает как шарм без исключения. Но, что такое proguard, что приводит к этой проблеме?
Я попытался добавить это в proguard, но не работал:
-keep class toolfa.android.base.ui.PagerSlidingTabStrip { *; }
-dontwarn toolfa.android.base.ui.PagerSlidingTabStrip
это моя текущая конфигурация proguard:
-keep class com.nineoldandroids.** { *; }
-dontwarn com.nineoldandroids.**
-keep class ir.adad.** { *; }
-dontwarn ir.adad.**
-keep class android.support.v4.** { *; }
-dontwarn android.support.v4.**
-keep class toolfa.android.base.ui.PagerSlidingTabStrip { *; }
-dontwarn toolfa.android.base.ui.PagerSlidingTabStrip
-keep class toolfa.android.sega.ActivityEmulator { *; }
-keep class toolfa.android.sega.Zip { *; }
Ответы
Ответ 1
Как мы выяснили в комментариях, исключение было результатом ProGuard obfuscating Parcelable classes. Исправление состоит в том, чтобы включить этот фрагмент в файл конфигурации ProGuard:
-keepclassmembers class * implements android.os.Parcelable {
static ** CREATOR;
}
Я предполагаю, что конкретная проблема здесь заключалась в том, что ProGuard обфускал член CREATOR
PagerSlidingTabStrip
, но поскольку SavedState
является подклассом View.BaseSavedState
, член суперкласса все еще был доступен (поэтому он не выбрал BadParcelableException
), но использует другую структуру данных и не писал пользовательские атрибуты в выход Parcel
.
Существует рекомендуемая конфигурация для приложений Android, доступных в Руководстве ProGuard, с подробным объяснением записей. Например, он включает в себя, что вы должны хранить все имена классов, используемые в манифесте или других файлах XML.
Ответ 2
Думаю, я знаю, почему это происходит. Я не уверен в этом, поэтому я могу ошибаться.
Итак, в моем случае я также использую viewpager в своем приложении для отображения некоторых данных базы данных (используя курсор). Теперь, если я покину приложение в фоновом режиме и возобновляю его через долгое время (несколько часов), Android решает убить мое приложение. После возобновления приложения он восстанавливает мою активность. Однако базовые данные, установленные в моем адаптере, не восстанавливаются.
Чтобы решить эту проблему, я запрашиваю данные в onResume()
IF getCount()
возвращает 0.
На твоей стороне я думаю, что то же самое происходит и с твоим приложением. Попробуйте поместить журнал в свой onResume и посмотреть, действительно ли это так?