1. 程式人生 > >Activity的onAttachedToWindow和onDetachedFromWindow呼叫時機原始碼解析

Activity的onAttachedToWindow和onDetachedFromWindow呼叫時機原始碼解析

先上測試程式碼:

MyView.java

[java] view plain copy print?
  1. import android.content.Context;  
  2. import android.util.AttributeSet;  
  3. import android.util.Log;  
  4. import android.widget.TextView;  
  5. publicclass MyView extends TextView {  
  6.     public MyView(Context context) {  
  7.         super(context);  
  8.     }  
  9.     public MyView(Context context, AttributeSet attrs) {  
  10.         super(context, attrs);  
  11.         Log.e(”test”,“view constructor”);  
  12.     }  
  13.     @Override
  14.     protectedvoid onAttachedToWindow() {  
  15.         super.onAttachedToWindow();  
  16.         Log.e(”test”“onAttachedToWindow”);  
  17.     }  
  18.     @Override
  19.     protectedvoid onDetachedFromWindow() {  
  20.         super.onDetachedFromWindow();  
  21.         Log.e(”test”“onDetachedFromWindow”);  
  22.     }  
  23. }  
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.TextView;

public class MyView extends TextView {
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        Log.e("test","view constructor");
    }

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        Log.e("test", "onAttachedToWindow");
    }

    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        Log.e("test", "onDetachedFromWindow");
    }
}

MainActivity.java

[java] view plain copy print?
  1. import android.support.v7.app.AppCompatActivity;  
  2. import android.os.Bundle;  
  3. import android.util.Log;  
  4. publicclass MainActivity extends AppCompatActivity {  
  5.     @Override
  6.     protectedvoid onCreate(Bundle savedInstanceState) {  
  7.         super.onCreate(savedInstanceState);  
  8.         Log.e(”test”“before setContextView”);  
  9.         setContentView(R.layout.activity_main);  
  10.         Log.e(”test”“after setContextView”);  
  11.     }  
  12.     @Override
  13.     protectedvoid onResume() {  
  14.         super.onResume();  
  15.         Log.e(”test”“onResume”);  
  16.     }  
  17.     @Override
  18.     protectedvoid onDestroy() {  
  19.         super.onDestroy();  
  20.         Log.e(”test”“onDestroy”);  
  21.     }  
  22. }  
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.e("test", "before setContextView");
        setContentView(R.layout.activity_main);
        Log.e("test", "after setContextView");
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e("test", "onResume");
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        Log.e("test", "onDestroy");
    }
}
執行後輸出的Log如下:

執行Log
點選返回鍵退出後,輸出的Log如下:

退出後輸出的Log

根據Log的onAttachedToWindow和onDetachedFromWindow的輸出情況一目瞭然。

下面通過原始碼分析下,他兩的呼叫時機到底在哪。

首先看下onAttachedToWindow的呼叫時機,在Android原始碼中onResume呼叫前會先呼叫了ActivityThread中的handleResumeActivity,下面是相應的程式碼:

ActivityThread.java

