为什么在设备轮换后调用CursorLoader onLoaderReset()?

时间:2016-05-08 11:53:46

标签: android reset loader

我有一个主要的Activity A,它使用CursorLoader来查询数据库。这是我在活动onCreate()方法中创建的:

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    ...
    getSupportLoaderManager().initLoader(LOADER_MEASUREMENTS, null, A.this);
}

Activity A还实现了CursorLoader的3个回调:

public Loader<Cursor> onCreateLoader(int loaderId, Bundle args)
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor)
public void onLoaderReset(Loader<Cursor> loader)

当我旋转设备时,我看到正确的生命周期方法运行:

A.onPause()
A.onStop()
A.onDestroy()          
A.onCreate()      <-- re-connect to existing loader, onCreateLoader() not called
A.onLoadFinished()
A.onStart()
A.onResume()

然后我打开一个子活动B并旋转我的设备。当我完成B并返回活动A时,我看到以下运行:

B.onPause()
       A.onLoaderReset()      <- why does this run?
       A.onDestroy()          
       A.onCreate()
       A.onCreateLoader()     <- now runs as loader is null
       A.onStart()
       ...

为什么我的装载机会重置,因为我打开了活动B并让设备旋转?只是添加活动B与DB或CursorLoader无关。

3 个答案:

答案 0 :(得分:3)

我检查了 LoaderManager source code您将找到此方法:

.outer {
   display: table;
   position: absolute;
   height: 100%;
   width: 100%;
}

.middle {
   display: table-cell;
   vertical-align: middle;
}

.inner {
   margin-left: auto;
   margin-right: auto; 
   width: /*whatever width you want*/;
}

在旋转屏幕时(由于配置更改),您的加载程序似乎被破坏了。 LoaderManager 在内部调用 destroyLoader 方法,后者又调用 onLoaderReset 回调方法。

答案 1 :(得分:2)

这似乎与LoaderManager有关,而不是保留活动状态。

LoaderManagerandroid.app.FragmentHostCallback管理,此类中的void doLoaderStop(boolean retain)似乎有所不同。根据参数,它将是retain()stop()其加载器。

更改活动A(旋转屏幕)中的配置时,活动会被销毁并立即重新创建。在ActivityThread#handleRelaunchActivity()中,活动的mChangingConfigurations值设置为true。这很重要,因为在配置更改停止活动时,会在Activity

中调用
final void performStop() {
    mDoReportFullyDrawn = false;
    mFragments.doLoaderStop(mChangingConfigurations /*retain*/);
    // ...
}

你可以尝试深入了解发生的事情 - 你的Android安装应该有源代码,而grep很棒 - 但我只是总结一下其他内容。

  

免责声明:我没有彻底核实以下情况,但这是我理解的情况。

如上所示,当看到活动适合重新启动时,它将保留加载器而不是停止它们。旋转活动A时,加载器将被保留。当您旋转活动B时,活动B会立即重新创建,而活动A则会被销毁。与以前相反,装载机将被停止。

LoaderManager可以直接销毁并重新创建已停止的加载器,这就是您所发生的事情。

如果您想自己好好看看,请查看:

  • app/LoaderManagerv4/app/LoaderManager
  • app/FragmentHostCallback
  • ActivityActivityThread

答案 2 :(得分:1)

您可以在A.onLoaderReset()中设置断点并在调试模式下运行应用程序以查看堆栈跟踪,以便使用以下内容进行故障排除:

class A extends Activity implements LoaderManager.LoaderCallbacks
{
    @Override
    public void onLoaderReset(Loader loader)
    {
        try
        {
            // Constructs a new Exception that includes the current stack trace.
            throw new Exception();
        }
        catch (Exception e)
        {
            Log.d("TAG", Log.getStackTraceString(e));
        }
    }
}