Android Loader
2015-12-09 00:35
866 查看
Introduced in Android 3.0, loaders make it easy to asynchronously load data in an activity or fragment. Loaders have these characteristics:
1、They are available to every Activity and Fragment. //支持Activity和Fragment
2、They provide asynchronous loading of data. //异步下载
3、They monitor the source of their data and deliver new results when the content changes. //当数据源改变时能及时通知客户端
4、They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data. //发生configuration change时自动重连接
用法相当简单,首先看一个例子
这里只是一个简单的从数据库,然后展示在listview上。
从代码上看来,通过实现LoaderManager.LoaderCallbacks就行了.
在onCreateLoader里面实现你要请求的耗时操作,当异步线程操作完成之后就会从onLoadFinished返回数据.
getLoaderManager 是获得一个LoaderManager 实例,但是LoaderManager
是一个抽象类,他的一个实例是LoaderManagerImpl是它的一个内部类
通过源码我们知道这里获取的其实就是LoaderManagerImpl实例
下面我们来看LoaderManager
的类结构
LoaderManagerImpl是LoaderManager的实现类,并且是LoaderManager的内部类,
LoaderInfo是LoaderManagerImpl的内部类,LoaderInfo类实现了Loader.OnLoadCompleteListener<Object>接口
LoaderManager.LoaderCallbacks<Cursor>
是LoaderManager的内部接口
这里为了方便说明略去了很多东西,但是并不会影响我们分析,其原理,我们这里只分析了第一次启用的情况,所以会忽略很多其他的东西,
首先
这是我们Loader的启动点。
前面我们从源码知道getLoaderManager其实就是获取一个LoaderManagerImpl的实例,所以这个initLoader方法也就是调用的此实例的方法
下面我们就来看一下LoaderManagerImpl的initLoader的方法的具体实现
如果我们传入的id对应的Loadinfo 不为,此时将传入的callback 赋值给空Loadinfo对应的成员变量 ,如果Loadinfo 有数据,此时
就会调用Loadinfo 的callOnLoadFinished方法
此方法最关键额一句
这一句代码就是将数据放回到实现了LoaderManager.LoaderCallbacks的Activity或者Fragment.在拿到数据后就可以更新UI了
下面再看Loadinfo
为空的情况
如果Loadinfo
为空了,此时会走这一句代码
下面我们看createAndInstallLoader方法
关键代码
createLoader()方法中的这一句代码,其实就是我们在Activity或者Fragment中实现LoaderManager.LoaderCallbacks的onCreateLoader方法
installLoader()方法首先是将我们创建的Loadinfo
添加到SparseArray的实例mLoaders中,然后回去调用Loadinfo 的start()方法
此方法首先做一些相关的检查工作,例如,Loader是不是静态的?是不是内部类的?当前Loader是否注册了回调事件,没注册会给其注册等。
最关键的一句是
这一句是我们的Loader要开始工作,我们先看Loader的类结构
LoadTask是AsyncTaskLoader的内部内,他是AsyncTask子类,所有异步操作有他完成
接下来我们进入Loader的startLoading()方法
发现onStartLoading()是一个空方法,那么我们找子类AsyncTaskLoader,发现AsyncTaskLoader未重写该方法
再去找CursorLoader,CursorLoader重写了onStartLoading(),如下
会触发Loader<D>.OnLoadCompleteListener<D>接口的
onLoadComplete(Loader<D> loader, D data)方法,LoadInfo类实现了他,这里效果和LoaderManagerImpl的initLoader的方法中info
不为空的情形一样 。
关键是forceLoad()(Loader中的实现)
发现onForceLoad
是一个空方法,
AsyncTaskLoader重写了此方法,CursorLoader未重写
此方法创建了一个LoadTask异步任务,并调用了executePendingTask()方法
此方法代码看的人头皮发麻啊,不过不要紧我们其他的不看,只看下面一句
也就是执行异步任务,
此时会调用LoadTask类的doInBackground()方法
doInBackground()方法中做的是在AsyncTaskLoader的onLoadInBackground()方法中,我们去看
loadInBackground()是一个抽象方法,CursorLoader实现了他,发现其实就是在查询数据库哦,哈哈哈。
当doInBackground()方法走完之后,就来到了方法。
下面这句是线程相关的东西,我们不需要关心,有兴趣可以百度一下。
我们找到AsyncTaskLoader的dispatchOnLoadComplete()方法
关键代码
我们看此方法的实现
mListener是 OnLoadCompleteListener<D>的实例,这个实例实在LoadInfo 的start()方法中赋值的,而LoadInfo 也实现了该接口,我们来看onLoadComplete()方法在LoadInfo中的实现
关键代码
这里又调用了callOnLoadFinished,
终于可已将获取的数据给实现了LoaderManager.LoaderCallbacks的Activity或者Fragment
下面的方法调用的时序图
1、They are available to every Activity and Fragment. //支持Activity和Fragment
2、They provide asynchronous loading of data. //异步下载
3、They monitor the source of their data and deliver new results when the content changes. //当数据源改变时能及时通知客户端
4、They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data. //发生configuration change时自动重连接
用法相当简单,首先看一个例子
public class CursorLoaderActivity extends Activity implements LoaderManager.LoaderCallbacks<Cursor> { ArrayList<Person> persons; Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); lv.setAdapter(new MyAdapter()); } }; Uri uri = Uri.parse("content://com.exanple.liaoli.db/person"); @Override protected void onResume() { super.onResume(); getLoaderManager().initLoader(0, null, this); } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(this,uri,null,null,null,null); } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { if(cursor == null){ return; } persons = new ArrayList<>(); while (cursor.moveToNext()){ String pName = cursor.getString(cursor.getColumnIndex("Name")); String pPhone = cursor.getString(cursor.getColumnIndex("phone")); int pCount = cursor.getInt(cursor.getColumnIndex("account")); String pSix = cursor.getString(cursor.getColumnIndex("six")); Person p = new Person(pName,pPhone,pCount,pSix); persons.add(p); } cursor.close(); Message.obtain(handler, 0).sendToTarget(); } @Override public void onLoaderReset(Loader<Cursor> loader) { } class MyAdapter extends BaseAdapter { @Override public int getCount() { return persons.size(); } @Override public Object getItem(int position) { return persons.get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { View v = null; if(convertView == null){ v = View.inflate(CursorLoaderActivity.this,R.layout.lv_item,null); }else{ v = convertView; } TextView name = (TextView) v.findViewById(R.id.name); TextView phone = (TextView) v.findViewById(R.id.phone); TextView count = (TextView) v.findViewById(R.id.count); TextView six= (TextView) v.findViewById(R.id.six); Person p = persons.get(position); name.setText(p.getName()); phone.setText(p.getPhone()); count.setText(p.getCount() + ""); six.setText(p.getSix()); return v; } } ListView lv; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_show_dbdate); lv = (ListView) findViewById(R.id.lv); }
这里只是一个简单的从数据库,然后展示在listview上。
从代码上看来,通过实现LoaderManager.LoaderCallbacks就行了.
在onCreateLoader里面实现你要请求的耗时操作,当异步线程操作完成之后就会从onLoadFinished返回数据.
getLoaderManager().initLoader(0, null, this);
getLoaderManager 是获得一个LoaderManager 实例,但是LoaderManager
是一个抽象类,他的一个实例是LoaderManagerImpl是它的一个内部类
通过源码我们知道这里获取的其实就是LoaderManagerImpl实例
LoaderManagerImpl getLoaderManagerImpl() { if (mLoaderManager != null) { return mLoaderManager; } mCheckedForLoaderManager = true; mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/); return mLoaderManager; }
下面我们来看LoaderManager
的类结构
LoaderManagerImpl是LoaderManager的实现类,并且是LoaderManager的内部类,
LoaderInfo是LoaderManagerImpl的内部类,LoaderInfo类实现了Loader.OnLoadCompleteListener<Object>接口
LoaderManager.LoaderCallbacks<Cursor>
是LoaderManager的内部接口
这里为了方便说明略去了很多东西,但是并不会影响我们分析,其原理,我们这里只分析了第一次启用的情况,所以会忽略很多其他的东西,
首先
getLoaderManager().initLoader(0, null, this);
这是我们Loader的启动点。
前面我们从源码知道getLoaderManager其实就是获取一个LoaderManagerImpl的实例,所以这个initLoader方法也就是调用的此实例的方法
下面我们就来看一下LoaderManagerImpl的initLoader的方法的具体实现
/** * 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. * * <p>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 {@link Activity} is re-created after a configuration change it * does not need to re-create its loaders. * * <p>Note that in the case where an existing Loader is re-used, the * <var>args</var> given here <em>will be ignored</em> because you will * continue using the previous Loader. * * @param id A unique (to this LoaderManager instance) identifier under * which to manage the new Loader. * @param args Optional arguments that will be propagated to * {@link LoaderCallbacks#onCreateLoader(int, Bundle) LoaderCallbacks.onCreateLoader()}. * @param callback Interface implementing management of this Loader. Required. * Its onCreateLoader() method will be called while inside of the function to * instantiate the Loader object. */ @SuppressWarnings("unchecked") public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) { if (mCreatingLoader) { throw new IllegalStateException("Called while creating a 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; }
如果我们传入的id对应的Loadinfo 不为,此时将传入的callback 赋值给空Loadinfo对应的成员变量 ,如果Loadinfo 有数据,此时
就会调用Loadinfo 的callOnLoadFinished方法
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)); mCallbacks.onLoadFinished(loader, data); } finally { if (mHost != null) { mHost.mFragmentManager.mNoTransactionsBecause = lastBecause; } } mDeliveredData = true; } }
此方法最关键额一句
mCallbacks.onLoadFinished(loader, data);
这一句代码就是将数据放回到实现了LoaderManager.LoaderCallbacks的Activity或者Fragment.在拿到数据后就可以更新UI了
下面再看Loadinfo
为空的情况
如果Loadinfo
为空了,此时会走这一句代码
info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks<Object>)callback);
下面我们看createAndInstallLoader方法
private LoaderInfo createLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<Object> callback) { LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks<Object>)callback); Loader<Object> loader = callback.onCreateLoader(id, args); info.mLoader = (Loader<Object>)loader; return info; } 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; } } void installLoader(LoaderInfo info) { mLoaders.put(info.mId, info); if (mStarted) { // The activity will start all existing loaders in it's onStart(), // so only start them here if we're past that point of the activitiy's // life cycle info.start(); } }
关键代码
Loader<Object> loader = callback.onCreateLoader(id, args);
createLoader()方法中的这一句代码,其实就是我们在Activity或者Fragment中实现LoaderManager.LoaderCallbacks的onCreateLoader方法
installLoader()方法首先是将我们创建的Loadinfo
添加到SparseArray的实例mLoaders中,然后回去调用Loadinfo 的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) { 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; } mLoader.startLoading(); } }
此方法首先做一些相关的检查工作,例如,Loader是不是静态的?是不是内部类的?当前Loader是否注册了回调事件,没注册会给其注册等。
最关键的一句是
mLoader.startLoading();
这一句是我们的Loader要开始工作,我们先看Loader的类结构
LoadTask是AsyncTaskLoader的内部内,他是AsyncTask子类,所有异步操作有他完成
接下来我们进入Loader的startLoading()方法
public final void startLoading() { mStarted = true; mReset = false; mAbandoned = false; onStartLoading(); } /** * Subclasses must implement this to take care of loading their data, * as per {@link #startLoading()}. This is not called by clients directly, * but as a result of a call to {@link #startLoading()}. */ protected void onStartLoading() { }
发现onStartLoading()是一个空方法,那么我们找子类AsyncTaskLoader,发现AsyncTaskLoader未重写该方法
再去找CursorLoader,CursorLoader重写了onStartLoading(),如下
@Override protected void onStartLoading() { if (mCursor != null) { deliverResult(mCursor); } if (takeContentChanged() || mCursor == null) { forceLoad(); } }
deliverResult(mCursor);
会触发Loader<D>.OnLoadCompleteListener<D>接口的
onLoadComplete(Loader<D> loader, D data)方法,LoadInfo类实现了他,这里效果和LoaderManagerImpl的initLoader的方法中info
不为空的情形一样 。
关键是forceLoad()(Loader中的实现)
public void forceLoad() { onForceLoad(); }
发现onForceLoad
是一个空方法,
protected void onForceLoad() { }
AsyncTaskLoader重写了此方法,CursorLoader未重写
@Override protected void onForceLoad() { super.onForceLoad(); cancelLoad(); mTask = new LoadTask(); if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask); executePendingTask(); }
此方法创建了一个LoadTask异步任务,并调用了executePendingTask()方法
void executePendingTask() { if (mCancellingTask == null && mTask != null) { if (mTask.waiting) { mTask.waiting = false; mHandler.removeCallbacks(mTask); } if (mUpdateThrottle > 0) { long now = SystemClock.uptimeMillis(); if (now < (mLastLoadCompleteTime+mUpdateThrottle)) { // Not yet time to do another load. if (DEBUG) Log.v(TAG, "Waiting until " + (mLastLoadCompleteTime+mUpdateThrottle) + " to execute: " + mTask); mTask.waiting = true; mHandler.postAtTime(mTask, mLastLoadCompleteTime+mUpdateThrottle); return; } } if (DEBUG) Log.v(TAG, "Executing: " + mTask); mTask.executeOnExecutor(mExecutor, (Void[]) null); } }
此方法代码看的人头皮发麻啊,不过不要紧我们其他的不看,只看下面一句
mTask.executeOnExecutor(mExecutor, (Void[]) null);
也就是执行异步任务,
此时会调用LoadTask类的doInBackground()方法
@Override protected D doInBackground(Void... params) { if (DEBUG) Log.v(TAG, this + " >>> doInBackground"); try { 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; } }
doInBackground()方法中做的是在AsyncTaskLoader的onLoadInBackground()方法中,我们去看
protected D onLoadInBackground() { return loadInBackground(); }public abstract D loadInBackground();
loadInBackground()是一个抽象方法,CursorLoader实现了他,发现其实就是在查询数据库哦,哈哈哈。
@Override public Cursor loadInBackground() { synchronized (this) { if (isLoadInBackgroundCanceled()) { throw new OperationCanceledException(); } mCancellationSignal = new CancellationSignal(); } try { Cursor cursor = getContext().getContentResolver().query(mUri, mProjection, mSelection, mSelectionArgs, mSortOrder, mCancellationSignal); if (cursor != null) { try { // Ensure the cursor window is filled. cursor.getCount(); cursor.registerContentObserver(mObserver); } catch (RuntimeException ex) { cursor.close(); throw ex; } } return cursor; } finally { synchronized (this) { mCancellationSignal = null; } } }
当doInBackground()方法走完之后,就来到了方法。
/* Runs on the UI thread */ @Override protected void onPostExecute(D data) { if (DEBUG) Log.v(TAG, this + " onPostExecute"); try { AsyncTaskLoader.this.dispatchOnLoadComplete(this, data); } finally { mDone.countDown(); } }
下面这句是线程相关的东西,我们不需要关心,有兴趣可以百度一下。
mDone.countDown();
我们找到AsyncTaskLoader的dispatchOnLoadComplete()方法
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); } } }
关键代码
deliverResult(data);
我们看此方法的实现
public void deliverResult(D data) { if (mListener != null) { mListener.onLoadComplete(this, data); } }
mListener是 OnLoadCompleteListener<D>的实例,这个实例实在LoadInfo 的start()方法中赋值的,而LoadInfo 也实现了该接口,我们来看onLoadComplete()方法在LoadInfo中的实现
@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) { 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(); }
关键代码
callOnLoadFinished(loader, data);
这里又调用了callOnLoadFinished,
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)); mCallbacks.onLoadFinished(loader, data); } finally { if (mHost != null) { mHost.mFragmentManager.mNoTransactionsBecause = lastBecause; } } mDeliveredData = true; } }
终于可已将获取的数据给实现了LoaderManager.LoaderCallbacks的Activity或者Fragment
mCallbacks.onLoadFinished(loader, data);
下面的方法调用的时序图
相关文章推荐
- As3.0 xml + Loader应用代码
- 基于jquery的lazy loader插件实现图片的延迟加载[简单使用]
- AS3.0 实例学习 熟悉addChild和removeChild在不同的swf之间的运用,以及loader的用法
- 借用Google的Javascript API Loader来加速你的网站
- ioncube_loader_win_5.2.dll的错误解决方法
- Windows下的PHP 5.3.x安装 Zend Guard Loader教程
- PHP5.3安装Zend Guard Loader图文教程
- android CursorLoader用法介绍
- 使用 angular-async-loader 来实现异步加载 angular 模块
- JS文件装载器(Eve Js Loader)
- Oracle sql loader的应用(二)
- Oracle sql loader的应用(一)
- Oracle sql loader的基本概念
- flash as3 加载外部swf jpg gif png loader urlloader的通用代码
- Loader,AsyncTaskLoader,CursorLoader,LoaderManager 相关
- Loader,AsyncTaskLoader,CursorLoader,LoaderManager 相关
- qml之Loader使用
- AsyncTasLoader不进行加载操作的原因及解决方法
- 使用Universal-Image-Loader加载系统图片并点击放大显示
- Android Loader学习