안 드 로 이 드 - 소스 코드 - LayoutInflater (1)

7459 단어
다음 절: 안 드 로 이 드 - 소스 분석 - Layout Inflater (2)
먼저 Layout Inflater 의 설명 을 살 펴 보 겠 습 니 다.
/**
 * LayoutInflater       xml         View  
 *           ,          :
 * Activity.getLayoutInflater / Context.getSystemService
 *      ,            LayoutInflater  。
 * 
 *     View      Factory       LayoutInflater,
 *   cloneInContext    LayoutInflater,  ,
 *   setFactory     Factory   LayoutInflater 。
 * 
 *       ,View          xml      ,
 *     LayoutInflater               xml。
 */

클래스 설명 은 우리 에 게 세 가 지 를 명확 하 게 해 주 었 다.

  • 이 종 류 를 직접 만 들 지 말고 Layout Inflater 대상 을 지정 한 방법 으로 가 져 와 야 합 니 다.

  • Factory 를 통 해 LayoutInflater 의 충전 과정 을 사용자 정의 할 수 있 습 니 다.LayoutInflater 를 복사 하고 Factory 를 다시 설정 할 수 있 습 니 다.

  • LayoutInflater 는 컴 파일 된 xml 레이아웃 파일 만 해석 할 수 있 습 니 다.
    그 중에서 모든 지 정 된 방법 은 최종 적 으로 Context. getSystemService 를 통 해 이 루어 집 니 다.
    /*
     *    :
     * getWindow().getLayoutInflater()
     * getWindow()    Activity mWindow  :
     * mWindow = new PhoneWindow(this, window);
     *     PhoneWindow.getLayoutInflater(),   :
     * mLayoutInflater = LayoutInflater.from(context);
     */
    Activity.getLayoutInflater();
    
    /*
     *     :
     * LayoutInflater factory = LayoutInflater.from(context);
     * return factory.inflate(resource, root);
     */
    View.inflate(Context context, @LayoutRes int resource, ViewGroup root);
    
    /*
     *     :
     * LayoutInflater LayoutInflater = (LayoutInflater) context
     *         .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
     */
    LayoutInflater.from(context);
    

    그리고 내부 의 몇 개의 인터페이스 와 대상 을 다시 봅 시다.
    private boolean mFactorySet;       //     setFactory
    private Factory mFactory;          //  Factory   
    private Factory2 mFactory2;        //  Factory2   
    private Factory2 mPrivateFactory;  //        
    private Filter mFilter;            //   
    
    /*
     *    
     *       View       ,    InflateException  
     */
    public interface Filter {
        boolean onLoadClass(Class clazz);
    }
    
    /*
     * Factory
     * 3      :
     * name    :     Tag  , View  ;
     * context :View        ;
     * attrs   :View xml        ,
     *       View ,   View    null。
     */
    public interface Factory {
        public View onCreateView(String name, Context context, AttributeSet attrs);
    } 
    
    /*
     * Factory2
     *   onCreateView,   ViewParent  。
     */
    public interface Factory2 extends Factory {
        public View onCreateView(View parent, String name,
                                 Context context, AttributeSet attrs);
    }
    

    필터 필터: setFilter 방법 을 통 해 LayoutInflater 에 사용자 정의 필 터 를 설정 할 수 있 습 니 다.
    /*
     *  LayoutInflater     ,   View        ,
     *       inflate       InflateException,
     *     filter           filter。
     */
    public void setFilter(Filter filter) {
        mFilter = filter;
        if (filter != null) 
            mFilterMap = new HashMap();
    }
    

    Filter 를 새로 설정 하면 오래된 Filter 를 덮어 쓰 고 mFilterMap 을 다시 초기 화 합 니 다.mFilterMap 의 역할: Filter 가 서로 다른 View 에 대한 필터 결 과 를 기록 하고 View 가 필터 에 들 어 갈 때 mFilterMap 을 우선 찾 아 Filter 가 중복 사용 되 지 않도록 합 니 다.
    Filter 의 호출 과정 은 뒤의 분석 과정 에서 분 석 될 것 입 니 다.
    Factory: Factory 에 대해 서 는 채 워 야 할 View 를 사용자 정의 할 수 있 습 니 다.Factory 인터페이스 에서 방법 매개 변 수 는 name, context, attrs 가 있 고 Factory 2 는 parent 매개 변 수 를 추가 하 는 과부하 가 하나 더 있 습 니 다.관심 을 가 져 야 할 매개 변 수 는: name 과 attrs:

  • name: xml 의 태그 이름 에 대응 하 는 View 의 클래스 이름 을 채 워 야 합 니 다.예 를 들 어 TextView.이 클래스 이름 에 따라 사용자 정의 View 를 만 들 수 있 습 니 다. 해당 하 는 View 를 만 들 수도 있 고 다른 View 를 만 들 수도 있 습 니 다.예 를 들 어 AppCompatActivity 에서 TextView 를 처리 하면 TextView 가 아 닌 AppCompatTextView 로 돌아 갑 니 다.

  • attrs: View 속성 은 이 속성 을 수정 할 수 있 습 니 다. 예 를 들 어 새로운 속성 을 추가 하고 기 존 속성 을 수정 하 는 등 입 니 다.attrs 수정 을 통 해 쉽게 스킨 케 어 기능 을 만 들 수 있 습 니 다.
    setFactory 방법 을 사용 하여 LayoutInflater 에 사용자 정의 Factory 를 추가 합 니 다.
    /*
     *    LayoutInflater      Factory       View     ,
     *   Factory     null,       ,          ,
     *    xml       ,   View ,Factory    ,
     *   Factory    View,  View           ,
     *      ,        onCreateView    View。
     */
    public void setFactory(Factory factory) {
        //         ,         
        if (mFactorySet) 
            throw new IllegalStateException("A factory has already "
                + "been set on this LayoutInflater");
        if (factory == null) 
            throw new NullPointerException("Given factory can not be null");
    
        // mFactorySet   false,   mFactorySet  true
        //     setFactory        
        mFactorySet = true;
        
        //      LayoutInflater  mFactory
        //       mFactory,      
        if (mFactory == null) 
            mFactory = factory;
        else
            mFactory = new FactoryMerger(factory, null, mFactory, mFactory2);
    }
    

    setFactory 2 를 사용 하여 Factory 2 대상 을 설정 할 수도 있 습 니 다.setFactory 2 는 setFactory 방법 과 같 지만 Factory 2 를 mFactory 와 mFactory 2 로 설정 합 니 다.
    public void setFactory2(Factory2 factory) {
        ...
        if (mFactory == null) {
            mFactory = mFactory2 = factory;
        } else {
            mFactory = mFactory2 = new FactoryMerger(factory, factory, mFactory, mFactory2);
        }
    }
    

    위 에 Factory Merger 류 가 언급 되 어 있 습 니 다.
    private static class FactoryMerger implements Factory2 {
        private final Factory mF1, mF2;
        private final Factory2 mF12, mF22;
            
        FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
            mF1 = f1; mF2 = f2; mF12 = f12; mF22 = f22;
        }
            
        public View onCreateView(String name, Context context, AttributeSet attrs) {
            View v = mF1.onCreateView(name, context, attrs);
            if (v != null) return v;
            return mF2.onCreateView(name, context, attrs);
        }
    
        public View onCreateView(View parent, String name, 
                                 Context context, AttributeSet attrs) {
            View v = mF12 != null ? 
                        mF12.onCreateView(parent, name, context, attrs) :
                        mF1.onCreateView(name, context, attrs);
            if (v != null) return v;
            return mF22 != null ? 
                       mF22.onCreateView(parent, name, context, attrs) : 
                       mF2.onCreateView(name, context, attrs);
        }
    }
    

    이 종 류 는 Factory 2 인 터 페 이 스 를 실현 했다. 즉, Factory 의 실현 류 이다. 그 역할 은 사실은 이전 Factory 를 기본 View 로 만 드 는 방법 으로 유지 하 는 것 이다.예 를 들 어 현재 Layout Inflater 가 있 습 니 다.
    LayoutInflater inflater;
    inflater.setFactory((name, context, attrs) -> {
        if(TextUtils.equals(name, TextView.class.getSimpleName()))
            return new EditText(context,attrs);
        return null;
    })
    

    이때 EditView 를 처리 하고 원래 Factory 행 위 를 유지 하 는 새로운 Layout Inflater 를 얻 고 싶 습 니 다.
    //      LayoutInflater
    LayoutInflater newInflater = inflater.cloneInContext(context); 
    newInflater.setFactory((name, context, attrs) -> {
        if(TextUtils.equals(name, EditText.class.getSimpleName()))
            return new TextView(context,attrs);
        return null;
    })
    

    new Inflater 에 Factory 가 존재 하기 때문에 setFactory 는 Factory Merger 대상 을 만 들 것 입 니 다.
    public void setFactory(Factory factory) {
        if (mFactory == null) 
            mFactory = factory;
        else
            mFactory = new FactoryMerger(factory, null, mFactory, mFactory2);
    }
    

    EditText 를 채 울 때 새 Factory 는 TextView 대상 을 되 돌려 줍 니 다.TextView 를 채 울 때 null 로 돌아 갑 니 다. 이 때 는 기 존의 Factory 를 호출 하여 해석 합 니 다. 즉, EditText 대상 을 되 돌려 줍 니 다.
    나머지 분석 은 다음 절 에 놓 여 있다. 안 드 로 이 드 - 소스 코드 분석 - Layout Inflater (2)

    좋은 웹페이지 즐겨찾기