android源码解析(十九)-->Dialog加载绘制流程

前面两篇文章,我们分析了Activity的布局文件加载、绘制流程,算是对整个Android系统中界面的显示流程有了一个大概的了解,其实Android系统中所有的显示控件(注意这里是控件,而不是组件)的加载绘制流程都是类似的,包括:Dialog的加载绘制流程,PopupWindow的加载绘制流程,Toast的显示原理等,上一篇文章中,我说在介绍了Activity界面的加载绘制流程之后,就会分析一下剩余几个控件的显示控制流程,这里我打算先分析一下Dialog的加载绘制流程。

可能有的同学问这里为什么没有Fragment?其实严格意义上来说Fragment并不是一个显示控件,而只是一个显示组件。为什么这么说呢?其实像我们的Activity,Dialog,PopupWindow以及Toast类的内部都管理维护着一个Window对象,这个Window对象不但是一个View组件的集合管理对象,它也实现了组件的加载与绘制流程,而我们的Fragment组件如果看过源码的话,严格意义上来说,只是一个View组件的集合并通过控制变量实现了其特定的生命周期,但是其由于并没有维护Window类型的成员变量,所以其不具备组件的加载与绘制功能,因此其不能单独的被绘制出来,这也是我把它称之为组件而不是控件的原因。(在分析完这几个控件的加载绘制流程之后,有时间的话,也会分析一下Fragment的相关源码)

好吧,开始我们今天关于Dialog的讲解,相信大家在平时的开发过程中经常会使用到Dialog弹窗,使用Dialog可以在Activity弹出弹窗,确认消息等。为了更好的分析Dialog的源码,我们这里暂时写一个简单的demo,看一下Dialog的使用实例。

title.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
                builder.setIcon(R.mipmap.ic_launcher);
                builder.setMessage("this is the content view!!!");
                builder.setTitle("this is the title view!!!");
                builder.setView(R.layout.activity_second);
                builder.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialog.dismiss();
                    }
                });
                alertDialog = builder.create();
                alertDialog.show();
            }
        });

我们在Activity中获取一个textView组件,并监听TextView的点击事件,并在点击事件中,初始化一个AlertDialog弹窗,并执行AlertDialog的show方法展示弹窗,在弹窗中定义一个按钮,并监听弹窗按钮的点击事件,若用户点击了弹窗的按钮,则执行AlertDialog的dismiss方法,取消展示AlertDialog。好吧,我们来看一下这个弹窗弹出的展示结果:

可以看到我们定义的icon,title,message和button都已经显示出来了,这时候我们点击弹窗按钮知道了,这时候弹窗就会消失了。

一般我们使用Dialog的大概流程都是这样的,可能定制Dialog的时候有一些定制化的操作,但是基本操作流程还是这样的。

那么我们先来看一下AlertDialog.Builder的构造方法,这里的Builder是AlertDialog的内部类,用于封装AlertDialog的构造过程,看一下Builder的构造方法:

public Builder(Context context) {
            this(context, resolveDialogTheme(context, 0));
        }

好吧,这里调用的是Builder的重载构造方法:

public Builder(Context context, int themeResId) {
            P = new AlertController.AlertParams(new ContextThemeWrapper(
                    context, resolveDialogTheme(context, themeResId)));
        }

那么这里的P是AlertDialog.Builder中的一个AlertController.AlertParams类型的成员变量,可见在这里执行了P的初始化操作。

public AlertParams(Context context) {
            mContext = context;
            mCancelable = true;
            mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

可以看到这里主要执行了AlertController.AlertParams的初始化操作,初始化了一些成员变量。这样执行了一系列操作之后我们的代码:

AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);

就已经执行完成了,然后我们调用了builder.setIcon方法,这里看一下setIcon方法的具体实现:

public Builder setIcon(@DrawableRes int iconId) {
            P.mIconId = iconId;
            return this;
        }

可以看到AlertDialog的Builder的setIcon方法,这里执行的就是给类型为AlertController.AlertParams的P的mIconId赋值为传递的iconId,并且这个方法返回的类型就是Builder。

然后我们调用了builder.setMessage方法,可以看一下builder.setMessage方法的具体实现:

public Builder setMessage(CharSequence message) {
            P.mMessage = message;
            return this;
        }

