【问题标题】:Exception loading data with CursorLoader after screen rotation屏幕旋转后使用 CursorLoader 加载数据时出现异常
【发布时间】:2012-08-30 11:28:08
【问题描述】:

我的应用程序在 Nexus 7 平板电脑上运行时遇到了一个奇怪的问题。 我有两个片段使用 CursorLoader 从我的自定义 ContentProvider 加载数据。

当我启动应用程序时,它在横向和纵向模式下都运行良好,加载程序正确加载数据。当我旋转屏幕时会出现问题:我的 Activity 和两个 Fragment 都已正确重新创建,并且加载程序再次启动,如预期的那样。他们加载数据(调试时我看到两个加载器都调用了 onLoadFinished)但之后应用程序是 FC,但有以下异常:

08-30 13:10:03.310: E/AndroidRuntime(14964): FATAL EXCEPTION: ModernAsyncTask #4
08-30 13:10:03.310: E/AndroidRuntime(14964): java.lang.RuntimeException: An error occured while executing doInBackground()
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.ModernAsyncTask$3.done(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.FutureTask.run(FutureTask.java:137)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.lang.Thread.run(Thread.java:856)
08-30 13:10:03.310: E/AndroidRuntime(14964): Caused by: java.lang.NullPointerException
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.content.ContentResolver.acquireUnstableProvider(ContentResolver.java:1094)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.content.ContentResolver.query(ContentResolver.java:354)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.content.ContentResolver.query(ContentResolver.java:313)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.CursorLoader.loadInBackground(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.CursorLoader.loadInBackground(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.AsyncTaskLoader.onLoadInBackground(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.AsyncTaskLoader$LoadTask.doInBackground(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at android.support.v4.content.ModernAsyncTask$2.call(Unknown Source)
08-30 13:10:03.310: E/AndroidRuntime(14964):    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
08-30 13:10:03.310: E/AndroidRuntime(14964):    ... 4 more

老实说,stacktrace 没有帮助,因为它不包含对我的代码的任何引用,而且这是一个非常奇怪的问题,因为如上所述,两个片段在我第一次启动应用程序时都可以正常工作,在手机布局,但屏幕旋转后我的平板电脑布局崩溃。

编辑:

在两个片段中,我在 onActivityCreated 方法中加载数据,只需调用 getLoaderManager.initLoader(....);

这就是我创建装载机的方式:

第一个片段

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    CursorLoader cursorLoader = new CursorLoader(getActivity(), MyContract.CONTENT_URI,
            null, null, null, null);

    return cursorLoader;
}

第二个片段:

@Override
public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    return new CursorLoader(getActivity(), MyContract.CONTENT_URI, null,
            null, null, null);
}

这是我CP的内容uri的声明:

//MyContract class
public static final Uri CONTENT_URI = Uri.parse("content://" + MyProvider.AUTHORITY + "/items");

//In MyProvider class
public static final String AUTHORITY = "it.rciovati.mypackage.MyProvider"

【问题讨论】:

  • 你能把代码贴在你正在加载光标的地方吗?看起来这与您正在使用的 uri 没有关联的方案有关
  • 这不是什么意思?我认为我的内容提供程序实现可能存在错误,但我不明白为什么我第一次启动应用程序时它会起作用。
  • 我的意思是崩溃。无论如何,我认为您传递给加载程序的 uri 在字符串中的任何位置都没有:(冒号)。这就是它崩溃的原因。打印您拥有的所有 uris 并检查
  • 我在上面写了我如何声明我的内容 uri。
  • 问题不在于 ContentProvider 中的 Content uri,而在于您正在加载 uri 的应用程序中。在您创建要加载的 uri 的位置发布代码

标签: android android-contentprovider android-loadermanager


【解决方案1】:

android.content.ContentResolver.acquireUnstableProvider() 中存在一个错误,该错误仅在 2013 年 11 月得到修复。该错误的详细信息可在此处查看:

https://bugzilla.mozilla.org/show_bug.cgi?id=904551

本质上,如果 Uri 为空,该函数将无法处理,并会导致崩溃。为了正确支持较旧的 Android 版本,您需要确保永远不会传入 null Uri,或者捕获抛出的 NPE。

【讨论】:

    【解决方案2】:

    我解决了。 在我的布局中,我有一个加载其他数据的第三个片段,并且对其进行了错误检查。

    【讨论】:

    • 您能详细说明一下吗?谢谢。
    • @MattWear 基本上是由于错误的检查,我将 null 传递给了 Uri 参数。
    【解决方案3】:

    我也有同样的问题。事实证明,这是一个非常容易消除的错误。基于我的代码的示例

            Uri content_uri = null;
    
            if (bundle != null && bundle.containsKey("ID_BUNDLE_KEY")) {
                int word_id_to_query = bundle.getInt(ID_BUNDLE_KEY, 1);
                content_uri = ContentUris.withAppendedId(WordListContentProvider.CONTENT_URI, word_id_to_query);
    
            }
    
            cursorLoader = new CursorLoader(getActivity()
                    .getApplicationContext(), content_uri,
                    projections, SELECTION, SELECTION_ARGS, null);
    

    我的错误是使用“ID_BUNDLE_KEY”而不是 ID_BUNDLE_KEY 作为参数。后者已经是最终的静态字符串变量。因此 bundle.containsKey 将始终返回 false。这导致 content_uri 的变量在传递给新的 CurorLoader 函数时包含“null”。我的建议是在您自己的代码中验证“空”uri 没有错误地传入。

    有关额外信息,Android 4.1.2 AOSP 代码中 ContentResolver.java 的第 1094 行确实是 [uri.getscheme() != "content"] 的条件返回 false,导致提供程序为空。运行时库抱怨的是这个 null 提供程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-04-07
      • 1970-01-01
      • 1970-01-01
      • 2011-07-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多