Androd的源码分析(五)WindowManager

Posted 小图包

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Androd的源码分析(五)WindowManager相关的知识,希望对你有一定的参考价值。

Window: window 它是一个抽象类,具体实现类为 PhoneWindow ,它对 View 进行管理

//Window.java
public abstract class Window {
  ...
}
//PhoneWindow.java
public class PhoneWindow extends Window implements MenuBuilder.Callback {
  ...
}

WindowManager 是一个接口类,继承自接口 ViewManager ,从它的名称就知道它是用来管理 Window 的,它的实现类为 WindowManagerImpl。

//ViewManager.java
public interface ViewManager
{
  //添加 View 
    public void addView(View view, ViewGroup.LayoutParams params);
  //更新
    public void updateViewLayout(View view, ViewGroup.LayoutParams params);
  //删除
    public void removeView(View view);
}

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

//WindowManagerImpl
public final class WindowManagerImpl implements WindowManager {
  ...
}

如果我们想要对 Window 进行添加、更新、删除操作就可以使用 WindowManager 类, WindowManager 会将具体的工作交于 WMS 来处理, WindowManager 与 WMS 以 Binder 的形式进行通信,这一点与 ActivityManager 和 AMS 一样 。


WindowManager 的关联类

我们会从源码的角度来分析 WindowManager 的关联类,从中我们可以更好地理解 Window 和 WindowManager 的关系。

WindowManager 继承了父类接口的方法,说明也具备了父类的能力,从父类方法中的第一个参数得知,传入的都是 View 类型的参数,那么这就可以说明 Window 都是以 View 的方式存在。在继承父类的特性之外 WindowManager 又加入了很多功能,比如 Window 的类型和层级相关的常量、内部类以及一些方法,其中有两个方法时根据 Window 的特性加入的 

//interface-->WindowManager.java
public interface WindowManager extends ViewManager {
  
 ...
   
    /**
     * 得知将 Window 添加到哪个屏幕上了,通俗来说就是拿到 WindowManager 所管理的屏幕 Display
     * @return
     */
    public Display getDefaultDisplay();


    /**
     * 规定在这个方法返回前要立刻执行 View.onDetachedFromWindow() 来完成传入的 View 相关逻辑的销毁工作
     * @param view
     */
    public void removeViewImmediate(View view);
   
 ...
}

我们知道 Window 是一个抽象类, 它的唯一子类就是 PhoneWindow, 那么 PhoneWindow 是何时创建的呢?在讲解 Activity 启动的时候我们知道要启动一个 Activity 最后实际调用的 H 类的 handleLaunchActivity -> performLaunchActivity 方法中又调用了 Activity 的 attach 方法,PhoneWindow 就在该方法中创建的 ,我们看代码实现 

//Activity.java
    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) {
       	...
        /**
         * 1. 实例化 Window 的唯一子类 PhoneWindow 
         */
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        ...

        /**
         * 2. 绑定 WindowManager
         */
        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());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;

        mWindow.setColorMode(info.colorMode);
    }

上述主要做了两个作用 一实例化 Window 抽象类的子类 PhonWindow, 其二就是 PhoneWindow 与 WindowManager 想关联,我们看 setWindowManager 方法

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

进来的 wm 类型的 WindowManager 为 null ,就通过 mContext . getSystemService 方法在获取 WIndowManager 对象,这里的 mContext 是 Context 类型,它的实现类是 ContentImp 对象,也是在 performLaunchActivity 方法中实例化。我们先跟一下 ContentImp 的 getSystemService 方法具体实现

//ContextImpl.java
    @Override
    public Object getSystemService(String name) {
        return SystemServiceRegistry.getSystemService(this, name);
    }



我们看到在 SystemServiceRegistry 类中的静态方法 getSystemService 中获取,代码如下:

//SystemServiceRegistry.java
final class SystemServiceRegistry {
  
  ...
    
