FragmentでgetContextで得たcontextはどこから来ますか?

5982 ワード

まずfragmentのgetContextメソッドを見てみましょう.
    @Nullable
    public Context getContext() {
        return mHost == null ? null : mHost.getContext();
    }

contextはmHostのgetContextメソッドで得られていることがわかりますが、Ctrl+左ボタンでmHostはFragmentHostCallbackクラスのオブジェクトであることがわかります.次にFragmentのmHostオブジェクトがどこで値を付けているかを知るだけでいいです.
我々のfragmentは一般的にfragmentManagerのbeginTransactionメソッドでFragmentTransactionを取得してaddを追加しますが、getSupportFragmentManagerで取得したのはFragmentManagerImpl、つまりFragmentManagerの実装クラス(後述)です.FragmentManagerImplのbeginTransactionメソッドを見てみましょう.
@Override
    public FragmentTransaction beginTransaction() {
        return new BackStackRecord(this);
    }

FragmentTransactionはFragmnetTransactionから継承されたBackStackRecordオブジェクトであり、BackStackRecordのaddメソッドは最終的にFragmentManagementのaddFragmentメソッドに戻ります(これはfragmentの起動プロセスに関連し、詳しくは説明しません):
public void addFragment(Fragment fragment, boolean moveToStateNow) {
       ...
            if (moveToStateNow) {
                moveToState(fragment);
}
void moveToState(Fragment f) {
        moveToState(f, mCurState, 0, 0, false);
}
void moveToState(Fragment f, int newState, int transit, int transitionStyle,
            boolean keepActive) {
...
switch (f.mState) {
                case Fragment.INITIALIZING:
                    ...
                        f.mHost = mHost;
                        f.mParentFragment = mParent;
                        f.mFragmentManager = mParent != null
                                ? mParent.mChildFragmentManager : mHost.getFragmentManagerImpl();

                       ...
                    }
}

f.mHost=mHost、つまりfragmentでcontextを取得する際に使用されるFragmentHostCallbackクラスのオブジェクトmHostがFragmentManagement Implによって付与されていることがわかります.
私たちの問題は、そのmHostはどこから来たのかということになりました.
fragmentManagerImplのattachControlメソッドを参照してください.
public void attachController(FragmentHostCallback host,
            FragmentContainer container, Fragment parent) {
        if (mHost != null) throw new IllegalStateException("Already attached");
        mHost = host;
        mContainer = container;
        mParent = parent;
}

mHostは、FragmentControllerによって呼び出される値をここに割り当てます.
public void attachHost(Fragment parent) {
        mHost.mFragmentManager.attachController(
                mHost, mHost /*container*/, parent);
    }

fragmentControllerは誰だ?そのmHostはどこから来たのですか?
Fragmentを追加するのは、一般的にgetSupportFragmentManager()を使用します.beginTransaction()FragmentTransactionオブジェクトを取得します.FragmentActivityのgetSupportFragmentManagerメソッドを見てみましょう.
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
...
    public FragmentManager getSupportFragmentManager() {
        return mFragments.getSupportFragmentManager();
    }

Activityは、finalタイプのFragmentControlオブジェクトのgetSupportFragmentManagerを使用してfragmentManagerを取得していることがわかります.
public class FragmentController {
    private final FragmentHostCallback> mHost;

    /**
     * Returns a {@link FragmentController}.
     */
    public static FragmentController createController(FragmentHostCallback> callbacks) {
        return new FragmentController(callbacks);
    }

    private FragmentController(FragmentHostCallback> callbacks) {
        mHost = callbacks;
    }

    /**
     * Returns a {@link FragmentManager} for this controller.
     */
    public FragmentManager getSupportFragmentManager() {
        return mHost.getFragmentManagerImpl();
    }
...
}

FragmentControllerのgetSupportFragmentManagerは、関数を構築するパラメータFragmentHostCallbackオブジェクトのgetFragmentMnaagerImlから得られます.
public abstract class FragmentHostCallback extends FragmentContainer {
    private final Activity mActivity;
    final Context mContext;
    private final Handler mHandler;
    final int mWindowAnimations;
    final FragmentManagerImpl mFragmentManager = new FragmentManagerImpl();
    ...
    FragmentManagerImpl getFragmentManagerImpl() {
        return mFragmentManager;
    }
}

FragmentManagerから継承されるFragmentManagerImplを直接返します.
元のfragmentManagerとそのmHostオブジェクトは、FragmentActivityのfragmentControlオブジェクトによって取得されていました.
ここで私たちの問題は、FragmentControllerのmHostはどこから来たのかということになりました.
FragmentActivityが伝えたものです
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());
    LoaderManager mLoaderManager;

HostCallbacksを見てみましょう
class HostCallbacks extends FragmentHostCallback {
        public HostCallbacks() {
            super(FragmentActivity.this /*fragmentActivity*/);
        }
}

HostCallbackは、FragmentHostCallbackのコンストラクション関数を呼び出す現在のactivityオブジェクトを持っていることがわかります.
public FragmentHostCallback(Context context, Handler handler, int windowAnimations) {
        this(context instanceof Activity ? (Activity) context : null, context, handler,
                windowAnimations);
    }

    FragmentHostCallback(FragmentActivity activity) {
        this(activity, activity /*context*/, activity.mHandler, 0 /*windowAnimations*/);
    }

    FragmentHostCallback(Activity activity, Context context, Handler handler,
            int windowAnimations) {
        mActivity = activity;
        mContext = context;
        mHandler = handler;
        mWindowAnimations = windowAnimations;
    }

すべてが水面に捧げられた.mHostのcontextはここにある.
まとめてみます.
FragmentActivityにはfinalタイプのFragmentControllerオブジェクトがあり、FragmentControllerはHostCallbackオブジェクトmHost(mHostはcontext)を持ち、FragmentManagerもそのmHostによって作成され、FragmentControllerがattachControllerメソッドを呼び出したときにそのmHostに値を付与し(FragmentManagerのmHostとFragmentControllerのmHostは同じ)、FragmentのmHostはaddのときにFragmentManagerによって値を付与される.
実はすべてのソースはFragmentActivityが持っているFragmentControllerオブジェクトです!
足指で考えてもfragmentのgetContextメソッドで手に入れたのがその付着したActivityかもしれませんが、書きました...
いいね!