Android应用Loaders浅析

本文转载地址:Android应用Loaders全面详解及源码浅析

本文是对上述内容的总结。

流程

当需要使用loader时,需要获取activity或fragment中的loaderManager并启动loader。

getLoaderManager().initLoader(1, null, new LoaderManager.LoaderCallbacks<Cursor>() {
            @Override
            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                return null;
            }

            @Override
            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
            }

            @Override
            public void onLoaderReset(Loader<Cursor> loader) {
            }
        });

进入getLoaderManager中,一直到最后

LoaderManagerImpl getLoaderManagerImpl() {
        if (mLoaderManager != null) {
            return mLoaderManager;
        }
        mCheckedForLoaderManager = true;
        mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true /*create*/);
        return mLoaderManager;
    }

可以发现每个activity都只会有一个LoaderManager,该LoaderManager通过getLoaderManager方法创建。

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;
}

传入三个参数,其中who为在该LoaderManager在mAllLoaderManagers列表中对应的key,create为true时创建LoaderManager。

获取LoaderManager后,需要调用其initLoader方法。

public <D> Loader<D> initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks<D> callback) {
    if (mCreatingLoader) {
        throw new IllegalStateException("Called while creating a loader");
    }
    //从列表中取出对应id的loader。loaderInfo中封装了一个loader
    LoaderInfo info = mLoaders.get(id);

    if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
    //如果为空则创建loader
    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;
    }
    //已有数据,调用callOnLoadFinished方法
    if (info.mHaveData && mStarted) {
        info.callOnLoadFinished(info.mLoader, info.mData);
    }
    return (Loader<D>)info.mLoader;
}
//创建和初始化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;
    }
}
//创建loader
private LoaderInfo createLoader(int id, Bundle args,
        LoaderManager.LoaderCallbacks<Object> callback) {
    LoaderInfo info = new LoaderInfo(id, args,  (LoaderManager.LoaderCallbacks<Object>)callback);
   //关键点,获取在onCreateLoader方法中,用户创建的Loader
    Loader<Object> loader = callback.onCreateLoader(id, args);
    info.mLoader = (Loader<Object>)loader;
    return info;
}
void installLoader(LoaderInfo info) {
    //放入列表中
    mLoaders.put(info.mId, info);
    if (mStarted) {
        info.start();
    }
}

在initLoader中主要是创建了一个Loader(该Loader是在onCreateLoader中创建的Loader),并用LoaderInfo进行了封装。在方法的最后调用了LoaderInfo的start()方法。

void start() {
            。。。
            mStarted = true;
            if (mLoader == null && mCallbacks != null) {
               mLoader = mCallbacks.onCreateLoader(mId, mArgs);
            }
            if (mLoader != null) {
                。。。
                if (!mListenerRegistered) {
                    mLoader.registerListener(mId, this);
                    mLoader.registerOnLoadCanceledListener(this);
                    mListenerRegistered = true;
                }
                mLoader.startLoading();
            }
        }

该方法主要是注册监听事件及调用Loader的StartLoading()方法,实际上调用了Loader的onStartLoading()方法,该方法内部为空,在自定义Loader时实现。

以CursorLoader为例,在CursorLoader中找到onStartLoading()方法:

protected void onStartLoading() {
        if (mCursor != null) {
            deliverResult(mCursor);
        }
        if (takeContentChanged() || mCursor == null) {
            forceLoad();
        }
    }

初始化时,mCursor为空,进入forceLoad()方法中:

 public void forceLoad() {
        onForceLoad();
    }

再进入onForceLoad()中,发现方法为空,其具体实现在AsyncTaskLoader中:

 protected void onForceLoad() {
        super.onForceLoad();
        cancelLoad();
        //新建task
        mTask = new LoadTask();
        if (DEBUG) Log.v(TAG, "Preparing load: mTask=" + mTask);
        executePendingTask();
    }

进入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);
        }
    }

