http://blog.csdn.net/liaoqianchuan00/article/details/24094733
使用LoaderManager 1. 简单的API让你的Activity/Fragment可以和Loaders进行交互。 2. 每个Activity和每个Fragment只有一个LoaderManager的实例,他们不共享这些Loaders。 3. 主要的方法: initLoader(intid, Bundle args, LoaderCallbacks<D> callbacks) restartLoader(intid, Bundle args, LoaderCallbacks<D> callbacks) destroyLoader(intid) getLoader(intid) privatefinal LoaderCallbacks<Result> loaderCallbacks = newLoaderCallbacks<Result>() { @Override public Loader<Result>onCreateLoader(int id, Bundle args) { return newMyLoader(getActivity(), args.getLong("id")); } @Override public voidonLoadFinished(Loader<Result> loader, Result result) { handleResult(result); } @Override public voidonLoaderReset(Loader<Result> loader) { }}; 注意:绝对不要直接调用一个Loader的框架方法,而你需要使用LoaderManager来自动调用。 如何初始化Loaders 在Activity中 @Override protectedvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... getSupportLoaderManager().initLoader(LOADER_ID,null, callbacks); } 在Fragment中 @Override publicvoid onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); ... getLoaderManager().initLoader(LOADER_ID,null, callbacks); } Loader状态 每个Loader有三个状态:started,stopped,reset。而我们的LoaderManager会自动的根据Activity或者Fragment的状态来改变这些Loader的状态。 1. 在Activity/FragmentstartsàLoader starts: onStartLoading() 2. Activity变成InVisible或者Fragment被detachedàLoader stops: onStopLoading() 3. Activity/Fragment被重新创建à没有回调。LoaderManager将会继续接收results,然后将结果保存到缓存。 4. Activity/Fragment被销毁或者restartLoader/destroyLoader被调用àLoader resets: onReset() 使用Bundle private void onNewQuery(String query) { Bundleargs = new Bundle(); args.putString("query",query); getLoaderManager().restartLoader(LOADER_ID,args, loaderCallbacks); } /////////////////////////////////// @Override publicLoader<Result> onCreateLoader(int id, Bundle args) { returnnew QueryLoader(getActivity(), args.getString("query")); } 很多时候你都不需要使用参数,直接传入null。 LoaderCallBacks是你的Fragment/Activity的一部分。你也可以直接使用Fragment/Activity的实例变量。 @Override publicvoid onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); this.newsId= getArguments().getLong("newsId"); } ... @Override publicLoader<News> onCreateLoader(int id, Bundle args) { returnnew NewsLoader(getActivity(), NewsFragment.this.newsId); } LoaderManager的一个Bug 当一个Fragment因为configuration变化被重新创建的时候(比如旋转屏幕,改变语言等),你在onActivityCreated()里面调用了initLoader()之后,他的LoaderManager调用了两次onLoadFinished。 解决方案: 1. 如果代码逻辑允许,可以不用处理。 2. 将之前的result保存起来,检查结果是否有变化。 3. 在onCreate()里面调用setRetainInstance(true)。 One-shot Loader 很多时候,我们只想运行一次这个Loader一次。比如:我们点击一个按钮然后提交一些信息到服务器。在用户点击了一个按钮后,我们调用initLoader,这个时候用户旋转屏幕,在旋转完屏幕之后,我们想要使用之前loader得到的结果。注意在旋转屏幕的时候,我们的Loader还没有提交完数据。像我们之前用AsyncTask的话,是没有办法在Activity/Fragment重新创建之后拿到之前任务返回的result的。但是使用Loader就简单多了。 在LoaderCallbacks中加入下面的代码 @Override publicvoid onLoadFinished(Loader<Integer> loader, Result result) { getLoaderManager().destroyLoader(LOADER_ID); ... // Process the result } 在Activity/Fragment的创建过程中加入: @Override publicvoid onActivityCreated(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ... //Reconnect to the loader only if present if(getLoaderManager().getLoader(LOADER_ID) != null) { getLoaderManager().initLoader(LOADER_ID,null, this); } } 常见的错误使用 1. 滥用loader id。在创建和restart一个loader的时候,不需要每次都去增加这个ID值。对于某种Loader,只需要一个唯一的id值。 2. 不需要在整个应用程序的范围类为每种Loader创建一个唯一的id值。因为每个LoaderManager都是独立的。你只需要保证你的Activity活着Fragment范围内这种Loader的ID值唯一就可以了。所以直接在Activity或者Fragment中创建一个私有的常量ID就可以了。 3. 避免出现FragmentManager exceptions 你不能在LoaderCallback这些回调里面直接创建FragmentTransaction(包括DialogFragment这种dialog)。 解决方法就是使用Handler来处理FragmentTransaction。 publicclass LinesFragment extends ContextMenuSherlockListFragment implementsLoaderCallbacks<List<LineInfo>>, Callback { ... @Override public void onCreate(BundlesavedInstanceState) { super.onCreate(savedInstanceState); handler = new Handler(this); adapter = newLinesAdapter(getActivity()); } @Override public void onActivityCreated(BundlesavedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(adapter); setListShown(false); getLoaderManager().initLoader(LINES_LOADER_ID,null, this); } @Override public Loader<List<LineInfo>>onCreateLoader(int id, Bundle args) { return newLinesLoader(getActivity()); } @Override public voidonLoadFinished(Loader<List<LineInfo>> loader, List<LineInfo>data) { if (data != null) { adapter.setLinesList(data); } else if (isResumed()) { handler.sendEmptyMessage(LINES_LOADING_ERROR_WHAT); } // The list should now be shown. if (isResumed()) { setListShown(true); } else { setListShownNoAnimation(true); } } @Override public voidonLoaderReset(Loader<List<LineInfo>> loader) { adapter.setLinesList(null); } @Override public boolean handleMessage(Messagemessage) { switch (message.what) { case LINES_LOADING_ERROR_WHAT: MessageDialogFragment .newInstance(R.string.error_title, R.string.lines_loading_error) .show(getFragmentManager()); return true; } return false; }