android window(二)从getSystemService到WindowManagerGlobal

 在Activity调用getSystemService(WINDOW_SERVICE) 调用的是父类ContextThemeWrapper 

package android.view;
public class ContextThemeWrapper extends ContextWrapper {
  @Override
    public Object getSystemService(String name) {
        if (LAYOUT_INFLATER_SERVICE.equals(name)) {
            if (mInflater == null) {
                mInflater = LayoutInflater.from(getBaseContext()).cloneInContext(this);
            }
            return mInflater;
        }
        return getBaseContext().getSystemService(name);
    }
}

这里getBaseContext返回是context的实现类ContextImpl

ContextImpl.java  的源码

208  class ContextImpl extends Context {
//...
628        registerService(WINDOW_SERVICE, new ServiceFetcher() {
629                Display mDefaultDisplay;
630                public Object getService(ContextImpl ctx) {
631                    Display display = ctx.mDisplay;
632                    if (display == null) {
633                        if (mDefaultDisplay == null) {
634                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
635                                    getSystemService(Context.DISPLAY_SERVICE);
636                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
637                        }
638                        display = mDefaultDisplay;
639                    }
640                    return new WindowManagerImpl(display);
641                }});

1829    @Override
1830    public Object getSystemService(String name) {
1831        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
1832        return fetcher == null ? null : fetcher.getService(this);
1833    }
//... 
}

 

WindowManagerImpl.java

public final class WindowManagerImpl implements WindowManager {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    private final Display mDisplay;
    private final Window mParentWindow;
    //...
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }

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

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

    @Override
    public void updateViewLayout(View view, ViewGroup.LayoutParams 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 Display getDefaultDisplay() {
        return mDisplay;
    }
}

WindowManager.java

public interface WindowManager extends ViewManager {
//...
}

ViewManager.java

public interface ViewManager
{
    public void addView(View view, ViewGroup.LayoutParams params);
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
    public void removeView(View view);
}

 WindowManageraddView的过程,WindowManager是个接口,它的实现类是WindowManagerImpl类,而WindowManagerImpl又把相关逻辑交给了WindowManagerGlobal处理。WindowManagerGlobal是个单例类,它在进程中只存在一个实例,是它内部的addView方法最终创建了我们的核心类ViewRootImpl

可以看到这里的WindowManagerImpl 的主要功能都是通过WindowManagerGlobal来实现的

 WindowManagerGlobal.java

public final class WindowManagerGlobal {
    private static final String TAG = "WindowManager";

       //...
    private static WindowManagerGlobal sDefaultWindowManager;
    private static IWindowManager sWindowManagerService;
    private static IWindowSession sWindowSession;

    private final Object mLock = new Object();

    private final ArrayList<View> mViews = new ArrayList<View>();
    private final ArrayList<ViewRootImpl> mRoots = new ArrayList<ViewRootImpl>();
    private final ArrayList<WindowManager.LayoutParams> mParams =
            new ArrayList<WindowManager.LayoutParams>();
    private final ArraySet<View> mDyingViews = new ArraySet<View>();

    private Runnable mSystemPropertyUpdater;

    private WindowManagerGlobal() {
    }

    public static WindowManagerGlobal getInstance() {
        synchronized (WindowManagerGlobal.class) {
            if (sDefaultWindowManager == null) {
                sDefaultWindowManager = new WindowManagerGlobal();
            }
            return sDefaultWindowManager;
        }
    }

    public static IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
            }
            return sWindowManagerService;
        }
    }

    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());
                    ValueAnimator.setDurationScale(windowManager.getCurrentAnimatorScale());
                } catch (RemoteException e) {
                    Log.e(TAG, "Failed to open window session", e);
                }
            }
            return sWindowSession;
        }
    }

    public static IWindowSession peekWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            return sWindowSession;
        }
    }

    public String[] getViewRootNames() {
        synchronized (mLock) {
            final int numRoots = mRoots.size();
            String[] mViewRoots = new String[numRoots];
            for (int i = 0; i < numRoots; ++i) {
                mViewRoots[i] = getWindowName(mRoots.get(i));
            }
            return mViewRoots;
        }
    }

    public View getRootView(String name) {
        synchronized (mLock) {
            for (int i = mRoots.size() - 1; i >= 0; --i) {
                final ViewRootImpl root = mRoots.get(i);
                if (name.equals(getWindowName(root))) return root.getView();
            }
        }

        return null;
    }

    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
       //...
            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;
        }
    }

    public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }
        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
        }

        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

        view.setLayoutParams(wparams);

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            ViewRootImpl root = mRoots.get(index);
            mParams.remove(index);
            mParams.add(index, wparams);
            root.setLayoutParams(wparams, false);
        }
    }

    public void removeView(View view, boolean immediate) {
        if (view == null) {
            throw new IllegalArgumentException("view must not be null");
        }

        synchronized (mLock) {
            int index = findViewLocked(view, true);
            View curView = mRoots.get(index).getView();
            removeViewLocked(index, immediate);
            if (curView == view) {
                return;
            }

            throw new IllegalStateException("Calling with view " + view
                    + " but the ViewAncestor is attached to " + curView);
        }
    }

    public void closeAll(IBinder token, String who, String what) {
     //...
    }

    private void removeViewLocked(int index, boolean immediate) {
        ViewRootImpl root = mRoots.get(index);
        View view = root.getView();

        if (view != null) {
            InputMethodManager imm = InputMethodManager.getInstance();
            if (imm != null) {
                imm.windowDismissed(mViews.get(index).getWindowToken());
            }
        }
        boolean deferred = root.die(immediate);
        if (view != null) {
            view.assignParent(null);
            if (deferred) {
                mDyingViews.add(view);
            }
        }
    }

    void doRemoveView(ViewRootImpl root) {
        synchronized (mLock) {
            final int index = mRoots.indexOf(root);
            if (index >= 0) {
                mRoots.remove(index);
                mParams.remove(index);
                final View view = mViews.remove(index);
                mDyingViews.remove(view);
            }
        }
        if (HardwareRenderer.sTrimForeground && HardwareRenderer.isAvailable()) {
            doTrimForeground();
        }
    }

    private int findViewLocked(View view, boolean required) {
        final int index = mViews.indexOf(view);
        if (required && index < 0) {
            throw new IllegalArgumentException("View=" + view + " not attached to window manager");
        }
        return index;
    }


    //...
}

 

