fkm blog

software開発に関することを書いていきます

AndroidのLoaderのソースを読む(1)

LoaderManagerImplを読む. ここにいろいろ実装が入っているはず. LoaderManager.java内にあった.

class LoaderManagerImpl extends LoaderManager {
  LoaderManagerImpl(String who, FragmentActivity activity, boolean started) {
    mWho = who;
    mActivity = activity;
    mStarted = started;
  }
}

コンストラクタはただ貰った値をセットしているだけ.

class LoaderManagerImpl extends LoaderManager {
  @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;
  }
}

順に読んでみる.

LoaderInfo info = mLoaders.get(id);

引数に指定するidで, 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;
}

無ければ作る. あればcallbackを上書き.

作る部分はどうなってる?

class LoaderManagerImpl extends LoaderManager {
  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;
    }
  }
}

メソッド名のままだ. createLoader()は?

class LoaderManagerImpl extends LoaderManager {
  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;
  }
}

Loaderの情報をいれておくオブジェクトを作って, callbackの力を借りてloaderを作って返す. ここでcallbackのonCreateLoader()が呼ばれるんですな.

installってどういう意味だ?

class LoaderManagerImpl extends LoaderManager {
  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();
    }
  }
}

先ほどでてきたmapにいれる処理のことか. 既にLoaderが開始状態の場合は, info.start()を読んでる.

このinfo.start()とは?

final class LoaderInfo implements Loader.OnLoadCompleteListener<Object> {
  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();
    }
  }
}

開始している状態だったら何もしない. そうでなければ作ってstartLoading()を呼んでる. もし作り損ねても(=callbackのonCreateLoader()がnullを返しても)落ちたりはしなさそう.

public class Loader<D> {
  public final void startLoading() {
    mStarted = true;
    mReset = false;
    mAbandoned = false;
    onStartLoading();
  }
}

ここでLoaderのonStartLoading()が呼ばれるのか.

順に読むところから脱線したが, ようやく戻ってこれそう.

if (info.mHaveData && mStarted) {
  // If the loader has already generated its data, report it now.
  info.callOnLoadFinished(info.mLoader, info.mData);
}

開始状態で既にデータがある時は, 終了を通知.