   //1. 
  private static final HashMap<String, ServiceFetcher<?>> SYSTEM_SERVICE_FETCHERS =
            new HashMap<String, ServiceFetcher<?>>();
  
  ...
    
    static{
    ...
      //2.
    registerService(Context.WINDOW_SERVICE, WindowManager.class,
                new CachedServiceFetcher<WindowManager>() {
            @Override
            public WindowManager createService(ContextImpl ctx) {
                return new WindowManagerImpl(ctx);
            }});
    ...
  }
  
   private static <T> void registerService(String serviceName, Class<T> serviceClass,
            ServiceFetcher<T> serviceFetcher) {
        SYSTEM_SERVICE_NAMES.put(serviceClass, serviceName);
        SYSTEM_SERVICE_FETCHERS.put(serviceName, serviceFetcher);
    }
  
  public static Object getSystemService(ContextImpl ctx, String name) {
        ServiceFetcher<?> fetcher = SYSTEM_SERVICE_FETCHERS.get(name);
        return fetcher != null ? fetcher.getService(ctx) : null;
    }

SystemServiceRegistry 类的静态代码块中会注册以 Context.xxx 类型的各种服务,最后 register 成功会存入单例容器中2处调用 createLocalWindowManager 来创建 WindowManager 实现类

//WindowManagerImpl.java
public final class WindowManagerImpl implements WindowManager {
  ...
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
    		//实例化 WindowManager 的实现类对象
        return new WindowManagerImpl(mContext, parentWindow);
    }
  
      private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        mParentWindow = parentWindow;
    }
  ...
}

注释 1 跟注释 2 都会创建一个 WindowManagerImpl 它们的不同之处就是在于注释 2 它是把创建 Window 的实例也传入了进入,这样 WindowManagerImpl 就有了 PhoneWindow 的引用,然后就就可以对 Window 进行一些处理

看WindowManagerImp 的 addView 方法

//WindowManagerImpl.java
    @Override
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        /**
         * 委托给 WindowManagerGlobal 来处理 addView 
         */
        mGlobal.addView(view, params, mContext.getDisplay(), mParentWindow);
    }

通过上面代码知道,调用了 WindowManagerImp 类中的 addView 方法,但是内部方法并没有具体实现,而是委托给了 WindowManagerGlobal 来具体处理 addView 的逻辑。

我们看下 WindowManagerGlobl在 WindowManagerImp 中怎么创建出来的,代码如下:

//WindowManagerImp.java
public final class WindowManagerImpl implements WindowManager {
  	//1. 通过线程安全的单例拿到 WindowManagerGlobal 对象
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
			/**2. */
      private final Window mParentWindow;
  
      private WindowManagerImpl(Context context, Window parentWindow) {
        mContext = context;
        //3
        mParentWindow = parentWindow;
    }
  
  
  
}

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

在注释 1 代码可以看出我们通过了一个线程安全的单例拿到了 WindowManagerGlobal 的地址,然后注释 2 ,注释 3 是在 Activity 创建 PhoneWindow 的时候一路传递进来的,这里就代表 WindowManagerImpl 实例会作为哪个 Window 的子 Window。

总结 

PhoneWindow 继承自 Window, PhoneWindow 通过 setWindowManager 方法与WindowManager 进行关联。WindowManager 继承自接口 ViewManager, WindowManagerImpl 是 WindowManager 接口的实现类,但是内部功能都委托给了 WindowManagerGlobal 来处理。

以上是关于Androd的源码分析(五)WindowManager的主要内容,如果未能解决你的问题,请参考以下文章

Androd Gradle 使用技巧之模块依赖替换

Androd Gradle 对其使用模块依赖的替换

Androd Gradle 使用技巧之模块依赖替换

[Androd] Gradle 使用技巧之模块依赖替换

Androd Gradle 使用技巧之模块依赖替换

MyBatis源码分析五MyBatis的缓存