好吧,这里跟setIcon方法的实现逻辑类似,都是给成员变量的mMessage赋值为我们传递的Message值,且和setIcon方法类似的,这个方法返回值也是Builder。

再看一下builder.setTitle方法:

public Builder setTitle(CharSequence title) {
            P.mTitle = title;
            return this;
        }

可以发现builder的setIcon、setMessage、setTitle等方法都是给Builder的成员变量P的icon,message,title赋值。

然后我们看一下builder.setView方法:

public Builder setView(int layoutResId) {
            P.mView = null;
            P.mViewLayoutResId = layoutResId;
            P.mViewSpacingSpecified = false;
            return this;
        }

可以发现这里的setView和setIcon,setMessage,setTitle等方法都是类似的,都是将我们传递的数据值赋值给Builder的成员变量P。

然后我们调用了builder.setPositiveButton方法:

builder.setPositiveButton("知道了", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        alertDialog.dismiss();
                    }
                });

好吧,这里我们看一下builder的setPositiveButton的源码:

public Builder setPositiveButton(CharSequence text, final OnClickListener listener) {
            P.mPositiveButtonText = text;
            P.mPositiveButtonListener = listener;
            return this;
        }

好吧,可以发现跟上面几个方法还是类似的,都是为Builder的成员变量P的相应成员变量赋值。。。

上面的几行代码我们都是调用的builder.setXXX等方法,主要就是为Builder的成员变量P的相应成员变量值赋值。并且setXX方法返回值都是Builder类型的,因此我们可以通过消息琏的方式连续执行:

builder.setIcon().setMessage().setTitle().setView().setPositiveButton()...

这样代码显得比较简洁,set方法的执行顺序是没有固定模式的,这里多说一下,这种编程方式很优秀,平时我们在设计构造类工具类的时候也可以参考这种模式,构造类有不同的功能或者特性,并且都不是必须的,我们可以通过set方法设置不同的特性值并返回构造类本身。

然后我们调用了builder.create方法,并且这个方法返回了AlertDialog。

public AlertDialog create() {
            // Context has already been wrapped with the appropriate theme.
            final AlertDialog dialog = new AlertDialog(P.mContext, 0, false);
            P.apply(dialog.mAlert);
            dialog.setCancelable(P.mCancelable);
            if (P.mCancelable) {
                dialog.setCanceledOnTouchOutside(true);
            }
            dialog.setOnCancelListener(P.mOnCancelListener);
            dialog.setOnDismissListener(P.mOnDismissListener);
            if (P.mOnKeyListener != null) {
                dialog.setOnKeyListener(P.mOnKeyListener);
            }
            return dialog;
        }

可以看到这里首先构造了一个AlertDialog,我们可以看一下这个构造方法的具体实现:

AlertDialog(Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        super(context, createContextThemeWrapper ? resolveDialogTheme(context, themeResId) : 0,
                createContextThemeWrapper);

        mWindow.alwaysReadCloseOnTouchAttr();
        mAlert = new AlertController(getContext(), this, getWindow());
    }

可以看到这里首先调用了super的构造方法,而我们的AlertDialog继承于Dialog,所以这里执行的就是Dialog的构造方法,好吧,继续看一下Dialog的构造方法:

Dialog(@NonNull Context context, @StyleRes int themeResId, boolean createContextThemeWrapper) {
        if (createContextThemeWrapper) {
            if (themeResId == 0) {
                final TypedValue outValue = new TypedValue();
                context.getTheme().resolveAttribute(R.attr.dialogTheme, outValue, true);
                themeResId = outValue.resourceId;
            }
            mContext = new ContextThemeWrapper(context, themeResId);
        } else {
            mContext = context;
        }

        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);

        mListenersHandler = new ListenersHandler(this);
    }

可以发现在Dialog的构造方法中直接直接构造了一个PhoneWindow,并赋值给Dialog的成员变量mWindow,从这里可以看出其实Dialog和Activity的显示逻辑都是类似的,都是通过对应的Window变量来实现窗口的加载与显示的。然后我们执行了一些Window对象的初始化操作,比如设置回调函数为本身,然后调用了Window类的setWindowManager方法,并传入了WindowManager,可以发现这里的WindowManager对象是通过方法:

mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);

获取的,而我们的context传入的是Activity对象,所以这里的WindowManager对象其实和Activity获取的WindowManager对象是一致的。然后我们看一下window类的setWindowManager方法:

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) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }

可以看到跟Activity的Window对象的windowManager的获取方式是相同的,都是通过new的方式创建一个新的WindowManagerImpl对象。好吧,继续回到我们的AlertDialog的构造方法中,在构造方法中,我们除了调用Dialog的构造方法之外还执行了:

mAlert = new AlertController(getContext(), this, getWindow());

相当于初始化了AlertDiaog的成员变量mAlert。

继续回到我们的AlertDialog.Builder.create方法,在创建了一个AlertDialog之后,又执行了P.apply(dialog.mAlert);

我们知道这里的P是一个AlertController.AlertParams的变量,而dialog.mAlert是我们刚刚创建的AlertDialog中的一个AlertController类型的变量,我们来看一下apply方法的具体实现:

ublic void apply(AlertController dialog) {
            if (mCustomTitleView != null) {
                dialog.setCustomTitle(mCustomTitleView);
            } else {
                if (mTitle != null) {
                    dialog.setTitle(mTitle);
                }
                if (mIcon != null) {
                    dialog.setIcon(mIcon);
                }
                if (mIconId != 0) {
                    dialog.setIcon(mIconId);
                }
                if (mIconAttrId != 0) {
                    dialog.setIcon(dialog.getIconAttributeResId(mIconAttrId));
                }
            }
            if (mMessage != null) {
                dialog.setMessage(mMessage);
            }
            if (mPositiveButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_POSITIVE, mPositiveButtonText,
                        mPositiveButtonListener, null);
            }
            if (mNegativeButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEGATIVE, mNegativeButtonText,
                        mNegativeButtonListener, null);
            }
            if (mNeutralButtonText != null) {
                dialog.setButton(DialogInterface.BUTTON_NEUTRAL, mNeutralButtonText,
                        mNeutralButtonListener, null);
            }
            if (mForceInverseBackground) {
                dialog.setInverseBackgroundForced(true);
            }
            // For a list, the client can either supply an array of items or an
            // adapter or a cursor
            if ((mItems != null) || (mCursor != null) || (mAdapter != null)) {
                createListView(dialog);
            }
            if (mView != null) {
                if (mViewSpacingSpecified) {
                    dialog.setView(mView, mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight,
                            mViewSpacingBottom);
                } else {
                    dialog.setView(mView);
                }
            } else if (mViewLayoutResId != 0) {
                dialog.setView(mViewLayoutResId);
            }
        }

看到了么?就是我们在初始化AlertDialog.Builder的时候设置的icon、title、message赋值给了AlertController.AlertParams,这里就是将我们初始化时候设置的属性值赋值给我们创建的Dialog对象的mAlert成员变量。。。。

继续我们的AlertDialog.Builder.create方法,在执行了AlertController.AlertParams.apply方法之后又调用了:

dialog.setCancelable(P.mCancelable);

可以发现这个也是AertController.AlertParams的一个成员变量,我们在初始化AlertDialog.Builder的时候也可以通过设置builder.setCancelable赋值,由于该属性为成员变量,所以默认值为false,而我们并没有通过builder.setCancelable修改这个属性值,所以这里设置的dialog的cancelable的值为false。然后我们的create方法有设置了dialog的cancelListener和dismissListener并返回了我们创建的Dialog对象。这样我们就获取到了我们的Dialog对象,然后我们调用了dialog的show方法用于显示dialog,好吧,这里我们看一下show方法的具体实现:

public void show() {
        if (mShowing) {
            if (mDecor != null) {
                if (mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
                    mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
                }
                mDecor.setVisibility(View.VISIBLE);
            }
            return;
        }

        mCanceled = false;

        if (!mCreated) {
            dispatchOnCreate(null);
        }

        onStart();
        mDecor = mWindow.getDecorView();

        if (mActionBar == null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
            final ApplicationInfo info = mContext.getApplicationInfo();
            mWindow.setDefaultIcon(info.icon);
            mWindow.setDefaultLogo(info.logo);
            mActionBar = new WindowDecorActionBar(this);
        }

        WindowManager.LayoutParams l = mWindow.getAttributes();
        if ((l.softInputMode
                & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) == 0) {
            WindowManager.LayoutParams nl = new WindowManager.LayoutParams();
            nl.copyFrom(l);
            nl.softInputMode |=
                    WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION;
            l = nl;
        }

        try {
            mWindowManager.addView(mDecor, l);
            mShowing = true;

            sendShowMessage();
        } finally {
        }
    }

