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 的范围是啥?的主要内容,如果未能解决你的问题,请参考以下文章
安卓:CursorLoader、LoaderManager、SQLite
IllegalStateException - 使用 AutocompleteTextView 支持 LoaderManager