【问题标题】:IllegalStateException when restarting Loader (SQLite) from an AsyncTask inside of a Fragment从 Fragment 内的 AsyncTask 重新启动 Loader (SQLite) 时出现 IllegalStateException
【发布时间】:2014-03-28 01:02:20
【问题描述】:

我注意到我的分析报告中有一些 IllegalStateException 崩溃,我似乎无法重现。我在这里做一些结构上不正确的事情吗?我已经包含了一些伪代码,希望可以显示我的片段的骨架而不会太杂乱。在我重构代码以使用片段之前,我不记得看到过这个错误。错误发生在 AsyncTask 的onPostExecute 中。如果我能更好地澄清我的问题/伪代码,请告诉我。

public class MyListFragment extends ListFragment 
    implements LoaderManager.LoaderCallbacks<Cursor> {

    Fragment fragment = this;
    SimpleCursorAdapter adapter;

    // onActivityCreated initializes the adapter and the loader

    public AsyncTaskLoader<Cursor> onCreateloader(int id, Bundle bundle) {
        return new CustomCursorLoader(this);
    }

    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
        adapter.swapCursor(data);
    }

    public void onLoaderReset(Loader<Cursor> loader) {
        adapter.swapCursor(null);
    }

    private class CustomCursorLoader extends CursorLoader {
        public CustomCursorLoader(Fragment fragment) {
            // get a handle to the OrmLite database helper class
            databaseHelper = (DatabaseHelper) OpenHelperManager.getHelper(fragment.getActivity(), DatabaseHelper.class);
        }

        public Cursor loadInBackground() {
            // construct the Cursor that will be used for loading results from the SQLite database
        }
    }

    private class Task extends AsyncTask {
        // pre execute

        // grab some new database results from the server and repopulate the SQLite database using OrmLite

        public void onPostExecute() {
            fragment.getLoaderManager().restartLoader(LOADER_ID, null, fragment);
        }
    }
}

更新

我能够通过启动Task 然后立即回击来重现该问题。当Task 完成时,包含该片段的活动未处于活动状态,因此对getLoaderManager 的调用失败。现在的问题是,处理这个问题的最优雅的方法是什么?我想我可以抓住异常。

更新 2

我相信我可以利用cancel 来阻止onPostExecute 执行。如果我这样做,我可能需要将 initLoader 移动到 onActivityCreated 以外的其他方法,以便在用户返回页面时刷新加载器(因为更新了结果,而不是加载器)。

更新 3

我想知道,就像 Robby Pond 在 cmets 中提到的那样,在这里使用 Loader 是否过大?

【问题讨论】:

  • 请发布 logcat 输出(stacktrace)以获取更多信息
  • @stan0 我希望我可以。我在分析中使用EasyTracker,所以我得到的只是异常名称和行号。我似乎无法在本地重现该问题。
  • 你什么时候创建和执行任务?
  • @RobbyPond 如果数据库中当前没有结果,则在onActivityCreated 中。否则,在onOptionsItemSelected 时点击刷新操作栏项。
  • 我不认为我们也可以用代码量。为什么要同时使用 Loader 和 AsyncTask 来查询数据库?

标签: android android-fragments android-asynctask ormlite android-loadermanager


【解决方案1】:

我对您的案例的一些想法:

  1. Loader 存在各种问题,尤其是与片段一起使用时。我可以建议您使用 ViewModel,但我认为它们都基于相同的代码。您可以使用普通线程,然后使用 EventBus 之类的东西来发布结果,但这可能有点过头了

  2. 我可以看到您忘记将类设置为静态,这意味着它们具有对托管类的引用。

  3. 是否可以将异步代码合并到一个 AsyncTaskLoader 中?

  4. 您可以尝试我使用 AsyncTaskLoader 的一般解决方案,here

  5. 也许不是重新启动,而是先销毁,然后再次调用 initLoader。

  6. AsyncTask 只应在小情况下使用,在这种情况下您不关心结果是否消失(例如,当您改变方向时)。一个很好的例子是要显示的项目列表。

  7. 我认为 Google 在 Google IO 2018 上提到,Loaders 的问题将得到修复。不确定是在支持库 28 中还是在 AndroidX 库中。我建议检查一下。要记住的主要事情是只在 UI 线程上使用它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多