findView ById()

3274 ワード

いらっしゃいませ。[Android日記][1]を転載したらAndroid日記を書いてください。http://androiddiary.site 2017.1.10火曜日晴臨沂
日記を書く
findView ByIdからは
三年前にandroidを勉強してからfindView ByIdを使い始めたのを覚えていますが、こんなに長く使っても彼の実現を具体的に分析したことがありません。
  • ActivityでfindView ById方法
  • を見つけました。
    /**
     * Finds a view that was identified by the id attribute from the XML that
     * was processed in {@link #onCreate}.
     *
     * @return The view if found or null otherwise.
     */
    public View findViewById(@IdRes int id) {
        return getWindow().findViewById(id);
    }
    
  • get Window:
  • public Window getWindow() {
        return mWindow;  
    }
    
    mwindowはprvate Windowです。Windowタイプの変数です。
  • WindowクラスのfindViewById方法
  • を見てください。
    /**
     * Finds a view that was identified by the id attribute from the XML that
     * was processed in {@link android.app.Activity#onCreate}.  This will
     * implicitly call {@link #getDecorView} for you, with all of the
     * associated side-effects.
     *
     * @return The view if found or null otherwise.
     */
    @Nullablepublic View findViewById(@IdRes int id) {
        return getDecorView().findViewById(id);
    }
    
  • は、get Decorview()がWindowの抽象的な方法であることを発見した。Windowの唯一のサブクラスはPhone Windowです。
  • Phone Windowでget Decorview()メソッド
  • を見つけました。
    @Override
    public final View getDecorView() {
        if (mDecor == null || mForceDecorInstall) {
            installDecor();
        }
        return mDecor;
    }
    
    mDecorはPhoneの内部タイプのDecorViewです。
    private final class DecorView extends FrameLayout implements RootViewSurfaceTaker 
    
    Frame Layoutを継承していますが、Frame LayoutはView Groupのサブクラスです。
  • 最終的に私達はViewの中で
  • を見つけました。
    /**
     * Look for a child view with the given id.  If this view has the given
     * id, return this view.
     *
     * @param id The id to search for.
     * @return The view that has the given id in the hierarchy or null
     */
    @Nullablepublic final View findViewById(@IdRes int id) {
        if (id < 0) {
            return null;
        }
        return findViewTraversal(id);
    }
    
    View類のfindView ByIdで呼び出したメソッドは、View Groupの中だけで書き換えられました。まずView Groupの実装を見てみます。(mDecorはView Groupのサブクラスなので、View Groupのメソッドを呼び出します。)
    @Override
    protected View findViewTraversal(@IdRes int id) {
        if (id == mID) {
            return this;
        }
        final View[] where = mChildren;
        final int len = mChildrenCount;
        for (int i = 0; i < len; i++) {
            View v = where[i];
            if ((v.mPrivateFlags & PFLAG_IS_ROOT_NAMESPACE) == 0) {
                v = v.findViewById(id);
                if (v != null) {
                    return v;
                }
            }
        }
        return null;
    }
    
    簡単に言えば、現在View Group(またはそのサブクラスの)mID==idがtrueであれば、Viewを探しています。同じでなければ、View Groupのサブビュー配列を遍歴して、サブビューで見つけたら戻ります。すべてのサブビューを遍歴した後、見つけられなかったらnullに戻ります。ここでの遍歴は木のようなものです。私たちはビューの中の実現を見ています。
    protected View findViewTraversal(@IdRes int id) {
        if (id == mID) {
            return this;
        }
        return null;
    }
    
    Viewは木の叶のノードに似ていて、それはサブレイアウト(ノード)がないので、彼の遍歴はとても简単で、idが等しいかどうかを简単に比较して、等しいです。
    簡単にまとめる
    findView ByIdを使うと、最終的にはView GroupのfindView Traversalを呼び出します。この方法はすべてのサブビューを遍歴して、再帰的なクエリを形成して、最終端を見つけます。見つけたらこのViewに戻り、検索を停止します。見つけられなかったらnullに戻ります。探しているViewがあるViewの中にあると確定した時、私達はそのView.findView ById()の方法を呼び出して、クエリの循環回数を減らして、効率を高めます。