WindowManagerGlobal的addView里面初始化了

  public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
       //...
            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;
        }
    }

WindowManagerGlobal的窗口管理:

 

WindowManager的总结

经过前文的分析,相信读者对WindowManager的工作原理有了深入的认识。

  • 鉴于窗口布局和控件布局的一致性,WindowManager继承并实现了接口ViewManager。

  • 使用者可以通过Context.getSystemService(Context.WINDOW_SERVICE)来获取一个WindowManager的实例。这个实例的真实类型是WindowManagerImpl。WindowManagerImpl一旦被创建就确定了通过它所创建的窗口所属哪块屏幕?哪个父窗口?

  • WindowManagerImpl除了保存了窗口所属的屏幕以及父窗口以外,没有任何实质性的工作。窗口的管理都交由WindowManagerGlobal的实例完成。

  • WindowManagerGlobal在一个进程中只有一个实例。

  • WindowManagerGlobal在3个数组中统一管理整个进程中的所有窗口的信息。这些信息包括控件、布局参数以及ViewRootImpl三个元素。

  • 除了管理窗口的上述3个元素以外,WindowManagerGlobal将窗口的创建、销毁与布局更新等任务交付给了ViewRootImpl完成。

说明 在实际的应用开发过程中,有时会在logcat的输出中遇到有关WindowLeaked的异常输出。WindowLeaked异常发生与WindowManagerGlobal中,其原因是Activity在destroy之前没有销毁其附属窗口,如对话框、弹出菜单等。

如此看来,WindowManager的实现仍然是很轻量的。窗口的创建、销毁与布局更新都指向了一个组件:ViewRootImpl。

转载于:https://www.cnblogs.com/mingfeng002/p/9143831.html

