在`LoaderManager`之间`initLoader`和`restartLoader`差异 [英] Difference between `initLoader` and `restartLoader` in `LoaderManager`

查看:324
本文介绍了在`LoaderManager`之间`initLoader`和`restartLoader`差异的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我关于 initLoader 和的<$ C $的 restartLoader 函数之间的区别我完全丧失C> LoaderManager :

I'm completely lost regarding the differences between the initLoader and the restartLoader functions of the LoaderManager:

  • 它们都具有相同的签名。
  • restartLoader 还创建了一个加载器,如果它不存在(开始一个新的或重新启动现有的装载机在此管理)。
  • They both have the same signature.
  • restartLoader also creates a loader, if it does not exist ("Starts a new or restarts an existing Loader in this manager").

有两种方法之间有一定的关系?难道叫 restartLoader 随时拨打 initLoader ?我能叫 restartLoader 无需调用 initLoader ?是将其保存到调用 initLoader 两次刷新数据?什么时候应该使用一两个和(重要!)为什么?

Is there some relation between the two methods? Does calling restartLoader always call initLoader? Can I call restartLoader without having to call initLoader? Is it save to call initLoader twice to refresh the data? When should I use one of the two and (important!) why?

推荐答案

要回答这个问题,你需要深入到LoaderManager code。 虽然LoaderManager本身的文件不够明确(或者就不会有这个问题),为LoaderManagerImpl,抽象LoaderManager的子类的文档,是更富有启发性。

To answer this question you need to dig into the LoaderManager code. While the documentation for LoaderManager itself isn't clear enough (or there wouldn't be this question), the documentation for LoaderManagerImpl, a subclass of the abstract LoaderManager, is much more enlightening.

initLoader

呼叫初始化一个特定ID与装载机。如果这个ID已经   具有与之相关联的装载机,它保持不变和任何previous   回调与新提供的那些所取代。如果不存在   目前是装载机的ID,一个新的创建和启动。

Call to initialize a particular ID with a Loader. If this ID already has a Loader associated with it, it is left unchanged and any previous callbacks replaced with the newly provided ones. If there is not currently a Loader for the ID, a new one is created and started.

当一个组件此功能一般应使用   初始化,以确保它依赖于装载机被创建。本   允许其重新使用现有装载机的数据,如果有已经是1,   使得例如当后一个重新创建一个活动   配置改变它不需要重新创建其装载机

This function should generally be used when a component is initializing, to ensure that a Loader it relies on is created. This allows it to re-use an existing Loader's data if there already is one, so that for example when an Activity is re-created after a configuration change it does not need to re-create its loaders.

restartLoader

通话重新创建与特定ID相关联的装载机。如果   有当前与此ID相关的装载机,这将是   取消/停止/销毁为宜。一个新的加载程序   给定参数将被创建,其数据传递给你一次   可用。

Call to re-create the Loader associated with a particular ID. If there is currently a Loader associated with this ID, it will be canceled/stopped/destroyed as appropriate. A new Loader with the given arguments will be created and its data delivered to you once available.

[...]调用此功能后,任何previous装载机与此ID相关联   将被视为无效,您将收到没有进一步数据   从他们的更新。

[...] After calling this function, any previous Loaders associated with this ID will be considered invalid, and you will receive no further data updates from them.

基本上有两种情况:

  1. id为加载程序不存在:这两种方法都会创建一个新的加载器,所以没有区别有
  2. id为装载机已经存在:initLoader将只替换作为参数传递的回调,但不会取消或停止加载程序。对于CursorLoader这意味着光标保持开放和活跃的(如果是这样的initLoader调用之前的情况)。 restartLoader,另一方面将取消,停止和销毁加载程序(并关闭就像一个游标基础数据源),并创建一个新的加载器(这也将创造一个新的光标,然后重新运行查询,如果加载器是CursorLoader)

下面是简化的code这两种方法:

Here's the simplified code for both methods:

initLoader

LoaderInfo info = mLoaders.get(id);
if (info == null) {
    // Loader doesn't already exist -> create new one
    info = createAndInstallLoader(id, args, LoaderManager.LoaderCallbacks<Object>)callback);
} else {
   // Loader exists -> only replace callbacks   
   info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}

restartLoader