[java] view plain copy print?
  1. finalvoid handleResumeActivity(IBinder token,  
  2.             boolean clearHide, boolean isForward, boolean reallyResume) {  
  3.         // If we are getting ready to gc after going to the background, well
  4.         // we are back active so skip it.
  5.         unscheduleGcIdler();  
  6.         mSomeActivitiesChanged = true;  
  7.         // TODO Push resumeArgs into the activity for consideration
  8.         ActivityClientRecord r = performResumeActivity(token, clearHide);  
  9.         if (r != null) {  
  10.             final Activity a = r.activity;  
  11.             if (localLOGV) Slog.v(  
  12.                 TAG, ”Resume ” + r + “ started activity: ” +  
  13.                 a.mStartedActivity + ”, hideForNow: ” + r.hideForNow  
  14.                 + ”, finished: ” + a.mFinished);  
  15.             finalint forwardBit = isForward ?  
  16.                     WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;  
  17.             // If the window hasn’t yet been added to the window manager,
  18.             // and this guy didn’t finish itself or start another activity,
  19.             // then go ahead and add the window.
  20.             boolean willBeVisible = !a.mStartedActivity;  
  21.             if (!willBeVisible) {  
  22.                 try {  
  23.                     willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(  
  24.                             a.getActivityToken());  
  25.                 } catch (RemoteException e) {  
  26.                 }  
  27.             }  
  28.             if (r.window == null && !a.mFinished && willBeVisible) {  
  29.                 r.window = r.activity.getWindow();  
  30.                 View decor = r.window.getDecorView();  
  31.                 decor.setVisibility(View.INVISIBLE);  
  32.                 ViewManager wm = a.getWindowManager();  
  33.                 WindowManager.LayoutParams l = r.window.getAttributes();  
  34.                 a.mDecor = decor;  
  35.                 l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;  
  36.                 l.softInputMode |= forwardBit;  
  37.                 if (a.mVisibleFromClient) {  
  38.                     a.mWindowAdded = true;  
  39.                     wm.addView(decor, l);//這裡呼叫了ViewManager中的addView方法。
  40.                 }  
  41.             // If the window has already been added, but during resume
  42.             // we started another activity, then don’t yet make the
  43.             // window visible.
  44.             } elseif (!willBeVisible) {  
  45.                 if (localLOGV) Slog.v(  
  46.                     TAG, ”Launch ” + r + “ mStartedActivity set”);  
  47.                 r.hideForNow = true;  
  48.             }  
  49.             // Get rid of anything left hanging around.
  50.             cleanUpPendingRemoveWindows(r);  
  51.             // The window is now visible if it has been added, we are not
  52.             // simply finishing, and we are not starting another activity.
  53.             if (!r.activity.mFinished && willBeVisible  
  54.                     && r.activity.mDecor != null && !r.hideForNow) {  
  55.                 if (r.newConfig != null) {  
  56.                     r.tmpConfig.setTo(r.newConfig);  
  57.                     if (r.overrideConfig != null) {  
  58.                         r.tmpConfig.updateFrom(r.overrideConfig);  
  59.                     }  
  60.                     if (DEBUG_CONFIGURATION) Slog.v(TAG, “Resuming activity ”
  61.                             + r.activityInfo.name + ” with newConfig ” + r.tmpConfig);  
  62.                     performConfigurationChanged(r.activity, r.tmpConfig);  
  63.                     freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));  
  64.                     r.newConfig = null;  
  65.                 }  
  66.                 if (localLOGV) Slog.v(TAG, “Resuming ” + r + “ with isForward=”
  67.                         + isForward);  
  68.                 WindowManager.LayoutParams l = r.window.getAttributes();  
  69.                 if ((l.softInputMode  
  70.                         & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)  
  71.                         != forwardBit) {  
  72.                     l.softInputMode = (l.softInputMode  
  73.                             & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))  
  74.                             | forwardBit;  
  75.                     if (r.activity.mVisibleFromClient) {  
  76.                         ViewManager wm = a.getWindowManager();  
  77.                         View decor = r.window.getDecorView();  
  78.                         wm.updateViewLayout(decor, l);  
  79.                     }  
  80.                 }  
  81.                 r.activity.mVisibleFromServer = true;  
  82.                 mNumVisibleActivities++;  
  83.                 if (r.activity.mVisibleFromClient) {  
  84.                     r.activity.makeVisible();  
  85.                 }  
  86.             }  
  87.             ….  
  88.     }  