方法体的内容比较多,我们慢慢看,由于一开始mShowing变量用于表示当前dialog是否正在显示,由于我们刚刚开始调用执行show方法,所以这里的mShowing变量的值为false,所以if分支的内容不会被执行,继续往下看:

if (!mCreated) {
            dispatchOnCreate(null);
        }

mCreated这个控制变量控制dispatchOnCreate方法只被执行一次,由于我们是第一次执行,所以这里会执行dispatchOnCreate方法,好吧,我们看一下dispatchOnCreate方法的执行逻辑:

void dispatchOnCreate(Bundle savedInstanceState) {
        if (!mCreated) {
            onCreate(savedInstanceState);
            mCreated = true;
        }
    }

好吧,可以看到代码的执行逻辑很简单就是回调了Dialog的onCreate方法,那么onCreate方法内部又执行了那些逻辑呢?由于我们创建的是AlertDialog对象,该对象继承于Dialog,所以我们这时候需要看一下AlertDialog的onCreate方法的执行逻辑:

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mAlert.installContent();
    }

可以看到这里面除了调用super.onCreate方法之外就是调用了mAlert.installContent方法,而这里的super.onCreate方法就是调用的Dialog的onCreate方法,Dialog的onCreate方法只是一个空的实现逻辑,所以我们具体来看一下mAlert.installContent的实现逻辑。

public void installContent() {
        /* We use a custom title so never request a window title */
        mWindow.requestFeature(Window.FEATURE_NO_TITLE);
        int contentView = selectContentView();
        mWindow.setContentView(contentView);
        setupView();
        setupDecor();
    }

可以看到这里实现Window窗口的页面设置布局初始化等操作,这里设置了mWindow对象为NO_TITLE,然后通过调用selectContentView设置Window对象的布局文件。

private int selectContentView() {
        if (mButtonPanelSideLayout == 0) {
            return mAlertDialogLayout;
        }
        if (mButtonPanelLayoutHint == AlertDialog.LAYOUT_HINT_SIDE) {
            return mButtonPanelSideLayout;
        }
        // TODO: use layout hint side for long messages/lists
        return mAlertDialogLayout;
    }

可以看到这里通过执行selectContentView方法返回布局文件的id值,这里的默认值是mAlertDialogLayout。看过Activity布局加载流程(http://blog.csdn.net/qq_23547831/article/details/51284556)的童鞋应该知道,从这个方法开始我们就把指定布局文件的内容加载到内存中的Window对象中。我们这里看一下具体的布局文件。

mAlertDialogLayout = a.getResourceId(
                R.styleable.AlertDialog_layout, R.layout.alert_dialog);

也就是R.layout.alert_dialog的布局文件,有兴趣的同学可以看一下该布局文件的源码,O(∩_∩)O哈哈~

继续回到我们的installContent方法,在执行了mWindow.setContentView方法之后,又调用了setupView方法和setupDector方法,这两个方法的主要作用就是初始化布局文件中的组件和Window对象中的mDector成员变量,这里就不在详细的说明。

然后回到我们的show方法,在执行了dispatchOnCreate方法之后我们又调用了onStart方法,这个方法主要用于设置ActionBar,这里不做过多的说明,然后初始化WindowManager.LayoutParams对象,并最终调用我们的mWindowManager.addView()方法。

O(∩_∩)O哈哈~,到了这一步大家如果看了上一篇Acitivty布局绘制流程的话,就应该知道顺着这个方法整个Dialog的界面就会被绘制出来了。

最后我们调用了sendShowMessage方法,可以看一下这个方法的实现:

private void sendShowMessage() {
        if (mShowMessage != null) {
            // Obtain a new message so this dialog can be re-used
            Message.obtain(mShowMessage).sendToTarget();
        }
    }

这里会发送一个Dialog已经显示的异步消息,该消息最终会在ListenersHandler中的handleMessage方法中被执行:

private static final class ListenersHandler extends Handler {
        private WeakReference<DialogInterface> mDialog;

        public ListenersHandler(Dialog dialog) {
            mDialog = new WeakReference<DialogInterface>(dialog);
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case DISMISS:
                    ((OnDismissListener) msg.obj).onDismiss(mDialog.get());
                    break;
                case CANCEL:
                    ((OnCancelListener) msg.obj).onCancel(mDialog.get());
                    break;
                case SHOW:
                    ((OnShowListener) msg.obj).onShow(mDialog.get());
                    break;
            }
        }
    }

