loader机制
一. 概述
- 对每个activity或者fragment都有效
- 提供了异步加载数据的能力
- 监视数据源并在内容改变的时候传递新的结果
- 在Activity配置发生变化(如横竖屏切换)时不重复加载数据
- Loader一般用在Activity和fragment异步加载数据,无需重新启动一个线程来执行数据加载,异步加载可以用asyncTask, 但是loader自带数据结果监听机制,可以方便优雅的进行UI更新
相关类
LoaderManager
每个activity或者fragment都只有一个LoaderManager,但是一个LoaderManager可以管理多个Loader
LoaderCallbacks
客户端用于和LoaderManager交互的回调接口
Loader
加载器的基类
AyncTaskLoader
提供一个AsyncTask来执行异步任务的抽象类
CursorLoader
AyncTaskLoader的子类,它查询ContentResolver然后返回一个Cursor,是从一个ContentProvider异步加载数据的最好方式。
二. 启动Loader
getLoaderManager().initLoader(id,args, callback);
- id:用来标志loader
- args:可选参数,用于loader的初始化
- callback:回调
initLoader保证一个loader被激活,它可能有两种结果
一种是:id所指示的loader已经存在,那么这个loader将被重用
另一种是:loader不存在,会触发callback的onCreateLoader方法。
三.重启和回调
重启
getLoaderManager().restartLoader(id, args, callback);
回调
onCreateLoader
onLoadFinished
onLoaderReset
四. 应用
public static class CursorLoaderListFragment extends ListFragment
implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {
// 这是用于显示列表数据的Adapter
SimpleCursorAdapter mAdapter;
// 如果非null,这是当前的搜索过虑器
String mCurFilter;
@Override public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// 如果列表中没有数据,就给控件一些文字去显示.在一个真正的应用
// 中这应用资源中取得.
setEmptyText("No phone numbers");
// 我们在动作栏中有一个菜单项.
setHasOptionsMenu(true);
// 创建一个空的adapter,我们将用它显示加载后的数据
mAdapter = new SimpleCursorAdapter(getActivity(),
android.R.layout.simple_list_item_2, null,
new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },
new int[] { android.R.id.text1, android.R.id.text2 }, 0);
setListAdapter(mAdapter);
// 准备loader.可能是重连到一个已存在的或开始一个新的
getLoaderManager().initLoader(0, null, this);
}
@Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// 放置一个动作栏项用于搜索.
MenuItem item = menu.add("Search");
item.setIcon(android.R.drawable.ic_menu_search);
item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
SearchView sv = new SearchView(getActivity());
sv.setOnQueryTextListener(this);
item.setActionView(sv);
}
public boolean onQueryTextChange(String newText) {
// 在动作栏上的搜索字串改变时被调用.更新
//搜索过滤器,并重启loader来执行一个新的查询
mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;
getLoaderManager().restartLoader(0, null, this);
return true;
}
@Override public boolean onQueryTextSubmit(String query) {
// 我们不关心这个方法
return true;
}
@Override public void onListItemClick(ListView l, View v, int position, long id) {
// 写入你想写的代码
Log.i("FragmentComplexList", "Item clicked: " + id);
}
// 这是我们想获取的联系人中一行的数据.
static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
Contacts._ID,
Contacts.DISPLAY_NAME,
Contacts.CONTACT_STATUS,
Contacts.CONTACT_PRESENCE,
Contacts.PHOTO_ID,
Contacts.LOOKUP_KEY,
};
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// 当一个新的loader需被创建时调用.本例仅有一个Loader,
//所以我们不需关心ID.首先设置base URI,URI指向的是联系人
Uri baseUri;
if (mCurFilter != null) {
baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,
Uri.encode(mCurFilter));
} else {
baseUri = Contacts.CONTENT_URI;
}
// 现在创建并返回一个CursorLoader,它将负责创建一个
// Cursor用于显示数据
String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("
+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ Contacts.DISPLAY_NAME + " != '' ))";
return new CursorLoader(getActivity(), baseUri,
CONTACTS_SUMMARY_PROJECTION, select, null,
Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");
}
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// 将新的cursor换进来.(框架将在我们返回时关心一下旧cursor的关闭)
mAdapter.swapCursor(data);
}
public void onLoaderReset(Loader<Cursor> loader) {
//在最后一个Cursor准备进入上面的onLoadFinished()之前.
// Cursor要被关闭了,我们需要确保不再使用它.
mAdapter.swapCursor(null);
}
}
利用loader查询通讯录
public class MainActivity extends ListActivity implements LoaderManager.LoaderCallbacks<cursor>, SearchView.OnQueryTextListener {
private SimpleCursorAdapter cursorAdapter;
private String filterName=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView tv= (TextView) findViewById(android.R.id.empty);
tv.setText("请稍后");
cursorAdapter=new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_2,
null,
new String[]{ContactsContract.Contacts.DISPLAY_NAME},
new int[]{android.R.id.text1},0);
setListAdapter(cursorAdapter);
//初始化Loader
getLoaderManager().initLoader(0,null,this);
}
@Override
public Loader<cursor> onCreateLoader(int id, Bundle args) {
Uri uri;
String[] pro=new String[]{ ContactsContract.Contacts.DISPLAY_NAME,ContactsContract.Contacts._ID};
if(TextUtils.isEmpty(filterName)){
uri= ContactsContract.Contacts.CONTENT_URI;
}else{
uri=Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,Uri.encode(filterName));
}
//创建Loader对象,开始异步加载数据
return new CursorLoader(this,uri,pro, null, null,null);
}
@Override
public void onLoadFinished(Loader<cursor> loader, Cursor data) {
//得到异步加载数据,更新Adapter
cursorAdapter.swapCursor(data);
}
@Override
public void onLoaderReset(Loader<cursor> loader) {
//移除adapter使用的Loader,系统会释放不再使用的Loader
cursorAdapter.swapCursor(null);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.menu_main,menu);
SearchView v= (SearchView) menu.findItem(R.id.menu_search).getActionView();
v.setOnQueryTextListener(this);
return true;
}
@Override
public boolean onQueryTextSubmit(String query) {
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
filterName=newText;
//使用新的Loader(清空旧的数据)
getLoaderManager().restartLoader(0,null,this);
return false;
}
}
应用列表的获取
public static class PackageIntentReceiver extends BroadcastReceiver {
final AppListLoader mLoader;
// 这个构造函数是很重要的 他接收的 就是自定义的loader
public PackageIntentReceiver(AppListLoader loader) {
mLoader = loader;
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addDataScheme("package");
mLoader.getContext().registerReceiver(this, filter);
// Register for events related to sdcard installation.
IntentFilter sdFilter = new IntentFilter();
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
// 在这个地方 直接用loader来注册这个广播接收器
mLoader.getContext().registerReceiver(this, sdFilter);
}
// 在收到广播以后 什么事情都没有做,而是调用了loader的onContentChanged方法
@Override
public void onReceive(Context context, Intent intent) {
// Tell the loader about the change.
mLoader.onContentChanged();
}
}
public static class AppListLoader extends AsyncTaskLoader<List<AppEntry>> {
final InterestingConfigChanges mLastConfig = new InterestingConfigChanges();
final PackageManager mPm;
List<AppEntry> mApps;
PackageIntentReceiver mPackageObserver;
public AppListLoader(Context context) {
super(context);
// Retrieve the package manager for later use; note we don't
// use 'context' directly but instead the save global application
// context returned by getContext().
mPm = getContext().getPackageManager();
}
// 实际上最重要的就是这个方法了,每当这个回调方法被调用的时候 就去取applist 然后将结果返回到
// onLoadFinished 这个回调方法里面!
@Override
public List<AppEntry> loadInBackground() {
// Retrieve all known applications.
List<ApplicationInfo> apps = mPm
.getInstalledApplications(PackageManager.GET_UNINSTALLED_PACKAGES
| PackageManager.GET_DISABLED_COMPONENTS);
if (apps == null) {
apps = new ArrayList<ApplicationInfo>();
}
final Context context = getContext();
// Create corresponding array of entries and load their labels.
List<AppEntry> entries = new ArrayList<AppEntry>(apps.size());
for (int i = 0; i < apps.size(); i++) {
AppEntry entry = new AppEntry(this, apps.get(i));
entry.loadLabel(context);
entries.add(entry);
}
// Sort the list.
Collections.sort(entries, ALPHA_COMPARATOR);
// Done!
return entries;
}
/**
* Called when there is new data to deliver to the client. The super class
* will take care of delivering it; the implementation here just adds a
* little more logic.
*/
@Override
public void deliverResult(List<AppEntry> apps) {
if (isReset()) {
// An async query came in while the loader is stopped. We
// don't need the result.
if (apps != null) {
onReleaseResources(apps);
}
}
List<AppEntry> oldApps = mApps;
mApps = apps;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(apps);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldApps != null) {
onReleaseResources(oldApps);
}
}
/**
* Handles a request to start the Loader.
*/
@Override
protected void onStartLoading() {
if (mApps != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mApps);
}
// Start watching for changes in the app data.
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
// Has something interesting in the configuration changed since we
// last built the app list?
boolean configChange = mLastConfig.applyNewConfig(getContext()
.getResources());
if (takeContentChanged() || mApps == null || configChange) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
@Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
@Override
public void onCanceled(List<AppEntry> apps) {
super.onCanceled(apps);
// At this point we can release the resources associated with 'apps'
// if needed.
onReleaseResources(apps);
}
/**
* Handles a request to completely reset the Loader.
*/
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mApps != null) {
onReleaseResources(mApps);
mApps = null;
}
// Stop monitoring for changes.
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
/**
* Helper function to take care of releasing resources associated with an
* actively loaded data set.
*/
protected void onReleaseResources(List<AppEntry> apps) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
在loader里 注册广播接收器,当广播接收器 收到广播以后 就调用loader的onContentChanged方法,这个方法一调用 AppListLoader里的loadInBackGround就会被调用,然后当loadInBackGround执行完毕以后 就会把结果传递给onLoadFinished方法了
五.源码分析
5.1 getLoaderManager的源码:每个activity和fragment都对应一个LoaderManager。
fragment getLoaderManager的源码
fragment的getLoaderManager也是通过activity的getLoader去调用的
//这边就能看出来一个fragment只能有一个loadermanager了。
public LoaderManager getLoaderManager() {
if (mLoaderManager != null) {
return mLoaderManager;
}
//mHost很好理解 就是fragment的宿主,也就是跟fragment 相关联的activity。
if (mHost == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mCheckedForLoaderManager = true;
mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, true);
return mLoaderManager;
}
activity中getLoaderManager的源码
**结论:
**真正的loadermanager都是存储在activity中的,包括fragment的loadermanager也是,通过一个map来保证 get的时候取的manager是自己对应的,并且全局唯一
//在activty中最终实际上调用的就是他了 是这个方法
LoaderManagerImpl getLoaderManagerImpl() {
if (mLoaderManager != null) {
return mLoaderManager;
}
mCheckedForLoaderManager = true;
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
return mLoaderManager;
}
//这个地方就能看到 主要的第一个参数 who,你到这就能发现 如果是activity自己调用的话,传进去的who的值就是root
//也就是说一个actvity 只能有一个loadermanger 但是我们可以发现在fragment里 传进去的值是下面这个:
// Internal unique name for this fragment;
//String mWho;
//也就是说每一个fragment的mWho的值都是唯一的,而在activty中,是维护了一个map,一个key 对应一个loadermanager
//key就是fragment的那个唯一的标示,或者是activity自己,activity自己的标示就是(root)了
LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {
if (mAllLoaderManagers == null) {
mAllLoaderManagers = new ArrayMap<String, LoaderManager>();
}
LoaderManagerImpl lm = (LoaderManagerImpl) mAllLoaderManagers.get(who);
if (lm == null) {
if (create) {
lm = new LoaderManagerImpl(who, this, started);
mAllLoaderManagers.put(who, lm);
}
} else {
lm.updateHostController(this);
}
return lm;
}
5.2 回调发生关系的源码(LoaderManger与LoaderCallback的联系)
//这个就是现在存活的loader
final SparseArray<LoaderInfo> mLoaders = new SparseArray<LoaderInfo>(0);
//这个是已经运行结束的loader
final SparseArray<LoaderInfo> mInactiveLoaders = new SparseArray<LoaderInfo>(0);
public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
if (mCreatingLoader) {
throw new IllegalStateException("Called while creating a loader");
}
//这个就是先看看是否有活动的loader 有的话就取出来 没有的话 就创建一个
LoaderInfo info = mLoaders.get(id);
if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
if (info == null) {
// Loader doesn't already exist; create.
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
if (DEBUG) Log.v(TAG, " Created new loader " + info);
} else {
if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
info.mCallbacks = (LoaderManager.LoaderCallbacks<Object>)callback;
}
if (info.mHaveData && mStarted) {
// If the loader has already generated its data, report it now.
info.callOnLoadFinished(info.mLoader, info.mData);
}
return (Loader<D>)info.mLoader;
}
//其实这个创建loader的过程特别简单,我们主要看第三个参数,callback 这个参数
//一想就明白,在前面3个demo里我们是直接在fragemet和activity里实现的callback
//所以传进去的就是this,也就是说 回调就是在这个函数里 真正的和loader 发生了关联了
private LoaderInfo createAndInstallLoader(int id, Bundle args,
LoaderManager.LoaderCallbacks<Object> callback) {
try {
mCreatingLoader = true;
LoaderInfo info = createLoader(id, args, callback);
installLoader(info);
return info;
} finally {
mCreatingLoader = false;
}
}
5.3 数据观察者
//这个是一个观察者 当发生变化的时候 他调用了onContentChanged方法
public final class ForceLoadContentObserver extends ContentObserver {
public ForceLoadContentObserver() {
super(new Handler());
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
@Override
public void onChange(boolean selfChange) {
onContentChanged();
}
}
//下面这2个方法一看就明白 最终当数据源发生变化的时候 会通知这个观察者,然后这个观察者会最终调用
//onForceLoad这个方法 而onForceLoad是交给子类去实现的 也就是AsyncTaskLoader的onForceLoad方法了
public void onContentChanged() {
if (mStarted) {
forceLoad();
} else {
// This loader has been stopped, so we don't want to load
// new data right now... but keep track of it changing to
// refresh later if we start again.
mContentChanged = true;
}
}
public void forceLoad() {
onForceLoad();
}
/**
* Subclasses must implement this to take care of requests to {@link #forceLoad()}.
* This will always be called from the process's main thread.
*/
protected void onForceLoad() {
}
5.4 AsyncTaskLoader加载数据
//这边一目了然 asynacTaskLoader 里面 正好是有一个AsyncTask对象的!实现了runnabele接口
//注意着参数d 这个d是干嘛的,这个d就是用来传递参数的一个泛型,可以是系统实现的loader里的cursor
//也可以是我们自己实现的loader里的list类型
final class LoadTask extends AsyncTask<Void, Void, D> implements Runnable {
private final CountDownLatch mDone = new CountDownLatch(1);
// Set to true to indicate that the task has been posted to a handler for
// execution at a later time. Used to throttle updates.
boolean waiting;
/* Runs on a worker thread */
@Override
protected D doInBackground(Void... params) {
if (DEBUG) Log.v(TAG, this + " >>> doInBackground");
try {
//这个地方就很明显了,他调用了自己的onLoadInBackGround方法
D data = AsyncTaskLoader.this.onLoadInBackground();
if (DEBUG) Log.v(TAG, this + " <<< doInBackground");
return data;
} catch (OperationCanceledException ex) {
if (!isCancelled()) {
// onLoadInBackground threw a canceled exception spuriously.
// This is problematic because it means that the LoaderManager did not
// cancel the Loader itself and still expects to receive a result.
// Additionally, the Loader's own state will not have been updated to
// reflect the fact that the task was being canceled.
// So we treat this case as an unhandled exception.
throw ex;
}
if (DEBUG) Log.v(TAG, this + " <<< doInBackground (was canceled)", ex);
return null;
}
}
//后面还有很多代码 略过
}
//你看这里下面的2个函数 一看就明白了 最终task里调用的是这个抽象方法,那这个抽象方法
//就是留给我们子类自己去实现的,我们在自定义loader的时候最重要的就是重写这个方法。
protected D onLoadInBackground() {
return loadInBackground();
}
public abstract D loadInBackground();
//你看这个地方 就是当数据源发生变化的时候 就会调用这个方法了,启动了我们的laodtask
//也是最终调用子类 也就是CursorLoader这样的子类的loadInBackground方法了
@Override
protected void onForceLoad() {
super.onForceLoad();
cancelLoad();
mTask = new LoadTask();
if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
executePendingTask();
}
//在那个asynctask里面 走完是肯定要走这个方法的 相信大家都能理解。
@Override
protected void onPostExecute(D data) {
if (DEBUG) Log.v(TAG, this + " onPostExecute");
try {
AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
} finally {
mDone.countDown();
}
}
//实际上走的就是这个方法。看26行-
void dispatchOnLoadComplete(LoadTask task, D data) {
if (mTask != task) {
if (DEBUG) Log.v(TAG, "Load complete of old task, trying to cancel");
dispatchOnCancelled(task, data);
} else {
if (isAbandoned()) {
// This cursor has been abandoned; just cancel the new data.
onCanceled(data);
} else {
commitContentChanged();
mLastLoadCompleteTime = SystemClock.uptimeMillis();
mTask = null;
if (DEBUG) Log.v(TAG, "Delivering result");
deliverResult(data);
}
}
}
//这边一下就看出来是调用的mListtenr的回调方法
public void deliverResult(D data) {
if (mListener != null) {
mListener.onLoadComplete(this, data);
}
}
public interface OnLoadCompleteListener<D> {
/**
* Called on the thread that created the Loader when the load is complete.
*
* @param loader the loader that completed the load
* @param data the result of the load
*/
public void onLoadComplete(Loader<D> loader, D data);
}
//并且通过这个注册
public void registerListener(int id, OnLoadCompleteListener<D> listener) {
if (mListener != null) {
throw new IllegalStateException("There is already a listener registered");
}
mListener = listener;
mId = id;
}
5.5 listener的注册和回调
void installLoader(LoaderInfo info) {
mLoaders.put(info.mId, info);
if (mStarted) {
//跳转到51行
info.start();
}
}
void start() {
if (mRetaining && mRetainingStarted) {
// Our owner is started, but we were being retained from a
// previous instance in the started state... so there is really
// nothing to do here, since the loaders are still started.
mStarted = true;
return;
}
if (mStarted) {
// If loader already started, don't restart.
return;
}
mStarted = true;
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
//回调onCreateLoader
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
if (mLoader.getClass().isMemberClass()
&& !Modifier.isStatic(mLoader.getClass().getModifiers())) {
throw new IllegalArgumentException(
"Object returned from onCreateLoader must not be a non-static inner member class: "
+ mLoader);
}
if (!mListenerRegistered) {
//就是在这里注册的mloader里的回调了,注意这里的参数是this 也就是loaderInfo这个类 注意这个类就是loadermanger里的内部类了 再继续往下看
//我们前面说到 在asynctask里面最终调用的是mLoader里的onLoadComplete方法 所以我们就看看loaderInfo这个类里的这个方法做了什么看91行
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
mLoader.startLoading();
}
}
@Override
public void onLoadComplete(Loader<Object> loader, Object data) {
if (DEBUG) Log.v(TAG, "onLoadComplete: " + this);
if (mDestroyed) {
if (DEBUG) Log.v(TAG, " Ignoring load complete -- destroyed");
return;
}
if (mLoaders.get(mId) != this) {
// This data is not coming from the current active loader.
// We don't care about it.
if (DEBUG) Log.v(TAG, " Ignoring load complete -- not active");
return;
}
LoaderInfo pending = mPendingLoader;
if (pending != null) {
// There is a new request pending and we were just
// waiting for the old one to complete before starting
// it. So now it is time, switch over to the new loader.
if (DEBUG) Log.v(TAG, " Switching to pending loader: " + pending);
mPendingLoader = null;
mLoaders.put(mId, null);
destroy();
installLoader(pending);
return;
}
// Notify of the new data so the app can switch out the old data before
// we try to destroy it.
if (mData != data || !mHaveData) {
mData = data;
mHaveData = true;
if (mStarted) {
//继续往下 看第149行
callOnLoadFinished(loader, data);
}
}
//if (DEBUG) Log.v(TAG, " onLoadFinished returned: " + this);
// We have now given the application the new loader with its
// loaded data, so it should have stopped using the previous
// loader. If there is a previous loader on the inactive list,
// clean it up.
LoaderInfo info = mInactiveLoaders.get(mId);
if (info != null && info != this) {
info.mDeliveredData = false;
info.destroy();
mInactiveLoaders.remove(mId);
}
if (mHost != null && !hasRunningLoaders()) {
mHost.mFragmentManager.startPendingDeferredFragments();
}
}
void callOnLoadFinished(Loader<Object> loader, Object data) {
if (mCallbacks != null) {
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoadFinished";
}
try {
if (DEBUG) Log.v(TAG, " onLoadFinished in " + loader + ": "
+ loader.dataToString(data));
//到这里就真相大白了,最终callback是在这里调用的onLoadFinished方法也就是我们经常重写的方法
mCallbacks.onLoadFinished(loader, data);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
mDeliveredData = true;
}
}
5.6 activity中声明周期方法里关于loader的源码分析
onStart
/看activity的onStart方法
protected void onStart() {
if (DEBUG_LIFECYCLE) Slog.v(TAG, "onStart " + this);
mCalled = true;
//继续看12行 这个地方mFragements 你就理解成activity本身即可,不多做解释 这个地方要搞清楚 又是另外一块了 有兴趣的可以自行谷歌activity和fragment如何建立关系
mFragments.doLoaderStart();
getApplication().dispatchActivityStarted(this);
}
//这个函数就很明显了 调用了manager的dostart函数
void doLoaderStart() {
if (mLoadersStarted) {
return;
}
mLoadersStarted = true;
if (mLoaderManager != null) {
//跳转到30行
mLoaderManager.doStart();
} else if (!mCheckedForLoaderManager) {
mLoaderManager = getLoaderManager("(root)", mLoadersStarted, false);
}
mCheckedForLoaderManager = true;
}
//------------------注意上面的代码都在activity里,下面的开始 都在LoaderManger类里了
void doStart() {
if (DEBUG) Log.v(TAG, "Starting in " + this);
if (mStarted) {
RuntimeException e = new RuntimeException("here");
e.fillInStackTrace();
Log.w(TAG, "Called doStart when already started: " + this, e);
return;
}
mStarted = true;
// Call out to sub classes so they can start their loaders
// Let the existing loaders know that we want to be notified when a load is complete
for (int i = mLoaders.size()-1; i >= 0; i--) {
//跳转到50行
mLoaders.valueAt(i).start();
}
}
void start() {
if (mRetaining && mRetainingStarted) {
// Our owner is started, but we were being retained from a
// previous instance in the started state... so there is really
// nothing to do here, since the loaders are still started.
mStarted = true;
return;
}
if (mStarted) {
// If loader already started, don't restart.
return;
}
mStarted = true;
if (DEBUG) Log.v(TAG, " Starting: " + this);
if (mLoader == null && mCallbacks != null) {
//原来onCreateLoader这个回调方法 是在这里调用的 怪不得谷歌说这个方法是必定会被执行并且只会被执行一次的方法!
mLoader = mCallbacks.onCreateLoader(mId, mArgs);
}
if (mLoader != null) {
if (mLoader.getClass().isMemberClass()
&& !Modifier.isStatic(mLoader.getClass().getModifiers())) {
throw new IllegalArgumentException(
"Object returned from onCreateLoader must not be a non-static inner member class: "
+ mLoader);
}
if (!mListenerRegistered) {
mLoader.registerListener(mId, this);
mLoader.registerOnLoadCanceledListener(this);
mListenerRegistered = true;
}
//你看这里调用了startLoading方法 这个方法是属于mLoader的 跳转到88行
mLoader.startLoading();
}
}
//88- 98行是loader这个类里的
public final void startLoading() {
mStarted = true;
mReset = false;
mAbandoned = false;
onStartLoading();
}
//你看最终是调用的这个方法,注意他是空方法 是交给子类去实现的,我们去看看cursorloader这个子类是怎么实现的吧。
protected void onStartLoading() {
}
//99- 112行 是cursorLoader这个类的代码
//你看这个地方 直接调用了forceload方法 这个方法大家前面肯定有印象 他最终会启动那个asynctask 去执行background方法
//这也就解释了 第一次我们的数据是怎么来的,比如说 假设我们的数据源还没有被更新的时候,为什么会自动去查找数据源 并返回数据
//到这里就明白了,原来是activity的onStart函数为开端 一步步走到Loader的子类的onStartLoading方法里的,当然你如果觉得
//Loader不需要初始加载 只要在有变化的时候再加载 那这个方法你就可以保持为空了。
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
//114-139行 为 http://developer.android.com/intl/zh-cn/reference/android/content/AsyncTaskLoader.html 这个里面 AppListLoader 的一段源码
//你看138行 也是直接调用的forceLoad 这样当我们的applist没有变化的时候 第一次也能显示出列表
/**
* Handles a request to start the Loader.
*/
@Override protected void onStartLoading() {
if (mApps != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mApps);
}
// Start watching for changes in the app data.
if (mPackageObserver == null) {
mPackageObserver = new PackageIntentReceiver(this);
}
// Has something interesting in the configuration changed since we
// last built the app list?
boolean configChange = mLastConfig.applyNewConfig(getContext().getResources());
if (takeContentChanged() || mApps == null || configChange) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
onDestroy
/我们来看看fragment的onDestroy方法 都做了什么
public void onDestroy() {
mCalled = true;
//Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
// + " mLoaderManager=" + mLoaderManager);
if (!mCheckedForLoaderManager) {
mCheckedForLoaderManager = true;
mLoaderManager = mHost.getLoaderManager(mWho, mLoadersStarted, false);
}
if (mLoaderManager != null) {
//跳转到16行
mLoaderManager.doDestroy();
}
}
//上面的代码 是在fragment里 下面的代码在loadermanger里
void doDestroy() {
if (!mRetaining) {
if (DEBUG) Log.v(TAG, "Destroying Active in " + this);
for (int i = mLoaders.size()-1; i >= 0; i--) {
mLoaders.valueAt(i).destroy();
}
mLoaders.clear();
}
if (DEBUG) Log.v(TAG, "Destroying Inactive in " + this);
for (int i = mInactiveLoaders.size()-1; i >= 0; i--) {
mInactiveLoaders.valueAt(i).destroy();
}
mInactiveLoaders.clear();
}
//下面这个destroy流程 可以清晰的看到很多东西 包括clear所有回调等
void destroy() {
if (DEBUG) Log.v(TAG, " Destroying: " + this);
mDestroyed = true;
boolean needReset = mDeliveredData;
mDeliveredData = false;
if (mCallbacks != null && mLoader != null && mHaveData && needReset) {
if (DEBUG) Log.v(TAG, " Reseting: " + this);
String lastBecause = null;
if (mHost != null) {
lastBecause = mHost.mFragmentManager.mNoTransactionsBecause;
mHost.mFragmentManager.mNoTransactionsBecause = "onLoaderReset";
}
try {
mCallbacks.onLoaderReset(mLoader);
} finally {
if (mHost != null) {
mHost.mFragmentManager.mNoTransactionsBecause = lastBecause;
}
}
}
mCallbacks = null;
mData = null;
mHaveData = false;
if (mLoader != null) {
if (mListenerRegistered) {
mListenerRegistered = false;
mLoader.unregisterListener(this);
mLoader.unregisterOnLoadCanceledListener(this);
}
//在这调用了rest
mLoader.reset();
}
if (mPendingLoader != null) {
mPendingLoader.destroy();
}
}
//最后我们来看看loader里的代码 就能明白了 当fragement destroy的时候最终的调用来到了子类的onReset方法
public void reset() {
onReset();
mReset = true;
mStarted = false;
mAbandoned = false;
mContentChanged = false;
mProcessingChange = false;
}
/**
* Subclasses must implement this to take care of resetting their loader,
* as per {@link #reset()}. This is not called by clients directly,
* but as a result of a call to {@link #reset()}.
* This will always be called from the process's main thread.
*/
protected void onReset() {
}
//这里是cURSORLOADER的代码了 你看这里关闭了cursor
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
//同样的 我们也能看到applistloader源码里面 也是在这个函数里清除了广播接收器。
//所以读到这里 我们就知道 loader的强大了。你只需要搞清楚这些生命周期的函数的意义
//就可以重写他们,至于什么时候调用 loader都帮你做好了 你只需要在里面实现你自己的逻辑即可!非常强大 非常好用
@Override protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
// At this point we can release the resources associated with 'apps'
// if needed.
if (mApps != null) {
onReleaseResources(mApps);
mApps = null;
}
// Stop monitoring for changes.
if (mPackageObserver != null) {
getContext().unregisterReceiver(mPackageObserver);
mPackageObserver = null;
}
}
参考:
http://www.cnblogs.com/punkisnotdead/p/4861376.html
http://coderrobin.com/2015/02/05/Android-LoaderManager%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90/
网友评论