LoaderInfo info = mLoaders.get(id);
if (info != null) {
    LoaderInfo inactive = mInactiveLoaders.get(id);
    if (inactive != null) {
        // does a lot of stuff to deal with already inactive loaders
    } else {
        // Keep track of the previous instance of this loader so we can destroy
        // it when the new one completes.
        info.mLoader.abandon();
        mInactiveLoaders.put(id, info);
    }
}
info = createAndInstallLoader(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);

正如我们在情况下看到加载不存在(资讯== NULL)这两种方法将创建一个新的加载器(资讯= createAndInstallLoader(...))。 如果装载机已经存在initLoader只替换回调(info.mCallbacks = ...),而restartLoader灭活旧装载机(当新的加载器完成其工作,这将被销毁),然后创建一个新的。

As we can see in case the loader doesn't exist (info == null) both methods will create a new loader (info = createAndInstallLoader(...)). In case the loader already exists initLoader only replaces the callbacks (info.mCallbacks = ...) while restartLoader inactivates the old loader (it will be destroyed when the new loader completes its work) and then creates a new one.

这样说,现在很清楚什么时候什么时候使用restartLoader使用initLoader和为什么是有意义的有两种方法。 initLoader用于确保有一个初始化装载机。如果不存在一个新的创建,如果已经存在它重新使用。我们总是用这种方法,除非我们需要一个新的加载程序因为运行查询发生了变化(而不是底层的数据,但像SQL语句的CursorLoader实际的查询),在这种情况下,我们将调用restartLoader。

Thus said it's now clear when to use initLoader and when to use restartLoader and why it makes sense to have the two methods. initLoader is used to ensure there's an initialized loader. If none exists a new one is created, if one already exists it's re-used. We always use this method UNLESS we need a new loader because the query to run has changed (not the underlying data but the actual query like in SQL statement for a CursorLoader), in which case we will call restartLoader.

该活动/片段生命周期无关,与使用一个决定或其他方式(而且也没有必要跟踪使用一杆旗西蒙提出的要求的)!这一决定是根据需要新装载器只。如果我们想要运行相同的查询,我们使用initLoader,如果我们要运行一个我们使用restartLoader不同的查询。 我们总是可以使用restartLoader但是这将是低效的。过了屏幕旋转,或者如果用户离开应用程序,并在稍后返回到相同的活动,我们通常要表现出同样的查询结果,并因此restartLoader将不必要地重新创建装载机和罢免底层(潜在的昂贵)查询结果