executePendingTask首先判断了任务是否正在运行,如果正在运行则停止,之后又判断是否设置了更新时间,最后就是真正的触发执行AsyncTask方法executeOnExecutor。该方法会执行对应的任务mTask。
接着进入LoaderTask的都InBackground中:

 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()) {
                    throw ex;
                }
                if (DEBUG) Log.v(TAG, this + "  <<< doInBackground (was canceled)", ex);
                return null;
            }
        }

在该方法中最关键是调用了onLoadInBackground(),在onLoadInBackground()方法中调用了loadInBackground(),该方法在自定义Loader中实现去获取相应的数据。

在CursorLoader中:

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;
            }
        }
    }

可以看到,在CursorLoader中,获取了相应cursor。即从对应的数据库中获取到了数据。获取数据后将数据返回。

 @Override
        protected void onPostExecute(D data) {
            if (DEBUG) Log.v(TAG, this + " onPostExecute");
            try {
                AsyncTaskLoader.this.dispatchOnLoadComplete(this, data);
            } finally {
                mDone.countDown();
            }
        }

进入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方法。该方法需要在子类中被实现。
CursorLoader中的delverResult:

public void deliverResult(Cursor cursor) {
        if (isReset()) {
            if (cursor != null) {
                cursor.close();
            }
            return;
        }
        Cursor oldCursor = mCursor;
        mCursor = cursor;

        if (isStarted()) {
            super.deliverResult(cursor);
        }

        if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
            oldCursor.close();
        }
    }
public void deliverResult(D data) {
        if (mListener != null) {
            mListener.onLoadComplete(this, data);
        }
    }

onLoadComplete的具体实现在LoaderInfo类中:

  @Override
        public void onLoadComplete(Loader<Object> loader, Object data) {
           。。。
            if (mData != data || !mHaveData) {
                mData = data;
                mHaveData = true;
                if (mStarted) {
                    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;
            }
        }

可以看见,在该方法中调用了onLoadFinished方法。在onLoadFinished方法中,根据新获得的数据更新容器。至此,执行initLoader的过程结束,相应容器获得数据并进行相应操作。

CursorLoader在loadInBackground中注册了一各观察者cursor.registerContentObserver(mObserver);其中mObserver为Loader定义的ForceLoadContentObserver类,该类继承自ContentObserver,因此当数据库中数据发生变化后,会调用ForceLoadContentObserver的onChange方法。

@Override
        public void onChange(boolean selfChange) {
            onContentChanged();
        }
public void onContentChanged() {
        if (mStarted) {
            **forceLoad();**
        } else {
            mContentChanged = true;
        }
    }

每当数据库中发生变化,都会调用forceLoad方法,每当调用forceLoad方法将重新执行上述操作。

小结

1.当执行initLoader方法后,首先会调用对应Loader的onStartLoading()方法,该方法中需要调用forceLoad()方法。
2.forceLoad方法会开启一个线程用于执行对应的任务,即在LoadTask中的doInBackground执行对应Loader的loadInBackground方法,在该方法中实现数据的获取。
3.获取数据后将调用子类的deliverResult方法,该方法中更新数据并最终调用回调方法onLoadComplete,从而执行onLoadFinished,最终在onLoadFinished中实现容器的数据更新。
4.当数据发生变化时,只需调用forceLoad即可再次执行上述操作。如在cursorLoader中通过注册观察者,当数据库中发生变化,执行对应的onChange方法,从而调用forceLoad方法进行更新。

题外话:

看源码是一件很痛苦的事情,Android应用Loaders全面详解及源码浅析看了两天也只是似懂非懂的样子,后来干脆直接从流程来看源码,抛弃一些看的不是很明白的部分,只看整个流程。虽然没把所有的源码看懂,但至少了解了大概的实现方式。因此本篇文章只是对Loader进行简单的认识,想看详细的可以参考Android应用Loaders全面详解及源码浅析

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值