final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        unscheduleGcIdler();
        mSomeActivitiesChanged = true;

        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            final Activity a = r.activity;

            if (localLOGV) Slog.v(
                TAG, "Resume " + r + " started activity: " +
                a.mStartedActivity + ", hideForNow: " + r.hideForNow
                + ", finished: " + a.mFinished);

            final int forwardBit = isForward ?
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION : 0;

            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.
            boolean willBeVisible = !a.mStartedActivity;
            if (!willBeVisible) {
                try {
                    willBeVisible = ActivityManagerNative.getDefault().willActivityBeVisible(
                            a.getActivityToken());
                } catch (RemoteException e) {
                }
            }
            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) {
                    a.mWindowAdded = true;
                    wm.addView(decor, l);//這裡呼叫了ViewManager中的addView方法。
                }

            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            } else if (!willBeVisible) {
                if (localLOGV) Slog.v(
                    TAG, "Launch " + r + " mStartedActivity set");
                r.hideForNow = true;
            }

            // Get rid of anything left hanging around.
            cleanUpPendingRemoveWindows(r);

            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                if (r.newConfig != null) {
                    r.tmpConfig.setTo(r.newConfig);
                    if (r.overrideConfig != null) {
                        r.tmpConfig.updateFrom(r.overrideConfig);
                    }
                    if (DEBUG_CONFIGURATION) Slog.v(TAG, "Resuming activity "
                            + r.activityInfo.name + " with newConfig " + r.tmpConfig);
                    performConfigurationChanged(r.activity, r.tmpConfig);
                    freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig));
                    r.newConfig = null;
                }
                if (localLOGV) Slog.v(TAG, "Resuming " + r + " with isForward="
                        + isForward);
                WindowManager.LayoutParams l = r.window.getAttributes();
                if ((l.softInputMode
                        & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION)
                        != forwardBit) {
                    l.softInputMode = (l.softInputMode
                            & (~WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION))
                            | forwardBit;
                    if (r.activity.mVisibleFromClient) {
                        ViewManager wm = a.getWindowManager();
                        View decor = r.window.getDecorView();
                        wm.updateViewLayout(decor, l);
                    }
                }
                r.activity.mVisibleFromServer = true;
                mNumVisibleActivities++;
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }
            ....
    }
看程式碼中的wm.addView(devor,l);通過該方法將View新增到Window當中(在當前Window也就是Activity,不過Window也可以是Dialog或Toast),而wm是ViewManager型別的,檢視對應程式碼是:[java] view plain copy print?
  1. package android.view;  
  2. /** Interface to let you add and remove child views to an Activity. To get an instance 
  3.   * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}. 
  4.   */
  5. publicinterface ViewManager  
  6. {  
  7.     /** 
  8.      * Assign the passed LayoutParams to the passed View and add the view to the window. 
  9.      * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming 
  10.      * errors, such as adding a second view to a window without removing the first view. 
  11.      * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a 
  12.      * secondary {@link Display} and the specified display can’t be found 
  13.      * (see {@link android.app.Presentation}). 
  14.      * @param view The view to be added to this window. 
  15.      * @param params The LayoutParams to assign to view. 
  16.      */
  17.     publicvoid addView(View view, ViewGroup.LayoutParams params);  
  18.     publicvoid updateViewLayout(View view, ViewGroup.LayoutParams params);  
  19.     publicvoid removeView(View view);  
  20. }  
package android.view;

/** Interface to let you add and remove child views to an Activity. To get an instance
  * of this class, call {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
  */
public interface ViewManager
{
    /**
     * Assign the passed LayoutParams to the passed View and add the view to the window.
     * <p>Throws {@link android.view.WindowManager.BadTokenException} for certain programming
     * errors, such as adding a second view to a window without removing the first view.
     * <p>Throws {@link android.view.WindowManager.InvalidDisplayException} if the window is on a
     * secondary {@link Display} and the specified display can't be found
     * (see {@link android.app.Presentation}).
     * @param view The view to be added to this window.
     * @param params The LayoutParams to assign to view.
     */
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}
該類是一個介面,在他下面還有一個WindowManager繼承於ViewManager,而真正的實現程式碼在WindowManagerImpl類中,程式碼如下:

WindowManagerImpl.java

