如何找到java.lang.RuntimeException类型的崩溃源:Parcel android.os.Parcel@####:在偏移量YYY解组未知类型代码XXXX

问题描述 投票:6回答:3

我们的崩溃报告系统正在记录此类型的崩溃:

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时会发生这种情况。我们的应用程序是一个单活动应用程序,所有UI都由片段管理。这种崩溃很少发生,很难在我们的开发环境中重现。

另外 - 我不相信原因是我们创建的一些可分割的对象,而是Android组件重新加载,但不确定。

我想知道的是:如何分析这些堆栈跟踪以找出原因?如何利用给出的小数据?

请注意,堆栈跟踪几乎不指向我们应用程序中的任何特定行,以及它的作用 - 仅指向我们的活动的onCreate方法和片段基类

android parcelable
3个回答
3
投票

我刚学会了你可以让你的测试设备不能保持活动。 “开发者”选项的“应用程序”部分中有一个选项,在打开时,每次用户离开时都会销毁活动。

打开此选项后,我可以通过关闭并重新打开我的应用程序来重现错误。正如你所说,onCreate()方法中的错误。在我的例子中,当我从保存的实例状态解组自定义Parcelable时,原因是ClassNotFoundException。这可能不是您问题的解决方案,但至少可以帮助您重现并确定错误。快乐狩猎!


2
投票

根据我的经验,这样的错误不是关于错误发生时发生的事情,而是关于应用程序早期发生的事情的更多信息。特别是当应用程序进入后台时。

但从堆栈跟踪揭示的内容开始。 TopLevelFragment正在从以前的状态恢复。在此恢复期间,正在恢复TopLevelFragment的子片段。在恢复子片段时,当在Bundle上调用getSparseParcelableArray()以检索片段的已保存视图状态时,片段之一的已保存片段状态尝试取消自身。这发生在FragmentManager.java第1329行。有一些关于保存的片段状态,Parcel不知道该怎么做,因为它正在解组自己。

为了缩小你应该关注的TopLevelFragment的子片段,我会在FragmentManager.java的第1329行放置一个断点并检查片段f是什么。请记住,您可能会有多个子片段被恢复,因此您希望看到哪个片段无法通过第1329行。

但是当然你强迫这种恢复逻辑始终如一地发生。如果您只是将应用程序发送到后台并将其恢复到前台,则可能不会发生这种情况。所以你可以像Richard R建议的那样做,并使用“不要保持活动”开发人员选项来强制Android销毁和恢复活动。

一旦缩小了哪个片段是问题所在,您需要在应用程序的早期版本中进行回顾,并仔细查看您在Fragment.onSaveInstanceState()中进入保存状态的数据类型。希望这能指出你正确的方向。

如果这是一个程序问题,如果禁用缩小,您应该会看到错误消失。如果是这种情况,您可能需要在其中一个自定义Parcelable类型上使用proguard规则或@Keep注释。如果错误发生在有和没有缩小的情况下,它可能与proguard无关。


-1
投票

获得这种类型的堆栈跟踪,我们可以使用crashlytics或我们可以设置手动默认的异常处理程序

    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();
}
}
}
© www.soinside.com 2019 - 2024. All rights reserved.