LoaderManager 的范围是啥?

Posted

技术标签:

【中文标题】LoaderManager 的范围是啥?【英文标题】:What is the scope of a LoaderManager?LoaderManager 的范围是什么? 【发布时间】:2011-11-11 15:28:35 【问题描述】:

在您的 LoaderManager 中识别 Loader 时,您使用唯一的 ID。我在问这些 id 必须有多独特。

是否每个活动和片段都有自己的 LoaderManager?片段是否使用它们附加到的 Activity 的 LoaderManager?应用程序是否只有一个 LoaderManager?

如果您能告诉我如何更改您正在使用的 LoaderManager,将获得奖励积分。如果我希望我的 Activity 中的每个片段都使用相同的 LoaderManager(其中一些正在提取相同的数据并共享 Loader 会很好),这可能吗?

【问题讨论】:

Understanding the LoaderManager (part 2) 【参考方案1】:

我目前正在将我的应用程序移植到 android 兼容包(主要用于 CursorLoader 和 Fragments)。我目前正在尝试在两个片段之间共享一个 CursorLoader,以便对我的 ContentProvider 进行查询。欢迎来到我的世界! ;)

一个简单的用例:

− DummyActivity 扩展 FragmentActivity / Log.d(Constants.LOGTAG, "DummyActivity.onCreate " + getSupportLoaderManager().toString());

- DataFragment 扩展 Fragment 实现 LoaderManager.LoaderCallbacks / Log.d(Constants.LOGTAG, "DataFragment.onCreate " + getLoaderManager().toString());

- ReportFragment 扩展 Fragment 实现 LoaderManager.LoaderCallbacks / Log.d(Constants.LOGTAG, "ReportFragment.onCreate " + getLoaderManager().toString());

DummyActivity 实例化 DataFragment,后者实例化 ReportFragment。 logcat 输出显示每个 LoaderManager 的不同地址。作为第一个结论,每个 Fragment 似乎都有一个合适的 LoaderManager……

如果我能回答您(我们的;))的问题,我会继续更新。如果您取得了任何进展,请分享您的宝贵知识。

更新:

我的假设是加载器 id 仅与特定片段的 LoaderManager 的本地范围相关联,以使多个本地加载器能够与片段相关联(因此您可以根据 id int 在 onCreateLoader 中返回不同的加载器arg 和 initLoader 调用)。

到目前为止,我设法“重用”了一个加载器(……或没有):

- 首先,我在 DummyActivity onCreate 方法中使用 getSupportLoaderManager().enableDebugLogging(true); 启用了 LoaderManager 调试。

- 然后我从 DataFragment 和 ReportFragment 的onCreate 方法中调用了getActivity().getSupportLoaderManager().initLoader(78, null, this);

- DataFragment 通过 mCursorLoader 私有成员上的 setter 公开由 onCreateLoader 方法创建的 CursorLoader。

− ReportFragment onCreateLoader 返回 DataFragment CursorLoader(在使用 findFragmentByTag 检索 Fragment 之后)。

过滤后的(略微混淆的)logcat 输出:

      DummyApp  D  DummyActivity.onCreate
      DummyApp  D  DataFragment.newInstance
      DummyApp  D  ReportFragment.newInstance
      DummyApp  D  DataFragment.onCreate
 LoaderManager  V  initLoader in LoaderManager405a19d0 in SpecificAction4059ee98: args=null
      DummyApp  D  DataFragment.onCreateLoader
 LoaderManager  V    Created new loader LoaderInfo405a2298 #78 : CursorLoader405a22e0
      DummyApp  D  DataFragment.onCreate
      DummyApp  D  DataFragment.onActivityCreated
      DummyApp  D  ReportFragment.onCreate
 LoaderManager  V  initLoader in LoaderManager405a19d0 in DummyActivity4059ee98: args=null
 LoaderManager  V    Re-using existing loader LoaderInfo405a2298 #78 : CursorLoader405a22e0
      DummyApp  D  SpecificActionReportFragment.onCreate
      DummyApp  D  SpecificActionReportFragment.onActivityCreated
 LoaderManager  V  Starting in LoaderManager405a19d0 in DummyActivity4059ee98
 LoaderManager  V    Starting: LoaderInfo405a2298 #78 : CursorLoader405a22e0
 DummyProvider  D  query called
 DummyProvider  D  […]       
 DummyProvider  D  [end of query]
 LoaderManager  V  onLoadComplete: LoaderInfo405a2298 #78 : CursorLoader405a22e0
 LoaderManager  V    onLoadFinished in CursorLoader405a22e0 id=78: CursorWrapperInner405afb20
      DummyApp  D  ReportFragment.onLoadFinished
      DummyApp  D  ReportFragment.displayActionReport
      DummyApp  D  DummyActivity.setReportViewsVisibility
      DummyApp  D  ReportFragment.setSaveReportImageViewVisibility