<think>我们分析WindowManager.addView()如何调用到WindowManagerGlobal.addView()的过程。 在Android中,WindowManager是一个接口,其实现类是WindowManagerImpl。当我们通过Context.getSystemService(Context.WINDOW_SERVICE)获取WindowManager时,实际返回的是WindowManagerImpl的实例。 在WindowManagerImpl中,addView()方法会委托给WindowManagerGlobal的同一静态方法。 具体步骤: 1. 在Activity中,我们通常通过getWindowManager()获取WindowManager实例,该实例实际上是WindowManagerImpl。 2. 调用WindowManagerImpl的addView()方法,该方法内部调用WindowManagerGlobal的addView()方法。 源码分析(以Android 14为例): 首先,WindowManagerImpl的addView方法: ```java public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); // ... 其他代码 @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { // ... 一些检查 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } } ``` 而WindowManagerGlobal是一个单例,整个进程只有一份实例。所以,所有WindowManagerImpl实例都共享同一个WindowManagerGlobal。 那么,为什么会有这样的设计? 原因:每个进程可能有多个窗口(例如多个Activity、Dialog等),但窗口管理是进程级别的,所以使用一个全局的WindowManagerGlobal来管理所有窗口。 调用链: 用户调用WindowManager.addView() -> WindowManagerImpl.addView() -> WindowManagerGlobal.addView() 另外,在创建Dialog时,我们也会使用WindowManager,同样是通过Context.getSystemService()获取,也是同样的委托机制。 示例:Dialog显示时添加窗口 ```java Dialog dialog = new Dialog(context); dialog.show(); // 内部会调用WindowManager.addView() ``` 在dialog.show()方法中,最终会执行: ```java // 在Dialog的show方法中 WindowManager wm = mWindow.getWindowManager(); wm.addView(mDecor, layoutParams); ``` 这里的mWindow是PhoneWindow,而PhoneWindow的getWindowManager()返回的是WindowManagerImpl实例。 因此,无论是Activity还是Dialog,添加窗口最终都是通过WindowManagerGlobal.addView()实现的。 在WindowManagerGlobal.addView()中,会创建ViewRootImpl,然后调用ViewRootImpl.setView()方法,进而触发scheduleTraversals()。 总结: 用户代码调用WindowManager.addView() -> WindowManagerImpl.addView() -> WindowManagerGlobal.addView() 设计模式:这里使用了桥接模式和单例模式。WindowManagerImpl将实际工作委托给单例的WindowManagerGlobal。 §§相关问题§§ 1. WindowManagerImpl 和 WindowManagerGlobal 分别承担什么角色? 2. 为什么 WindowManagerGlobal 需要设计成单例模式? 3. 在 ViewRootImpl 创建过程中,WindowManagerGlobal 做了哪些具体工作? 4. 一个进程中存在多个 WindowManagerImpl 实例,它们如何与 WindowManagerGlobal 交互?</think>在 Android 系统中,`wm.addView()` 调用到 `WindowManagerGlobal.addView()` 的详细过程如下(基于 Android 14 源码分析): ### 核心调用链 ``` WindowManager.addView()WindowManagerImpl.addView()WindowManagerGlobal.addView() ``` ### 详细源码解析 1. **入口:WindowManager 接口** `WindowManager` 是接口,实际调用的是其实现类 `WindowManagerImpl`: ```java // WindowManager.java (接口) public interface WindowManager extends ViewManager { void addView(View view, ViewGroup.LayoutParams params); } ``` 2. **WindowManagerImpl 实现** 在 `WindowManagerImpl.addView()` 中直接委托给 `WindowManagerGlobal`: ```java // WindowManagerImpl.java public final class WindowManagerImpl implements WindowManager { private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance(); @Override public void addView(View view, ViewGroup.LayoutParams params) { // 最终调用全局单例 mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow); } } ``` 3. **WindowManagerGlobal 单例** 全局窗口管理器通过单例模式管理所有窗口: ```java // WindowManagerGlobal.java public final class WindowManagerGlobal { private static WindowManagerGlobal sInstance; public static WindowManagerGlobal getInstance() { synchronized (WindowManagerGlobal.class) { if (sInstance == null) { sInstance = new WindowManagerGlobal(); } return sInstance; } } public void addView(View view, ViewGroup.LayoutParams params, Display display, Window parentWindow) { // 核心实现(创建 ViewRootImpl 等) } } ``` ### 具体调用场景示例 **场景:Activity 中添加 Dialog** 1. `Dialog.show()` 触发添加视图: ```java // Dialog.java public void show() { WindowManager wm = mWindow.getWindowManager(); wm.addView(mDecor, layoutParams); // wm 实际是 WindowManagerImpl } ``` 2. 调用链展开: ```java wm.addView() // WindowManager 接口方法 ↓ WindowManagerImpl.addView()WindowManagerGlobal.getInstance().addView() // 最终执行 ``` ### 设计原理剖析 1. **桥接模式设计** ```plantuml @startuml interface WindowManager { + addView() } class WindowManagerImpl { - mGlobal: WindowManagerGlobal + addView() } class WindowManagerGlobal { + addView() } WindowManager <|.. WindowManagerImpl WindowManagerImpl --> WindowManagerGlobal : 委托调用 @enduml ``` 2. **单例全局管理** - 每个进程只有一个 `WindowManagerGlobal` 实例 - 通过静态方法 `getInstance()` 获取 - 管理三大核心列表: ```java private final ArrayList<View> mViews = new ArrayList<>(); // 所有窗口的根视图 private final ArrayList<ViewRootImpl> mRoots = new ArrayList<>(); // 对应的ViewRootImpl private final ArrayList<WindowManager.LayoutParams> mParams = new ArrayList<>(); // 布局参数 ``` 3. **跨进程通信桥梁** 在 `WindowManagerGlobal.addView()` 内部会创建 `ViewRootImpl` 并建立与 `WindowManagerService` 的跨进程通信: ```java public void addView(View view, ...) { ViewRootImpl root = new ViewRootImpl(view.getContext(), display); root.setView(view, wparams, panelParentView); // 触发跨进程通信 } ``` ### 完整调用流程图 ```mermaid sequenceDiagram participant Dialog participant WindowManagerImpl participant WindowManagerGlobal participant ViewRootImpl Dialog->>WindowManagerImpl: show() 触发 addView() WindowManagerImpl->>WindowManagerGlobal: addView(decorView, params) WindowManagerGlobal->>WindowManagerGlobal: 创建新ViewRootImpl WindowManagerGlobal->>ViewRootImpl: setView(decorView, params) ViewRootImpl->>ViewRootImpl: requestLayout() 触发UI遍历 ``` > **关键设计目标**: > 1. 统一管理进程内所有窗口(Activity/Dialog/Toast 等) > 2. 隔离窗口实现细节(客户端只接触接口) > 3. 提供跨进程通信基础(通过 ViewRootImpl 连接 WindowManagerService
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值