[java] view plain copy print?
  1. /* 
  2. * @see WindowManager 
  3. * @see WindowManagerGlobal 
  4. * @hide 
  5. */
  6. ublic finalclass WindowManagerImpl implements WindowManager {  
  7.    privatefinal WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();  
  8.    privatefinal Display mDisplay;  
  9.    privatefinal Window mParentWindow;  
  10.    private IBinder mDefaultToken;  
  11.    public WindowManagerImpl(Display display) {  
  12.        this(display, null);  
  13.    }  
  14.    private WindowManagerImpl(Display display, Window parentWindow) {  
  15.        mDisplay = display;  
  16.        mParentWindow = parentWindow;  
  17.    }  
  18.    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {  
  19.        returnnew WindowManagerImpl(mDisplay, parentWindow);  
  20.    }  
  21.    public WindowManagerImpl createPresentationWindowManager(Display display) {  
  22.        returnnew WindowManagerImpl(display, mParentWindow);  
  23.    }  
  24.    /** 
  25.     * Sets the window token to assign when none is specified by the client or 
  26.     * available from the parent window. 
  27.     * 
  28.     * @param token The default token to assign. 
  29.     */
  30.    publicvoid setDefaultToken(IBinder token) {  
  31.        mDefaultToken = token;  
  32.    }  
  33.    @Override
  34.    publicvoid addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {  
  35.        applyDefaultToken(params);  
  36.        mGlobal.addView(view, params, mDisplay, mParentWindow);  
  37.    }  
  38.    @Override
  39.    publicvoid updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {  
  40.        applyDefaultToken(params);  
  41.        mGlobal.updateViewLayout(view, params);  
  42.    }  
  43.    privatevoid applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {  
  44.        // Only use the default token if we don’t have a parent window.
  45.        if (mDefaultToken != null && mParentWindow == null) {  
  46.            if (!(params instanceof WindowManager.LayoutParams)) {  
  47.                thrownew IllegalArgumentException(“Params must be WindowManager.LayoutParams”);  
  48.            }  
  49.            // Only use the default token if we don’t already have a token.
  50.            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;  
  51.            if (wparams.token == null) {  
  52.                wparams.token = mDefaultToken;  
  53.            }  
  54.        }  
  55.    }  
  56.    @Override
  57.    publicvoid removeView(View view) {  
  58.        mGlobal.removeView(view, false);  
  59.    }  
  60.    @Override
  61.    publicvoid removeViewImmediate(View view) {  
  62.        mGlobal.removeView(view, true);  
  63.    }  
  64.    @Override
  65.    public Display getDefaultDisplay() {  
  66.        return mDisplay;  
  67.    }  
 /*
 * @see WindowManager
 * @see WindowManagerGlobal
 * @hide
 */
public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;

    private IBinder mDefaultToken;

    public WindowManagerImpl(Display display) {
        this(display, null);
    }

    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }

    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

    public WindowManagerImpl createPresentationWindowManager(Display display) {
        return new WindowManagerImpl(display, mParentWindow);
    }

    /**
     * Sets the window token to assign when none is specified by the client or
     * available from the parent window.
     *
     * @param token The default token to assign.
     */
    public void setDefaultToken(IBinder token) {
        mDefaultToken = token;
    }

    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }

    @Override
    public void updateViewLayout(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        mGlobal.updateViewLayout(view, params);
    }

    private void applyDefaultToken(@NonNull ViewGroup.LayoutParams params) {
        // Only use the default token if we don't have a parent window.
        if (mDefaultToken != null && mParentWindow == null) {
            if (!(params instanceof WindowManager.LayoutParams)) {
                throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
            }

            // Only use the default token if we don't already have a token.
            final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
            if (wparams.token == null) {
                wparams.token = mDefaultToken;
            }
        }
    }

    @Override
    public void removeView(View view) {
        mGlobal.removeView(view, false);
    }

    @Override
    public void removeViewImmediate(View view) {
        mGlobal.removeView(view, true);
    }

    @Override
    public Display getDefaultDisplay() {
        return mDisplay;
    }
}
[java] view plain copy print?

從中可以看到addView又呼叫了 WindowManagerGlobal.java類中的addView,下面看看WindowManagerGlobal.java類的原始碼:

WindowManagerGlobal.java