这两个片段是从 DummyActivity onCreate 方法添加的(与描述的用例不同,但这对我们正在处理的问题没有任何改变)。不幸的是,加载器被重新分配到调用它的最新片段(此处为 ReportFragment)……并且永远不会调用 DataFragment.onLoadFinished。因此,ReportFragment 看起来不错,但 DataFragment 不是最新的,因为更新是从此类的 onLoadFinished 调用的。

我假设有一个底层取消注册调用,然后是 CursorLoader 上的一个注册调用。

待续……

【讨论】:

感谢您的回答!我一直在做一些 ios 的东西,但应该有时间玩弄并在一周左右完成回答这个问题。会回来报告的! :) 接下来几天我也会继续努力,因为我的同事都在等待。 我最终会优化我的 ContentProvider。很抱歉不值得加分……;) 您是否设法了解如何在多个片段/活动中使用一个 LoaderManager?这对我来说很有价值。【参考方案2】:

是的。它对我有用。我在导航抽屉中有 3 个不同的片段,其中相同的数据填充在不同的 ListView 中。 (所有片段都是 SAME Activity 的一部分)。

我的 AsyncTaskLoader:

public class MyTaskLoader extends AsyncTaskLoader<HashMap<String, Integer>> 

public MyTaskLoader(Context context) 
    super(context);


@Override
public HashMap<String, Integer> loadInBackground() 
...
return hashMap;


...

在所有片段中使用相同的加载器 ID。

片段1:

public class Fragment1 extends BaseFragment implements LoaderManager.LoaderCallbacks<HashMap<String, Integer>> 
@Override
public void onCreate(Bundle savedInstanceState) 

//initialize adapter

getActivity().getSupportLoaderManager().initLoader(0, null, this);



@Override
public Loader<HashMap<String, Integer>> onCreateLoader(int arg0, Bundle arg1) 
    // TODO Auto-generated method stub

    return new MyTaskLoader(getActivity());


@Override
public void onLoadFinished(Loader<HashMap<String, Integer>> arg0,
        HashMap<String, Integer> data) 
    // TODO Auto-generated method stub

    listAdapter.setData(data.keySet());



@Override
public void onLoaderReset(Loader<HashMap<String, Integer>> arg0) 
    // TODO Auto-generated method stub

    listAdapter.setData(null);


对 Fragment2 使用相同的 Id:

public class Fragment2 extends BaseFragment implements LoaderManager.LoaderCallbacks<HashMap<String, Integer>> 
@Override
public void onCreate(Bundle savedInstanceState) 

//initialize adapter

getActivity().getSupportLoaderManager().initLoader(0, null, this);



@Override
public Loader<HashMap<String, Integer>> onCreateLoader(int arg0, Bundle arg1) 
    // TODO Auto-generated method stub

    return new MyTaskLoader(getActivity());


@Override
public void onLoadFinished(Loader<HashMap<String, Integer>> arg0,
        HashMap<String, Integer> data) 
    // TODO Auto-generated method stub

    listAdapter.setData(data.keySet());



@Override
public void onLoaderReset(Loader<HashMap<String, Integer>> arg0) 
    // TODO Auto-generated method stub

    listAdapter.setData(null);


应在初始化加载程序之前初始化适配器。 工作至今。 但是,这是正确的方法吗?有没有更好的方法来为多个 Fragment 使用通用加载器?

【讨论】:

以上是关于LoaderManager 的范围是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Android LoaderManager原理剖析

Android LoaderManager原理详解

LoaderManager与CursorLoader用法

LoaderManager 是做啥的?

安卓:CursorLoader、LoaderManager、SQLite

IllegalStateException - 使用 AutocompleteTextView 支持 LoaderManager