Как найти источник сбоев типа java.lang.RuntimeException: Parcel android.os.Parcel@####: Отмена указания неизвестного кода типа XXXX со смещением YYY - PullRequest
6 голосов
/ 14 марта 2019

Наша система отчетов о сбоях регистрирует сбои этого типа:

Caused by java.lang.RuntimeException: Parcel android.os.Parcel@8bf0d1f: Unmarshalling unknown type code 6881391 at offset 356
   at android.os.Parcel.readValue(Parcel.java:2779)
   at android.os.Parcel.readSparseArrayInternal(Parcel.java:3148)
   at android.os.Parcel.readSparseArray(Parcel.java:2362)
   at android.os.Parcel.readValue(Parcel.java:2757)
   at android.os.Parcel.readArrayMapInternal(Parcel.java:3067)
   at android.os.BaseBundle.unparcel(BaseBundle.java:257)
   at android.os.Bundle.getSparseParcelableArray(Bundle.java:958)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1329)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:3194)
   at android.support.v4.app.Fragment.restoreChildFragmentState(Fragment.java:1444)
   at android.support.v4.app.Fragment.onCreate(Fragment.java:1415)
   at com.payments.base.BaseFragment.onCreate(BaseFragment.java:68)
   at com.payments.app.fragments.TopLevelFragment.onCreate(TopLevelFragment.java:422)
   at android.support.v4.app.Fragment.performCreate(Fragment.java:2331)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1386)
   at android.support.v4.app.FragmentManagerImpl.moveFragmentToExpectedState(FragmentManager.java:1759)
   at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1827)
   at android.support.v4.app.FragmentManagerImpl.dispatchStateChange(FragmentManager.java:3244)
   at android.support.v4.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:3194)
   at android.support.v4.app.Fragment.restoreChildFragmentState(Fragment.java:1444)
   at android.support.v4.app.Fragment.onCreate(Fragment.java:1415)

Что я знаю: это происходит, когда приложение восстанавливается из фона и вызывается onCreate.Наше приложение представляет собой приложение Single-Activity со всем пользовательским интерфейсом, управляемым фрагментами.Это аварийное завершение нечасто , и его очень трудно воспроизвести в нашей среде разработки.

Кроме того, я не верю, что причина в том, что мы создали какой-то пакетный объект, скорее перезагрузка компонента Android, но неконечно.

Что я хотел бы знать: как анализировать эти трассировки стека, чтобы точно определить причину? как использовать предоставленные небольшие данные?

Обратите внимание, что трассировка стека едва ли указывает на какую-либо конкретную строку в нашем приложении, а где она делает - только на методы onCreate нашей деятельности и фрагментирует базовые классы

Ответы [ 3 ]

3 голосов
/ 20 апреля 2019

Я только что узнал, что вы можете помешать своему тестовому устройству сохранять активность. В разделе «Приложения» есть опция «Приложения», которая при включении уничтожает действия каждый раз, когда пользователь покидает их.

После включения этой опции я смог воспроизвести ошибку, просто закрыв и снова открыв свое приложение. Как вы сказали, это ошибка в методе onCreate (). В моем случае причина в ClassNotFoundException при отмене вызова настраиваемого Parcelable из моего сохраненного состояния экземпляра. Возможно, это не решение вашей проблемы, но, по крайней мере, может помочь вам воспроизвести и зафиксировать ошибку. Удачной охоты!

2 голосов
/ 21 апреля 2019

По моему опыту, такая ошибка связана не столько с тем, что происходит при возникновении ошибки, сколько с тем, что происходило ранее в вашем приложении. В частности, когда приложение ушло в фоновый режим.

Но начиная с того, что показывает трассировка стека. TopLevelFragment восстанавливается из предыдущего состояния. Во время этого восстановления дочерние фрагменты TopLevelFragment восстанавливаются. При восстановлении дочерних фрагментов состояние сохраненного фрагмента одной из попыток фрагмента разархивировать себя, когда getSparseParcelableArray () вызывается в Bundle для получения сохраненного состояния просмотра фрагмента. Это происходит в FragmentManager.java, строка 1329. Что-то в состоянии сохраненного фрагмента, что Parcel не знает, что делать, так как он сам не выполняет маршалинг.

