Android源码解析:AlertDialog和WindowManager源码解析

(一)AlertDialog的实现模式

AlertDialog的实现模式使用了Builder模式,通过Builder对象来组装Dialog的各个部分。AlertController用于存储Builder成员变量中的各个参数。

AlertDialog可以设置title,message,button等参数,这些参数存储在AlertController.AlertParams的成员变量P中,AlertController.AlertParams中包含了AlertDialog视图中对应的成员变量。Builder类在调用create函数时会创建AlertDialog,并将P中的保存的参数应用到AlertDialog的mAlert对象中。这个是通过P.apply函数来实现的。

在调用完create函数后,我们获取了AlertDialog对象,就可以使用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);
        } else {
            // Fill the DecorView in on any configuration changes that
            // may have occured while it was removed from the WindowManager.
            final Configuration config = mContext.getResources().getConfiguration();
            mWindow.getDecorView().dispatchConfigurationChanged(config);
        }

        onStart();
        mDecor = mWindow.getDecorView();
       //省略代码
        mWindowManager.addView(mDecor, l);
        mShowing = true;

        sendShowMessage();
    }

show函数执行了三个操作:

1.如果AlertDialog没有被create,就通过dispatchOnCreate调用了AlertDialog的onCreate方法

2.调用AlertDialog的onStart方法

3.将DecorView添加到WindowManager中

我们看一下onCreate方法的实现。

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

然后我们看一下installContent()方法。

   public void installContent() {
        final int contentView = selectContentView();
        mDialog.setContentView(contentView);
        setupView();
    }

这方法就实现了两步,(1)设置AlertDialog的内容布局(2)初始化AlertDialog布局中的各个部分。setupView中使用了大量的findViewById来寻找相关的组件,代码比较庞杂,对此我们就不一一看了。

(二)WindowManager

AlertDialog的视图最后是将view传递给WindowManger来显示的。事实上所有的要显示到屏幕上的内容(包括Activity)都是通过WindowManager来进行操作的。

WindowManager是ContextImpl中注册的众多服务之一。各种系统服务会注册到ContextImpl的一个map容器中,然后通过该服务的关键字来获取。

通过getSystemService方法获取到WindowManger对象后。我们该如何将Window对象和WindowManager建立联系呢。在Dialog的构造函数中,我们可以看到这么一行代码。

w.setWindowManager(mWindowManager, null, null);

我们看一下setWindowManager方法的具体实现。

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        //省略代码
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
    }
 public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mContext, parentWindow);
    }

WindowManagerImpl是WindowManagerGlobal的包装。我们在上一层,通过调用WindowManager的addView方法请求系统将该View显示到屏幕上,实际上这一切的实现都是通过WindowManagerGlobal的addView方法来实现的。

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        //代码省略
        
        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);
        } catch (RuntimeException e) {
            // BadTokenException or InvalidDisplayException, clean up.
            synchronized (mLock) {
                final int index = findViewLocked(view, false);
                if (index >= 0) {
                    removeViewLocked(index, true);
                }
            }
            throw e;
        }
    }

这里构建了ViewRootImpl,将布局参数设置给View,存储ViewRootImpl,View,LayoutParam到列表中。然后通过ViewRootImpl的setView将View显示到窗口上。

ViewRootImpl实现了native层和Java层View系统通信的桥梁。它会检测系统中View的消息,并通过调用方法来绘制整棵视图树。我们看一下ViewRootImpl的构建方法。

public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        //省略代码
    }
    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager imm = InputMethodManager.getInstance();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            },
                            imm.getClient(), imm.getInputContext());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }
    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
                try {
                    sWindowManagerService = getWindowManagerService();
                    ValueAnimator.setDurationScale(sWindowManagerService.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }

从上文代码中可以看到,Android的架构层和native的wms是通过Binder机制进行通信的。架构层通过了Binder机制和Native建立了联系,并通过了openSession与WMS建立通行会话。

WMS管理的是View的Z轴。

在与WMS建立完联系后,我们会调用ViewRootImp的setView方法。该方法会向WMS发送显示Dialog或者Activity中的DecorView的请求,具体代码如下:

setView方法很复杂,但是主要逻辑是两步:

(1)requestLayout

 (2)向WMS发送显示当前Window的请求

requestLayout方法会向handler中发送一个DO_TRAVERSAL消息,这个消息会触发整个视图树的绘制操作,简而言之就是遍历整棵树的各个View,执行了Measure,Layout,Draw方法。



总结:



架构层和native层通过binder来进行通信




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值