由于我们的msg.what = SHOW,所以会执行OnShowListener.onShow方法,那么这个OnShowListener是何时赋值的呢?还记得我们构造AlertDialog.Builder么?

alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
                    @Override
                    public void onShow(DialogInterface dialog) {

                    }
                });

这样就为我们的AlertDialog.Builder设置了OnShowListener,可以看一下setOnShowListener方法的具体实现:

public void setOnShowListener(OnShowListener listener) {
        if (listener != null) {
            mShowMessage = mListenersHandler.obtainMessage(SHOW, listener);
        } else {
            mShowMessage = null;
        }
    }

这样就为我们的Dialog中的mListenersHandler构造了Message对象,并且当我们在Dialog中发送showMessage的时候被mListenersHandler所接收。。。。

注:

这里说一下我们平时开发中若创建的Dialog使用的Context对象不是Activity,就会报出:

Process: com.example.aaron.helloworld, PID: 11948                                                                         android.view.WindowManager$BadTokenException: Unable to add window -- token null is not for an application
at android.view.ViewRootImpl.setView(ViewRootImpl.java:690)
at android.view.WindowManagerGlobal.addView(WindowManagerGlobal.java:282)
at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:69)
at android.app.Dialog.show(Dialog.java:298)
at com.example.aaron.helloworld.MainActivity$1.onClick(MainActivity.java:59)
at android.view.View.performClick(View.java:4811)
at android.view.View$PerformClick.run(View.java:20136)
at android.os.Handler.handleCallback(Handler.java:815)
at android.os.Handler.dispatchMessage(Handler.java:104)
at android.os.Looper.loop(Looper.java:194)
at android.app.ActivityThread.main(ActivityThread.java:5552)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:964)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:759)

的异常,这是由于WindowManager.addView方法最终会调用ViewRootImpl.setView方法,而这时候会有mToken的检查,若我们传入的Context对象不是Activity,这时候的mToken为空,就会出现上述问题。。。

总结:

  • Dialog和Activity的显示逻辑是相似的都是内部管理这一个Window对象,用WIndow对象实现界面的加载与显示逻辑;
  • Dialog中的Window对象与Activity中的Window对象是相似的,都对应着一个WindowManager对象;
  • Dialog相关的几个类:Dialog,AlertDialog,AlertDialog.Builder,AlertController,AlertController.AlertParams,其中Dialog是窗口的父类,主要实现Window对象的初始化和一些共有逻辑,而AlertDialog是具体的Dialog的操作实现类,AlertDialog.Builder类是AlertDialog的内部类,主要用于构造AlertDialog,AlertController是AlertDialog的控制类,AlertController.AlertParams类是控制参数类;
  • 构造显示Dialog的一般流程,构造AlertDialog.Builder,然后设置各种属性,最后调用AlertDialog.Builder.create方法获取AlertDialog对象,并且create方法中会执行,构造AlertDialog,设置dialog各种属性的操作。最后我们调用Dialog.show方法展示窗口,初始化Dialog的布局文件,Window对象等,然后执行mWindowManager.addView方法,开始执行绘制View的操作,并最终将Dialog显示出来;
时间: 2024-10-24 09:45:28

android源码解析(十九)-->Dialog加载绘制流程的相关文章

android源码解析(二十七)--&gt;HOME事件流程

上一篇文章中我们介绍了android系统的截屏事件,由于截屏事件是一种系统全局处理事件,所以事件的处理逻辑不是在App中执行,而是在PhoneWindowManager中执行.而本文我们现在主要讲解android系统中HOME按键的事件处理,和截屏事件类似,这里的HOME按键也是系统级别的按键事件监听,所以其处理事件的逻辑也应该和截屏事件处理流程类似,从上一篇文章的分析过冲中我们不难发现,系统级别的按键处理逻辑其实都是在PhoneWindowManager中,所以HOME按键的处理逻辑也是在Ph

