ViewStub 소스 코드 분석

6915 단어
할 일 없 이 ViewStub 소스 코드 를 한 번 보 았 습 니 다. 그 전에 대략적인 원 리 를 알 고 소스 코드 를 자세히 본 적 이 없습니다. 코드 는 조금 있 으 면 다 볼 수 있 고 300 줄 밖 에 없 었 습 니 다. 그리고 반 은 주석 이 었 습 니 다. 읽 고 얻 은 것 이 있 으 면 필 기 를 했 습 니 다.
환경.
  • Android Studio 1.5 Preview 2
  • Android SDK 23

  • 해석 하 다.
    먼저 ViewStub 의 멤버 변 수 를 살 펴 보 자.
    private int mInflatedId; //   xml   inflatedId
    private int mLayoutResource; //   xml   layout
    
    private WeakReference mInflatedViewRef; //       inflate     View
    
    private LayoutInflater mInflater;   //      
    private OnInflateListener mInflateListener; // inflate      
    

    그 다음은 구조 법.
    public ViewStub(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context);
    
        final TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.ViewStub, defStyleAttr, defStyleRes);
        //   xml   inflatedId  ,   mInflatedId
        mInflatedId = a.getResourceId(R.styleable.ViewStub_inflatedId, NO_ID);
        //   xml   layout  ,   layout
        mLayoutResource = a.getResourceId(R.styleable.ViewStub_layout, 0);
        //   xml    id  
        mID = a.getResourceId(R.styleable.ViewStub_id, NO_ID);
        a.recycle();
    
        //       
        setVisibility(GONE);
        //         ,    
        setWillNotDraw(true);
    }
    

    이 안 에는 세 가지 설명 할 곳 이 있다.
  • mIDViewStub 에서 정의 되 지 않 았 습 니 다. mIDView 에서 정의 되 었 고 mID 방문 장식 부 는 default 입 니 다. 즉, 같은 가방 에서 방문 할 수 있 습 니 다. 이 mID 은 바로 우리 가 자주 사용 하 는 Viewid 입 니 다. 보통 xml 에서 지정 합 니 다.ViewsetIdgetId 을 통 해서 도 조작 할 수 있다.그러나 ViewStubsetId 방법 으로 설정 하지 않 고 mID 에 게 직접 할당 하 는 것 이 시 끄 러 웠 다. 이것 은 ViewStubView 이 같은 가방 에 있 기 때문에 우리 가 직접 사용자 정의 View 을 쓰 면 이 일 을 할 수 없 기 때문에 당연히 반 사 를 통 해 할 수 있다.
  • setVisibility() 방법 은 ViewStub 에서 재 작성 되 었 는데 이 방법 은 비교적 관건 적 이 고 뒤에 말한다.
  • setWillNotDraw() 이 방법 은 View 에서 기본 값 은 false 이 고 ViewGroup 에서 기본 값 은 true 이 며 true 이 라면 ViewonDraw() 은 호출 되 지 않 아 성능 을 향상 시 킬 수 있다.
  • ViewStub 을 다시 써 서 View 을 그 리 는 방법 을 보 겠 습 니 다.
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //   xml       ,     0
        setMeasuredDimension(0, 0);
    }
    
    @Override
    public void draw(Canvas canvas) {
    }
    
    @Override
    protected void dispatchDraw(Canvas canvas) {
    }
    

    우 리 는 onMeasure 에서 너비 와 높이 를 모두 0 으로 설정 하 는 것 을 보 았 고 draw 관련 방법 은 모두 공 으로 이 루어 진 것 을 보 았 다. 이것 은 ViewStub 의 성능 이 좋 은 원인 으로 그 자신 이 존재 하지 않 는 것 과 같다 는 것 을 설명 했다.
    OK, ViewStub 의 진실 한 View 을 보 여 주 려 면 두 가지 방법 이 있다 는 것 을 알 고 있 습 니 다.
  • 호출 setVisibility()VISIBLE 또는 INVISIBLE
  • 으로 설정 합 니 다.
  • 호출 inflate() 방법
  • 첫 번 째 방법 부터 봅 시다.
    @Override
    public void setVisibility(int visibility) {
        if (mInflatedViewRef != null) {
            //     inflate ,  mInflatedViewRef  null
            View view = mInflatedViewRef.get();
            if (view != null) {
                view.setVisibility(visibility);
            } else {
                //            View    ,            View    
                throw new IllegalStateException("setVisibility called on un-referenced view");
            }
        } else {
            super.setVisibility(visibility);
            if (visibility == VISIBLE || visibility == INVISIBLE) {
                //       inflate ,      ,   inflate()  
                inflate();
            }
        }
    }
    

    우 리 는 setVisibility() 도 최종 적 으로 inflate() 방법 을 사용 한 것 을 발견 했다. 첫 번 째 mInflatedViewRefnull 이 라 고 생각 했다. 그러면 inflate() 방법의 현실 을 계속 보 자.
    public View inflate() {
        //   ViewStub parent,ViewStub      ,    inflate   View  parent  
        final ViewParent viewParent = getParent();
    
        if (viewParent != null && viewParent instanceof ViewGroup) {
            // mLayoutResource  xml   layout  
            if (mLayoutResource != 0) {
                final ViewGroup parent = (ViewGroup) viewParent;
                final LayoutInflater factory;
                if (mInflater != null) {
                    factory = mInflater;
                } else {
                    factory = LayoutInflater.from(mContext);
                }
                //   LayoutInflater xml    layout    
                final View view = factory.inflate(mLayoutResource, parent,
                        false);
    
                if (mInflatedId != NO_ID) {
                    //     View  id,  xml    inflatedId
                    view.setId(mInflatedId);
                }
    
                //   ViewStub parent     
                final int index = parent.indexOfChild(this);
                //    ViewStub parent    ,ViewStub          
                parent.removeViewInLayout(this);
    
                final ViewGroup.LayoutParams layoutParams = getLayoutParams();
                //        View  parent 
                if (layoutParams != null) {
                    //  ViewStub    layout     View
                    parent.addView(view, index, layoutParams);
                } else {
                    parent.addView(view, index);
                }
    
                //        View
                mInflatedViewRef = new WeakReference(view);
    
                //   infalte      ,listener    set    
                if (mInflateListener != null) {
                    mInflateListener.onInflate(this, view);
                }
    
                //      View
                return view;
            } else {
                throw new IllegalArgumentException("ViewStub must have a valid layoutResource");
            }
        } else {
            throw new IllegalStateException("ViewStub must have a non-null ViewGroup viewParent");
        }
    }
    

    코드 논 리 는 비교적 간단 하 다. 여기 서 우 리 는 ViewStub 이 제거 되 는 과정 을 주의해 보 자. parent.removeViewInLayout(View) 방법 을 호출 하 는데 우 리 는 평소에 removeView(View) 을 많이 사용 할 수 있다. 그러면 이 두 가지 방법 이 어떤 차이 가 있 는 지 직접 소스 코드 를 보면 알 수 있다.
    public void removeView(View view) {
        if (removeViewInternal(view)) {
            requestLayout();
            invalidate(true);
        }
    }
    
    public void removeViewInLayout(View view) {
        removeViewInternal(view);
    }
    
    removeView(View)layout 을 다시 시작 하 는 과정 을 일 으 킬 수 있 음 이 분명 하 다. 즉, View 이 화면 에 표시 되 어 있 으 면 우리 가 제거 하려 면 removeView(View) 을 호출 하여 페이지 를 새로 고침 하 는 것 이다. View 이 화면 에 표시 되 지 않 으 면 removeViewInLayout(View) 의 성능 을 호출 하여 불필요 한 재 그림 을 피 할 수 있다.ViewStub 은 좋 은 예 다.
    여기 서 ViewStub 의 소스 코드 를 분석 하 였 습 니 다.

    좋은 웹페이지 즐겨찾기