編輯:關於Android編程
publicLoader initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks 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.LoaderCallbacksif (DEBUG) Log.v(TAG, " Created new loader " + info);} else {if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);info.mCallbacks = (LoaderManager.LoaderCallbacks}if (info.mHaveData && mStarted) {// If the loader has already generated its data, report it now.info.callOnLoadFinished(info.mLoader, info.mData);}return (Loader)info.mLoader; }
LoaderInfo聲明了Loader.OnLoadCompleteListener接口,並且保存了一個Loader的幾乎所有信息和狀態。
LoaderInfo的構造函數
public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacksmId = id;mArgs = args;mCallbacks = callbacks;}
createAndInstallLoader
private LoaderInfo createAndInstallLoader(int id, Bundle args,LoaderManager.LoaderCallbackstry {mCreatingLoader = true;LoaderInfo info = createLoader(id, args, callback);installLoader(info);return info;} finally {mCreatingLoader = false;}}
createLoader
private LoaderInfo createLoader(int id, Bundle args,LoaderManager.LoaderCallbacksLoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacksLoaderinfo.mLoader = (Loaderreturn info;}
通過調用callback的onCreateLoader接口創建Loader。這樣一個描述Loader的LoaderInfo就被成功創建了。完成了創建後,接下來是安裝。
installLoader
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 cycleinfo.start();}}
LoaderInfo的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);mListenerRegistered = true;}mLoader.startLoading();}}
Loader的startLoading()
public final void startLoading() {mStarted = true;mReset = false;mAbandoned = false;onStartLoading();}
會啟動Loader的onStartLoading,如果是復寫的Loader或者AsyncTaskLoader,就是執行到了這裡,是Loader在構造後執行的第一道工序。
在LoaderInfo中給Loader注冊了回調,回調就是LoaderInfo本身。下邊以AsyncTaskLoader為例進行分析。
AsyncTaskLoader繼承於Loader,同時其內部完成了一個AsyncTask。AsyncTaskLoader的抽象接口
public abstract D loadInBackground();
其實就是運行在其內部的AsyncTask中的doInBackground。
PS: 繼承於AsyncTaskLoader的Loader不會在構造後自動啟動,需要覆寫
onStartLoading中執行forceLoad,此Loader才會在onStartLoading的生命周期時正常啟動。
在其內部的AsyncTask完成後會在onPostExecute中調用AsyncTaskLoader的dispatchOnLoadComplete
void dispatchOnLoadComplete(LoadTask task, D data) {if (mTask != task) {if (DEBUG) Slog.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) Slog.v(TAG, "Delivering result");deliverResult(data);}}}
isAbandoned是Loader的方法,通過主動調用Loader的abandon()方法可以放棄這個Loader的執行結果,如果此Loader已經被放棄,那麼調用
public void onCanceled(D data)
處理被去掉的數據,AsyncTaskLoader中沒有做任何處理,留給繼承者自行決定是否處理
排除以上兩種異常情況,正常時會調用Loader的deliverResult處理數據結果。
public void deliverResult(D data) {if (mListener != null) {mListener.onLoadComplete(this, data);}}
之前分析過的LoaderInfo為自己的Loader注冊了監聽器,實現是自己,這下子數據就傳遞回去了:
@Override public void onLoadComplete(Loaderif (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 (mActivity != null && !hasRunningLoaders()) {mActivity.mFragments.startPendingDeferredFragments();}}
destroy()進行過銷毀,則不處理任何事情callOnLoadFinished對數據進行處理,這裡調用了回調函數callback中的onLoadFinishedActivity和Fragment都擁有getLoaderManager的方法,其實Fragment的getLoaderManager去獲取的就是Activity所管理的眾多LoaderManager之一。
先來看一下Activity的getLoaderManager方法:
LoaderManagerImpl getLoaderManager(String who, boolean started, boolean create) {if (mAllLoaderManagers == null) {mAllLoaderManagers = new ArrayMap(); }LoaderManagerImpl lm = mAllLoaderManagers.get(who);if (lm == null) {if (create) {lm = new LoaderManagerImpl(who, this, started);mAllLoaderManagers.put(who, lm);}} else {lm.updateActivity(this);}return lm;}
mAllLoaderManagers保存著一個Activity所擁有的所有LoaderManager,其key為String類型的who變量。若從Activity調用getLoaderManager,那麼所得LoaderManager的who標簽為(root):
public LoaderManager getLoaderManager() {if (mLoaderManager != null) {return mLoaderManager;}mCheckedForLoaderManager = true;mLoaderManager = getLoaderManager("(root)", mLoadersStarted, true);return mLoaderManager;}
若從Fragment中使用getLoaderManager,則所得LoaderManager的who標簽會根據Fragment的層級不同而不同,在Activity中處於最頂級的Fragment的who標簽為:
android:fragment:X
X為序號。
而屬於Fragment的Fragment所活的的LoaderManager who標簽就成為了:
android:fragment:X:Y
甚至更大的深度。
在開篇分析的時候分析過LoaderManager內部保存了一個mStarted狀態,很多操作會根據這個狀態做不同處理。通過上邊的分析也能看出,Fragment中獲取LoaderManager最終是通過Activity獲取的,在LoaderManager構造時,就將一個狀態量mLoadersStarted傳遞了進去,這個狀態量交給LoaderManager自行管理。
而無論是Fragment還是Activity,都有mLoadersStarted這樣一個狀態量,在onStart生命周期後為true,onStop後為false。所以在onStart生命周期後做initLoader操作就會使Loader一經初始化就開始運行了。
Fragment和Activity能夠對LoaderManager產生影響的生命周期是一樣的。
系統在onStart階段會獲取LoaderManager,如果成功獲取,則調用LoaderManager的doStart(),這裡需要特別說明的是,雖然所有LoaderManager都是保存在Activity中,但是在Activity的onStart生命周期其也只是會獲取屬於自己的(root)標簽LoaderManager,而並不是將所有保存在mAllLoaderManagers裡的Manager全部遍歷一遍。
處於onStop生命周期,但是系統內部是通過performStop調用的。在這裡,同樣會獲取屬於自己的LoaderManager,如果Activity是因為配置改變出發的onStop(旋轉屏幕),則調用LoaderManager的doRetain()接口,如果不是,就調用LoaderManager的doStop()接口。
調用LoaderManager的doDestroy()接口銷毀LoaderManager。
因為LoaderManager與Fragment/Activity的生命周期緊密相連,所以想要用好LoaderManager就必須了解其自身的生命周期,這樣就能把握數據的完整變化規律了。
正常的從出生到銷毀:
doStart() -> doReportStart() -> doStop() -> doDestroy()
Activity配置發生變化:
doStart() -> doRetain() -> finishRetain() -> doReportStart() -> doStart() -> doStop() -> doDestroy()
Fragment在onDestroyView()之後還會執行LoaderManager的doReportNextStart(), 即:
doStart() -> doRetain() -> doReportNextStart() -> finishRetain() -> doReportStart() -> doStart() -> doStop() -> doDestroy()
doStart()會將LoaderManager中保存的所有Loader都啟動。最終是運行每一個Loader的onStartLoading()方法。只要是通過initLoader使用過的Loader都會記錄在LoaderManager的mLoaders中,那麼問題來了:
怎樣在Fragment/Activity不銷毀的前提下從LoaderManager中移除某個使用過的Loader呢?
答案就是使用LoaderManager的接口去除指定ID的Loader:
public void destroyLoader(int id)
這樣就能在mLoaders中移除掉了,下次onStart的時候就沒有這個Loader什麼事了。
doReportStart()。如果Fragment上一次在銷毀並重做,而且數據有效的話會在這裡主動上報數據,最終走到callback的onLoadFinished中。doStop()會停止mLoaders保存的所有Loader。最終是運行每一個Loader的onStopLoading()方法。doDestroy()會清空所有有效和無效Loader,LoaderManager中不再存在任何Loader。doRetain()會將LoaderManager的mRetaining狀態置位true,並且保存retain時LoaderInfo的mStarted狀態finishRetain()如果之前所保存的mStarted與現在的不一樣而且新的狀態是停止的話,就停止掉這個Loader。否則若有數據並且不是要下次再上報(沒有call
doReportNextStart)的話就上報給callback的onLoadFinished。doReportNextStart(),根據第6條,已經能夠理解了。當Fragment執行到onDestroyView生命周期時,對自己的LoaderManager發出請求:即使現在有數據也不要進行上報,等我重做再到onStart生命周期時再給我。
在熟知了LoaderManager的梗概之後最後分析restartLoader就能夠更好理解了:
publicLoader restartLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback)
使用eclipse打包app以及AndroidStudio和Eclipse中app簽名修改等問題(SH1和MD5)
一,使用eclipse打包app內容新建keystore:1、先在eclipse中創建一個新的keystore看詳細圖2、接下來設置一些打包必要參數:3.設置好內容後點擊
Android網絡編程(十)Retrofit2後篇[請求參數]
前言在上一篇Android網絡編程(九)Retrofit2前篇[基本使用]中我們了解了Retrofit的最基本的GET方式訪問網絡的寫法以及請求參數的簡單介紹。這一篇我們
Android源碼分析(二):View的事件分發機制探析
Android應用開發時,自定義控件時少不了和View的觸摸點擊事件打交道。針對View的事件分發原理,也看過網上的一些博客,但是看歸看,看了之後時間一長就又忘記了,因此
詳解Android原生json和fastjson的簡單使用
android原生操作json數據主要是兩個類 JSONObject 操作對象 JONSArray操作json數組對象轉j