Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android應用開發:LoaderManager在Activity/Fragment中的使用分析

Android應用開發:LoaderManager在Activity/Fragment中的使用分析

編輯:關於Android編程

LoaderManager

外部接口initLoader:起始

  1. public Loader initLoader(int id, Bundle args, LoaderManager.LoaderCallbacks callback) {
  2. if (mCreatingLoader) {
  3. throw new IllegalStateException("Called while creating a loader");
  4. }
  5. LoaderInfo info = mLoaders.get(id);
  6. if (DEBUG) Log.v(TAG, "initLoader in " + this + ": args=" + args);
  7. if (info == null) {
  8. // Loader doesn't already exist; create.
  9. info = createAndInstallLoader(id, args, (LoaderManager.LoaderCallbacks)callback);
  10. if (DEBUG) Log.v(TAG, " Created new loader " + info);
  11. } else {
  12. if (DEBUG) Log.v(TAG, " Re-using existing loader " + info);
  13. info.mCallbacks = (LoaderManager.LoaderCallbacks)callback;
  14. }
  15. if (info.mHaveData && mStarted) {
  16. // If the loader has already generated its data, report it now.
  17. info.callOnLoadFinished(info.mLoader, info.mData);
  18. }
  19. return (Loader)info.mLoader;
  20. }
    1. mCreatingLoader代表當前LoaderManager正處於創建Loader的狀態,這個時候進入initLoader屬於沖突。
    2. LoaderInfo為LoaderManager內部保存Loader信息的一個類,mLoaders保存了此LoaderManager加載過的Loader,需要注意:一個ID對應一個Loader。
    3. info獲取不到,說明這次是一個新的Loader進來,需要通過createAndInstallLoader進行創建和安裝,參數即為initLoader的參數。
    4. 如果獲取到了info,說明這是一個已經存在過的Loader,只需要重新對callback回調進行重新賦值即可。
    5. 若獲取到的Loader已經開始,並且產生了有效數據,則執行LoaderInfo的callOnLoadFinished方法上報數據。
    6. 最終返回LoaderInfo中的Loader信息。

      LoaderInfo聲明了Loader.OnLoadCompleteListener接口,並且保存了一個Loader的幾乎所有信息和狀態。

      LoaderInfo的構造函數

      1. public LoaderInfo(int id, Bundle args, LoaderManager.LoaderCallbacks callbacks) {
      2. mId = id;
      3. mArgs = args;
      4. mCallbacks = callbacks;
      5. }

        createAndInstallLoader

        1. private LoaderInfo createAndInstallLoader(int id, Bundle args,
        2. LoaderManager.LoaderCallbacks callback) {
        3. try {
        4. mCreatingLoader = true;
        5. LoaderInfo info = createLoader(id, args, callback);
        6. installLoader(info);
        7. return info;
        8. } finally {
        9. mCreatingLoader = false;
        10. }
        11. }

          createLoader

          1. private LoaderInfo createLoader(int id, Bundle args,
          2. LoaderManager.LoaderCallbacks callback) {
          3. LoaderInfo info = new LoaderInfo(id, args, (LoaderManager.LoaderCallbacks)callback);
          4. Loader loader = callback.onCreateLoader(id, args);
          5. info.mLoader = (Loader)loader;
          6. return info;
          7. }

            通過調用callback的onCreateLoader接口創建Loader。這樣一個描述Loader的LoaderInfo就被成功創建了。完成了創建後,接下來是安裝。

            installLoader

            1. void installLoader(LoaderInfo info) {
            2. mLoaders.put(info.mId, info);
            3. if (mStarted) {
            4. // The activity will start all existing loaders in it's onStart(),
            5. // so only start them here if we're past that point of the activitiy's
            6. // life cycle
            7. info.start();
            8. }
            9. }
            1. 將新的Loader裝進mLoaders保存,凡是通過此LoaderManager管理過的Loader都會有記錄的
            2. 即使是在Fragment中使用LoaderManager,其獲取方式也是通過Fragment附屬的Activity獲取,而mStarted狀態量與Activity的生命周期onStart/onStop有關。稍後做詳細分析。
            3. 若Activity的生命周期處於onStart和onStop中,則開啟Loader。

              LoaderInfo的start()

              1. void start() {
              2. if (mRetaining && mRetainingStarted) {
              3. // Our owner is started, but we were being retained from a
              4. // previous instance in the started state... so there is really
              5. // nothing to do here, since the loaders are still started.
              6. mStarted = true;
              7. return;
              8. }
              9. if (mStarted) {
              10. // If loader already started, don't restart.
              11. return;
              12. }
              13. mStarted = true;
              14. if (DEBUG) Log.v(TAG, " Starting: " + this);
              15. if (mLoader == null && mCallbacks != null) {
              16. mLoader = mCallbacks.onCreateLoader(mId, mArgs);
              17. }
              18. if (mLoader != null) {
              19. if (mLoader.getClass().isMemberClass()
              20. && !Modifier.isStatic(mLoader.getClass().getModifiers())) {
              21. throw new IllegalArgumentException(
              22. "Object returned from onCreateLoader must not be a non-static inner member class: "
              23. + mLoader);
              24. }
              25. if (!mListenerRegistered) {
              26. mLoader.registerListener(mId, this);
              27. mListenerRegistered = true;
              28. }
              29. mLoader.startLoading();
              30. }
              31. }
              1. 如果Loader還處於上一個的開始狀態中,就不做任何事情
              2. 如果已經開始了,不要重啟
              3. 若Loader為null,則調用callback的接口再創建一個
              4. 注冊Loader的監聽器,以id為唯一標識
              5. 啟動Loader

                Loader的startLoading()

                1. public final void startLoading() {
                2. mStarted = true;
                3. mReset = false;
                4. mAbandoned = false;
                5. onStartLoading();
                6. }

                會啟動Loader的onStartLoading,如果是復寫的Loader或者AsyncTaskLoader,就是執行到了這裡,是Loader在構造後執行的第一道工序。

                關於結果數據的Loader回調

                在LoaderInfo中給Loader注冊了回調,回調就是LoaderInfo本身。下邊以AsyncTaskLoader為例進行分析。

                AsyncTaskLoader繼承於Loader,同時其內部完成了一個AsyncTask。AsyncTaskLoader的抽象接口

                1. public abstract D loadInBackground();

                其實就是運行在其內部的AsyncTask中的doInBackground。

                PS: 繼承於AsyncTaskLoader的Loader不會在構造後自動啟動,需要覆寫onStartLoading中執行forceLoad,此Loader才會在onStartLoading的生命周期時正常啟動。

                在其內部的AsyncTask完成後會在onPostExecute中調用AsyncTaskLoader的dispatchOnLoadComplete

                1. void dispatchOnLoadComplete(LoadTask task, D data) {
                2. if (mTask != task) {
                3. if (DEBUG) Slog.v(TAG, "Load complete of old task, trying to cancel");
                4. dispatchOnCancelled(task, data);
                5. } else {
                6. if (isAbandoned()) {
                7. // This cursor has been abandoned; just cancel the new data.
                8. onCanceled(data);
                9. } else {
                10. commitContentChanged();
                11. mLastLoadCompleteTime = SystemClock.uptimeMillis();
                12. mTask = null;
                13. if (DEBUG) Slog.v(TAG, "Delivering result");
                14. deliverResult(data);
                15. }
                16. }
                17. }