[java] view plain copy print?
  1. publicvoid addView(View view, ViewGroup.LayoutParams params,  
  2.         Display display, Window parentWindow) {  
  3.     if (view == null) {  
  4.         thrownew IllegalArgumentException(“view must not be null”);  
  5.     }  
  6.     if (display == null) {  
  7.         thrownew IllegalArgumentException(“display must not be null”);  
  8.     }  
  9.     if (!(params instanceof WindowManager.LayoutParams)) {  
  10.         thrownew IllegalArgumentException(“Params must be WindowManager.LayoutParams”);  
  11.     }  
  12.     final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;  
  13.     if (parentWindow != null) {  
  14.         parentWindow.adjustLayoutParamsForSubWindow(wparams);  
  15.     } else {  
  16.         // If there’s no parent, then hardware acceleration for this view is
  17.         // set from the application’s hardware acceleration setting.
  18.         final Context context = view.getContext();  
  19.         if (context != null
  20.                 && (context.getApplicationInfo().flags  
  21.                         & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {  
  22.             wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;  
  23.         }  
  24.     }  
  25.     ViewRootImpl root;  
  26.     View panelParentView = null;  
  27.     synchronized (mLock) {  
  28.         // Start watching for system property changes.
  29.         if (mSystemPropertyUpdater == null) {  
  30.             mSystemPropertyUpdater = new Runnable() {  
  31.                 @Overridepublicvoid run() {  
  32.                     synchronized (mLock) {  
  33.                         for (int i = mRoots.size() - 1; i >= 0; –i) {  
  34.                             mRoots.get(i).loadSystemProperties();  
  35.                         }  
  36.                     }  
  37.                 }  
  38.             };  
  39.             SystemProperties.addChangeCallback(mSystemPropertyUpdater);  
  40.         }  
  41.         int index = findViewLocked(view, false);  
  42.         if (index >= 0) {  
  43.             if (mDyingViews.contains(view)) {  
  44.                 // Don’t wait for MSG_DIE to make it’s way through root’s queue.
  45.                 mRoots.get(index).doDie();  
  46.             } else {  
  47.                 thrownew IllegalStateException(“View ” + view  
  48.                         + ” has already been added to the window manager.”);  
  49.             }  
  50.             // The previous removeView() had not completed executing. Now it has.
  51.         }  
  52.         // If this is a panel window, then find the window it is being
  53.         // attached to for future reference.
  54.         if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&  
  55.                 wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {  
  56.             finalint count = mViews.size();  
  57.             for (int i = 0; i < count; i++) {  
  58.                 if (mRoots.get(i).mWindow.asBinder() == wparams.token) {  
  59.                     panelParentView = mViews.get(i);  
  60.                 }  
  61.             }  
  62.         }  
  63.         root = new ViewRootImpl(view.getContext(), display);  
  64.         view.setLayoutParams(wparams);  
  65.         mViews.add(view);  
  66.         mRoots.add(root);  
  67.         mParams.add(wparams);  
  68.     }  
  69.     // do this last because it fires off messages to start doing things
  70.     try {  
  71.         root.setView(view, wparams, panelParentView);//這裡呼叫ViewRootImpl類中的setView方法,在該方法中觸發了<span style=”color:rgb(101,123,131);font-family:Menlo, Monaco, Consolas, ‘Courier New’, monospace;line-height:20.4px;white-space:pre-wrap;background-color:rgb(246,246,246);”>ViewRootImpl.performTraversals()</span>
  72.     } catch (RuntimeException e) {  
  73.         // BadTokenException or InvalidDisplayException, clean up.
  74.         synchronized (mLock) {  
  75.             finalint index = findViewLocked(view, false);  
  76.             if (index >= 0) {  
  77.                 removeViewLocked(index, true);  
  78.             }  
  79.         }  
  80.         throw e;  
  81.     }  
  82. }  
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (display == null) {
            throw new IllegalArgumentException("display must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams) params;
        if (parentWindow != null) {
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            // If there's no parent, then hardware acceleration for this view is
            // set from the application's hardware acceleration setting.
            final Context context = view.getContext();
            if (context != null
                    && (context.getApplicationInfo().flags
                            & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0) {
                wparams.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
            }
        }

        ViewRootImpl root;
        View panelParentView = null;

        synchronized (mLock) {
            // Start watching for system property changes.
            if (mSystemPropertyUpdater == null) {
                mSystemPropertyUpdater = new Runnable() {
                    @Override public void run() {
                        synchronized (mLock) {
                            for (int i = mRoots.size() - 1; i >= 0; --i) {
                                mRoots.get(i).loadSystemProperties();
                            }
                        }
                    }
                };
                SystemProperties.addChangeCallback(mSystemPropertyUpdater);
            }

            int index = findViewLocked(view, false);
            if (index >= 0) {
                if (mDyingViews.contains(view)) {
                    // Don't wait for MSG_DIE to make it's way through root's queue.
                    mRoots.get(index).doDie();
                } else {
                    throw new IllegalStateException("View " + view
                            + " has already been added to the window manager.");
                }
                // The previous removeView() had not completed executing. Now it has.
            }

            // If this is a panel window, then find the window it is being
            // attached to for future reference.
            if (wparams.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
                    wparams.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
                final int count = mViews.size();
                for (int i = 0; i < count; i++) {
                    if (mRoots.get(i).mWindow.asBinder() == wparams.token) {
                        panelParentView = mViews.get(i);
                    }
                }
            }

            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 {
            root.setView(view, wparams, panelParentView);//這裡呼叫ViewRootImpl類中的setView方法,在該方法中觸發了ViewRootImpl.performTraversals()
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

在該方法中的root.setView(view,wparams,panelParentView)方法,呼叫的是ViewRootImpl類中的setView方法,正是該setView方法觸發了ViewRootImpl.performTraversals()方法,也就是View繪製的起點,之後會進行measure,layout,draw三個步驟從而完成一個View的顯示工作。

ViewRootImpl.java

[java] view plain copy print?
  1. /** 
  2.  * We have one child 
  3.  */
  4. publicvoid setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {  
  5.     synchronized (this) {  
  6.         if (mView == null) {  
  7.             mView = view;  
  8.             mAttachInfo.mDisplayState = mDisplay.getState();  
  9.             mDisplayManager.registerDisplayListener(mDisplayListener, mHandler);  
  10.             …  
  11.             mSoftInputMode = attrs.softInputMode;  
  12.             mWindowAttributesChanged = true;  
  13.             mWindowAttributesChangesFlag = WindowManager.LayoutParams.EVERYTHING_CHANGED;  
  14.             mAttachInfo.mRootView = view;  
  15.             mAttachInfo.mScalingRequired = mTranslator != null;  
  16.             mAttachInfo.mApplicationScale =  
  17.                     mTranslator == null ? 1.0f : mTranslator.applicationScale;  
  18.             if (panelParentView != null) {  
  19.                 mAttachInfo.mPanelParentWindowToken  
  20.                         = panelParentView.getApplicationWindowToken();  
  21.             }  
  22.             mAdded = true;  
  23.             int res; /* = WindowManagerImpl.ADD_OKAY; */
  24.             // Schedule the first layout -before- adding to the window
  25.             // manager, to make sure we do the relayout before receiving
  26.             // any other events from the system.
  27.             requestLayout();//這裡開始請求view的繪製
  28.             if ((mWindowAttributes.inputFeatures  
  29.                     & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {  
  30.                 mInputChannel = new InputChannel();  
  31.             }  
  32.             try {  
  33.                 mOrigWindowType = mWindowAttributes.type;  
  34.                 mAttachInfo.mRecomputeGlobalAttributes = true;  
  35.                 collectViewAttributes();  
  36.                 res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,  
  37.                         getHostVisibility(), mDisplay.getDisplayId(),  
  38.                         mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,  
  39.                         mAttachInfo.mOutsets, mInputChannel);  
  40.             } catch (RemoteException e) {  
  41.                 mAdded = false;  
  42.                 mView = null;  
  43.                 mAttachInfo.mRootView = null;  
  44.                 mInputChannel = null;  
  45.                 mFallbackEventHandler.setView(null);  
  46.                 unscheduleTraversals();  
  47.                 setAccessibilityFocus(nullnull);  
  48.