Чтобы сузить, на каком дочернем фрагменте TopLevelFragment вы должны сосредоточиться, я бы поставил точку останова в строке 1329 FragmentManager.java и проверил, что это за тип Fragment f. Имейте в виду, что у вас может быть несколько дочерних фрагментов, которые будут восстановлены, поэтому вы хотите увидеть, какой фрагмент не может пройти после строки 1329.

Но, конечно, у вас есть сила, чтобы эта логика восстановления происходила последовательно. Если вы просто отправите свое приложение в фоновый режим и вернете его на передний план, этого, вероятно, не произойдет. Таким образом, вы можете сделать так, как предлагает Ричард Р., и использовать опцию разработчика «Не сохранять действия», чтобы заставить Android уничтожать и восстанавливать действия.

Как только вы определите, какой фрагмент является проблемой, вам нужно вернуться в свое приложение раньше и более внимательно посмотреть на типы данных, которые вы переводите в состояние сохранения в Fragment.onSaveInstanceState (). Надеюсь, это указывает на правильное направление.

Если это проблема proguard, вы должны увидеть, как ошибка исчезла, если вы отключите минификацию. И если это так, вам может понадобиться правило proguard или аннотация @Keep для одного из ваших пользовательских типов Parcelable. Если ошибка происходит с минификацией и без нее, возможно, она не связана с proguard.

0 голосов
/ 22 апреля 2019

Получая этот тип трассировки стека, мы можем использовать краш-тесты или установить вручную обработчик исключений по умолчанию

    public class BaseActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    if (!(Thread.getDefaultUncaughtExceptionHandler() instanceof CustomExceptionHandler)) {
    String path = Environment.getExternalStorageDirectory()
    + "/" + getString(R.string.app_name);
    Thread.setDefaultUncaughtExceptionHandler(new
    CustomExceptionHandler(path, ""));
    }
    }

Для сохранения журнала в пути к файлу ...

public class CustomExceptionHandler implements       UncaughtExceptionHandler {
private UncaughtExceptionHandler defaultUEH;
private String dirName;
private String url;

/*
* if any of the parameters is null, the respective functionality
* will not be used
*/           
public CustomExceptionHandler(String dirName, String url) {
this.dirName = dirName;
this.url = url;
this.defaultUEH = Thread.getDefaultUncaughtExceptionHandler();
}

public void uncaughtException(Thread t, Throwable e) {
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
String stacktrace = result.toString();
printWriter.close();           
if (dirName != null) {
writeToFile(stacktrace);
}
defaultUEH.uncaughtException(t, e);
}          
private void writeToFile(String stacktrace) {
try {
File myDir = new File(dirName.replace(" ", "") + "_Log");
if (!myDir.exists()) {
myDir.mkdir();
}
//Store only 10 file in device because of size.
if (myDir != null & myDir.isDirectory() & myDir.listFiles().length > 10) {
File[] filelist = myDir.listFiles();
for (int i = 0; i < filelist.length; i++) {
try {
filelist[i].delete();
} catch (Exception e) {}
}
}
Calendar c = Calendar.getInstance();                       c.setTimeInMillis(System.currentTimeMillis());
String fileName = "";
fileName = c.get(Calendar.SECOND) + "-" +
c.get(Calendar.MINUTE) + "-" +
c.get(Calendar.HOUR) + "-" +
(c.get(Calendar.AM) == 0 ? "AM" : "PM") + "_" +
c.get(Calendar.DAY_OF_MONTH) + "-" +
(c.get(Calendar.MONTH) + 1) + "-" +
c.get(Calendar.YEAR) + ".txt";
File f = new File(myDir, fileName);
FileWriter fr = new FileWriter(f);
BufferedWriter bos = new BufferedWriter(fr);
bos.write(stacktrace);
bos.flush();
bos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
...