The Activity/Fragment life cycle has nothing to do with the decision to use one or the other method (and there's no need to keep track of the calls using a one-shot flag as Simon suggested)! This decision is made solely based on the "need" for a new loader. If we want to run the same query we use initLoader, if we want to run a different query we use restartLoader. We could always use restartLoader but that would be inefficient. After a screen rotation or if the user navigates away from the app and returns later to the same Activity we usually want to show the same query result and so the restartLoader would unnecessarily re-create the loader and dismiss the underlying (potentially expensive) query result.

这是非常重要的是了解所加载的数据和查询来加载数据之间的差异。假设我们使用CursorLoader查询表的订单。如果一个新的顺序添加到该表中的CursorLoader使用onContentChanged()通知UI更新和显示新订单(不需要使用restartLoader在这种情况下)。如果我们想只显示未结订单,我们需要一个新的查询,我们将使用restartLoader返回一个新的CursorLoader反映新的查询。

It's very important to understand the difference between the data that is loaded and the "query" to load that data. Let's assume we use a CursorLoader querying a table for orders. If a new order is added to that table the CursorLoader uses onContentChanged() to inform the ui to update and show the new order (no need to use restartLoader in this case). If we want to display only open orders we need a new query and we would use restartLoader to return a new CursorLoader reflecting the new query.

有两种方法之间有一定的关系?

Is there some relation between the two methods?

它们共享code创建一个新的Loader,但他们做不同的事情,当装载机已经存在。

They share the code to create a new Loader but they do different things when a loader already exists.

是否调用restartLoader随时拨打initLoader?

Does calling restartLoader always call initLoader?

没有它从来不会。

我可以叫restartLoader无需调用initLoader?

Can I call restartLoader without having to call initLoader?

是的。

它是安全的呼吁initLoader两次刷新数据?

Is it safe to call initLoader twice to refresh the data?

这是安全地调用initLoader两次,但没有数据将被刷新。

It's safe to call initLoader twice but no data will be refreshed.

当我应该使用一两个和(重要!)为什么?

When should I use one of the two and (important!) why?

这应该(希望)我上面的解释后予以明确。

That should (hopefully) be clear after my explanations above.

的配置修改

一个LoaderManager保持其状态在整个配置更改(包括取向的变化),所以你会觉得没有什么留给我们去做。再想想...

A LoaderManager retains its state across configuration changes (including orientation changes) so you would think there's nothing left for us to do. Think again...

首先,一个LoaderManager不保留的回调,所以如果你什么都不做,你将无法接听您的回调方法,如onLoadFinished()之类的,而且很可能会打破你的应用程序。 因此,我们必须调用至少initLoader恢复回调方法(一restartLoader当然是可能的也是如此)。该<一href="http://developer.android.com/reference/android/app/LoaderManager.html#initLoader%28int,%20android.os.Bundle,%20android.app.LoaderManager.LoaderCallbacks%3CD%3E%29">documentation声明:

First of all a LoaderManager doesn't retain the callbacks, so if you do nothing you won't receive calls to your callback methods like onLoadFinished() and the like and that will very likely break your app. Therefore we HAVE to call at least initLoader to restore the callback methods (a restartLoader is of course possible too). The documentation states:

如果在调用点的呼叫者处于其开始状态,而   请装载机已经存在,并已产生了数据,那么   回调onLoadFinished(装载机,D)将被立即调用(内   此功能)[...]

If at the point of call the caller is in its started state, and the requested loader already exists and has generated its data, then callback onLoadFinished(Loader, D) will be called immediately (inside of this function) [...].

这意味着,如果我们改变方向时后拨打initLoader,我们将得到一个onLoadFinished电话马上,因为数据已经被加载(假设是变更前的情况下)。 虽然这听起来很简单的它可能会非常棘手(不大家都爱的Andr​​oid ...)。

That means if we call initLoader after an orientation change, we will get an onLoadFinished call right away because the data is already loaded (assuming that was the case before the change). While that sounds straight forward it can be tricky (don't we all love Android...).

我们有两种情况之间进行区分:

We have to distinguish between two cases:

  1. 在处理配置变化本身:这是片段的情况下 即使用setRetainInstance(真),或具有一个活动 根据机器人:在清单configChanges标签。这些 组件将不会收到如后的onCreate调用一个 屏幕旋转,所以记住调用 initLoader / restartLoader在另一个回调方法(例如,在 onActivityCreated(捆绑))。为了能够初始化加载器(S) 装载机的id需要存储(例如,在列表)。因为 该组件在整个配置的变化,我们可以保留 只是环比现有装载机ID和调用initLoader(loaderid, ...)。
  2. 在不处理配置更改自己:在这种情况下, 装载机可以的onCreate被初始化,但我们需要手动 保留装载机的ID,否则我们将不能够进行所需的 initLoader / restartLoader调用。如果ID被存储在一个 ArrayList中,我们会做一个
    outState.putIntegerArrayList(loaderIdsKey,loaderIdsArray)在 的onSaveInstanceState和恢复IDS中的onCreate: loaderIdsArray = savedInstanceState.getIntegerArrayList(loaderIdsKey)我们做之前, 在initLoader接听电话。
  1. Handles configuration changes itself: this is the case for Fragments that use setRetainInstance(true) or for an Activity with the according android:configChanges tag in the manifest. These components won't receive an onCreate call after e.g. a screen rotation, so keep in mind to call initLoader/restartLoader in another callback method (e.g. in onActivityCreated(Bundle)). To be able to initialize the Loader(s), the loader ids need to be stored (e.g. in a List). Because the component is retained across configuration changes we can just loop over the existing loader ids and call initLoader(loaderid, ...).
  2. Doesn't handle configuration changes itself: In this case the Loaders can be initialized in onCreate but we need to manually retain the loader ids or we won't be able to make the needed initLoader/restartLoader calls. If the ids are stored in an ArrayList, we would do an
    outState.putIntegerArrayList(loaderIdsKey, loaderIdsArray) in onSaveInstanceState and restore the ids in onCreate: loaderIdsArray = savedInstanceState.getIntegerArrayList(loaderIdsKey) before we make the initLoader call(s).

这篇关于在`LoaderManager`之间`initLoader`和`restartLoader`差异的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