laravel的源码解析:PHP自动加载功能原理解析

前言 这篇文章是对PHP自动加载功能的一个总结,内容涉及PHP的自动加载功能.PHP的命名空间.PHP的PSR0与PSR4标准等内容. 一.PHP自动加载功能 PHP自动加载功能的由来 在PHP开发过程中,如果希望从外部引入一个 class,通常会使用 include 和 require 方法,去把定义这个 class 的文件包含进来.这个在小规模开发的时候,没什么大问题.但在大型的开发项目中,使用这种方式会带来一些隐含的问题:如果一个 PHP 文件需要使用很多其它类,那么就需要很多的 requ

android源码解析之(十一)--&gt;应用进程启动流程

在android guide中有这样的一段关于android应用程序进程的描述: By default, every application runs in its own Linux process. Android starts the process when any of the application's components need to be executed, then shuts down the process when it's no longer needed or w

Spring 源码解析(二)加载配置文件2

接上一章,我们来具体分析下configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc)方法 //org.springframework.web.context.ContextLoader.class 1 protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicati

android源码解析(二十二)--&gt;Toast加载绘制流程

前面我们分析了Activity.Dialog.PopupWindow的加载绘制流程,相信大家对整个Android系统中的窗口绘制流程已经有了一个比较清晰的认识了,这里最后再给大家介绍一下Toast的加载绘制流程. 其实Toast窗口和Activity.Dialog.PopupWindow有一个不太一样的地方,就是Toast窗口是属于系统级别的窗口,他和输入框等类似的,不属于某一个应用,即不属于某一个进程,所以自然而然的,一旦涉及到Toast的加载绘制流程就会涉及到进程间通讯,看过前面系列文章的同

android源码解析(二十)--&gt;Dialog取消绘制流程

上几篇文章中我们分析了Dialog的加载绘制流程,也分析了Acvityi的加载绘制流程,说白了Android系统中窗口的展示都是通过Window对象控制,通过ViewRootImpl对象执行绘制操作来完成的,那么窗口的取消绘制流程是怎么样的呢?这篇文章就以Dialog为例说明Window窗口是如何取消绘制的. 有的同学可能会问前几篇文章介绍Activity的加载绘制流程的时候为何没有讲Activity的窗口取消流程,这里说明一下.那是因为当时说明的重点是Activity的加载与绘制流程,而取消绘

android源码解析(二十九)--&gt;应用程序返回按键执行流程

从这篇文章中我们开始分析android系统的事件分发流程,其实网上已经有了很多关于android系统的事件分发流程的文章,奈何看了很多但是印象还不是很深,所以这里总结一番. android系统的事件分发流程分为很多部分: Native层 –> ViewRootImpl层 –> DecorView层 –> Activity层 –> ViewGroup层 –> View层 所以android系统的事件分发流程是从Native层开始的,然后分发到ViewRootImpl中,然后分发

android源码解析(二十一)--&gt;PopupWindow加载绘制流程

在前面的几篇文章中我们分析了Activity与Dialog的加载绘制流程,取消绘制流程,相信大家对Android系统的窗口绘制机制有了一个感性的认识了,这篇文章我们将继续分析一下PopupWindow加载绘制流程. 在分析PopupWindow之前,我们将首先说一下什么是PopupWindow?理解一个类最好的方式就是看一下这个类的定义,这里我们摘要了一下Android系统中PopupWindow的类的说明: A popup window that can be used to display

android源码解析(三十)--&gt;触摸事件分发流程

前面一篇文章中我们分析了App返回按键的分发流程,从Native层到ViewRootImpl层到DocorView层到Activity层,以及在Activity中的dispatchKeyEvent方法中分发事件,最终调用了Activity的finish方法,即销毁Activity,所以一般情况下假如我们不重写Activity的onBackPress方法或者是onKeyDown方法,当我们按下并抬起返回按键的时候默认都是销毁当前Activity.而本文中我们主要介绍触摸事件的分发流程,从Nativ