Android 소스 읽기, View 그리기 프로세스 분석

10211 단어
1. View의 그리기 프로세스는 어디에서 시작되었습니까?
준비 지식:Activity의 시작 프로세스View의 그리기 입구는ActivityThread의handle ResumeActivity에서 볼 수 있습니다.
final void handleResumeActivity(IBinder token,
        boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
    ActivityClientRecord r = mActivities.get(token);

    //              onReStart onStart  onResume    
    r = performResumeActivity(token, clearHide, reason);

    if (r != null) {
        final Activity a = r.activity;
    
        if (r.window == null && !a.mFinished && willBeVisible) {
            r.window = r.activity.getWindow();
            View decor = r.window.getDecorView();
            decor.setVisibility(View.INVISIBLE);
            ViewManager wm = a.getWindowManager();
            WindowManager.LayoutParams l = r.window.getAttributes();
            a.mDecor = decor;
            l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
            l.softInputMode |= forwardBit;
            // ....      
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    //    View    ViewManager--》WindowManager--》WindowManagerImpl(     )
                    // View             
                    wm.addView(decor, l);
                } 
            } 
        }          
    } 
}

4
  • View의 드로잉 프로세스는 ViewManager에서 수행됩니다.addView(View view, View Group. Layout Params params)라는 방법으로 시작합니다

  • 2. ViewManager 클래스는 어디에서 생성됩니까?
    1. ViewManager wm = a.getWindowManager();      Activity   
    
    public WindowManager getWindowManager() {
        return mWindowManager;
    }
    
    // mWindowManager   attch       
    final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback) {
        attachBaseContext(context);
    
        mFragments.attachHost(null /*parent*/);
    
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        //            
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        //       ,      WindowManagerImpl   
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    
        mWindow.setColorMode(info.colorMode);
    }
    
    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        mHardwareAccelerated = hardwareAccelerated
                || SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        if (wm == null) {
          //  ViewManager        ,        :WindowManager
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        // WindowManagerImpl    new   
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
    
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }
    

    클래스 관계: 클래스 윈도 관리자 Impl은 윈도 관리자 인터페이스를 실현하고 윈도 관리자 인터페이스는 ViewManager 인터페이스를 계승한다.
    3. WindowManagerImpl 클래스,addView 코드 보기
    public final class WindowManagerImpl implements WindowManager {
        private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
        private final Context mContext;
        private final Window mParentWindow;
    
        private IBinder mDefaultToken;
    
    
        private WindowManagerImpl(Context context, Window parentWindow) {
            mContext = context;
            mParentWindow = parentWindow;
        }
        public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
            return new WindowManagerImpl(mContext, parentWindow);
        }
    
        
        @Override
        public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            //      WindowManagerGlobal.addView  
            mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
        }
    
        @Override
        public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
            applyDefaultToken(params);
            mGlobal.updateViewLayout(view, params);
        }
    
        
        @Override
        public void removeView(View view) {
            mGlobal.removeView(view, false);
        }
    
        @Override
        public void removeViewImmediate(View view) {
            mGlobal.removeView(view, true);
        }
    
        @Override
        public void requestAppKeyboardShortcuts(
                final KeyboardShortcutsReceiver receiver, int deviceId) {
            IResultReceiver resultReceiver = new IResultReceiver.Stub() {
                @Override
                public void send(int resultCode, Bundle resultData) throws RemoteException {
                    List result =
                            resultData.getParcelableArrayList(PARCEL_KEY_SHORTCUTS_ARRAY);
                    receiver.onKeyboardShortcutsReceived(result);
                }
            };
            try {
                WindowManagerGlobal.getWindowManagerService()
                    .requestAppKeyboardShortcuts(resultReceiver, deviceId);
            } catch (RemoteException e) {
            }
        }
    
        @Override
        public Display getDefaultDisplay() {
            return mContext.getDisplay();
        }
    }
    

    넷째, 윈도우 관리자 글로벌 클래스,addView 코드 보기
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        // ViewRootImpl    ViewParent     
        ViewRootImpl root;
        View panelParentView = null;
    
        synchronized (mLock) {
           
            //   ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);
    
            view.setLayoutParams(wparams);
            //        
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
    
            // do this last because it fires off messages to start doing things
            try {
                // View         
                root.setView(view, wparams, panelParentView);
            } catch (RuntimeException e) {
                // BadTokenException or InvalidDisplayException, clean up.
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
                throw e;
            }
        }
    }
    

    5. ViewRootImpl 클래스, setView 코드 보기
    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
    
                //    N   
    
                //     ,    
                requestLayout();
                
                //    N   
                
            }
        }
    }
    
    @Override
    public void requestLayout() {
        if (!mHandlingLayoutInLayoutRequest) {
            //   UI  ,       View     。
            checkThread();
            mLayoutRequested = true;
            //        
            scheduleTraversals();
        }
    }
    
    void scheduleTraversals() {
        if (!mTraversalScheduled) {
            mTraversalScheduled = true;
            mTraversalBarrier = mHandler.getLooper().getQueue().postSyncBarrier();
            //     Handler      mTraversalRunnable  。
            //        mTraversalRunnable   Runnable   run()  
            mChoreographer.postCallback(
                    Choreographer.CALLBACK_TRAVERSAL, mTraversalRunnable, null);
            if (!mUnbufferedInputDispatch) {
                scheduleConsumeBatchedInput();
            }
            notifyRendererOfFramePending();
            pokeDrawLockIfNeeded();
        }
    }
    

    6. TraversalRunnable 클래스,run () 코드 보기
    final TraversalRunnable mTraversalRunnable = new TraversalRunnable();
    final class TraversalRunnable implements Runnable {
        @Override
        public void run() {
            //     ViewRootImpl  doTraversal()
            doTraversal();
        }
    }
     // ViewRootImpl      
    void doTraversal() {
        if (mTraversalScheduled) {
            mTraversalScheduled = false;
            mHandler.getLooper().getQueue().removeSyncBarrier(mTraversalBarrier);
    
            if (mProfile) {
                Debug.startMethodTracing("ViewAncestor");
            }
            // View   、  、       
            performTraversals();
    
            if (mProfile) {
                Debug.stopMethodTracing();
                mProfile = false;
            }
        }
    }
      // ViewRootImpl      
    private void performTraversals() {
       
        // ...  N   
    
        //   View
        performMeasure(childWidthMeasureSpec, childHeightMeasureSpec);
        //   View
        performLayout(lp, mWidth, mHeight);
        //   View
        performDraw();
        
        // ...  N   
    }
    

    7.perform Measure,perform Layout,perform Draw 세 가지 방법을 총괄
    1. perform Measure(child Width Measure Spec,child Height Measure Spec) --> mView.measure(childWidthMeasureSpec, childHeightMeasureSpec) --> onMeasure(widthMeasureSpec, heightMeasureSpec);
    1. performMeasure                  。
    2.   ViewGrop,       View   ,     View               。
    3.   View,       View             。
    

    2. perform Layout(lp, mWidth, mHeight) -->> host.layout(0, 0, host.getMeasuredWidth(), host.getMeasuredHeight()); -->> onLayout(changed, l, t, r, b);
    1.        。
    2.   ViewGrop,   View,     View  child.layout(l,t,r,b)     View。
    3.   View    。
    

    3. performDraw()-->drawSoftware()-->mView.draw(canvas); --> drawBackground(canvas);-->onDraw(canvas);--> dispatchDraw(canvas);--> onDrawForeground(canvas);
    1.         View
    2.           ,   View  ViewGrop         。
    3.   ViewGrop,   dispatchDraw  ,          View draw()  ,    View。
    4.   View,    onDraw(canvas)     。
    

    좋은 웹페이지 즐겨찾기