Activity布局加载流程源码分析(II)

Activity布局加载流程源码分析(I)文章中,已经详细分析了setContentView()加载流程,但对于装饰器DecorView怎么被加载到Window上的,上篇博文没有说到,所以本篇博文将会接着上篇博文,继续分析Activity布局的加载流程。

在开始分析之前,我们需要了解一些概念,如:

  • Window: 是一个抽象类,表示是一个窗口。Android系统中的界面,也都是以窗口的形式存在的。
  • PhoneWindow: 是Window类具体实现类,Activity中布局加载逻辑主要就是在此类中完成的。
  • DecorView:是PhoneWindow中的一个内部类,也是Window的顶级View,主要负责装载各种View。
  • WindowManager: 是Window的管理类,管理着Window的添加、更新和删除。
  • WindowManagerService(AMS):是系统窗口管理服务类,具体管理着系统各种各样的Window。
  • ViewRootImpl:是View的绘制的辅助类,所有View的绘制都离不开ViewRootImpl。

一、Activity布局及DecorView加载分析

这里,我们接着Activity布局加载流程继续分析。在布局加载流程最后,主要是通过WindowManager添加装饰器DecorView到Window中,从而实现Activity布局的加载,这里继续来看那部分代码

   final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward) {

        ActivityClientRecord r = performResumeActivity(token, clearHide);
        .......
        if (r != null) {
            final Activity a = r.activity;
            ......
            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);
                }
            ......
        }
    }

这里,简单解释一下参数。其中r.window为PhoneWindow,decor就是装饰器DecorView,wm就是WindowManager。最后通过wm.addView(decor, l)方法,实现Activity布局的加载。这里还注意到WindowManager.LayoutParams的type参数为WindowManager.LayoutParams.TYPE_BASE_APPLICATION,也即是应用窗口类型(所有程序窗口的base窗口,其他应用程序窗口都显示在它上面),具体有关Window的窗口属性,可以参考博文Android悬浮窗原理解析(Window),想了解的同学,可以点击看看,这里有比较全的Window属性解释。

我们再来看一下wm,这里定义的类型是接口ViewManager,其实它就是WindowManager,这里主要是使用设计模式的里氏替换原则(源码中很多地方都用这原则)。wm主要是通过a.getWindowManager()赋值的,所以我们主要来看看Activity中的getWindowManager()方法

    public WindowManager getWindowManager() {
        return mWindowManager;
    }

mWindowMananger是Activity的一个属性变量,通过Activity的启动加载流程,Activity初始化过程中就会对mWindowManager进行赋值,而Activity初始化主要通过attach方法完成,所以我们继续来看Activity的attach方法

    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) {
        .......

        mWindow = PolicyManager.makeNewWindow(this);
        mWindow.setCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);

        ......
        mWindow.setWindowManager(null, mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        if (mParent != null) {
            mWindow.setContainer(mParent.getWindow());
        }
        mWindowManager = mWindow.getWindowManager();
        mCurrentConfig = config;
    }

这里是通过mWindow.getWindowManager()来赋值mWindowManager,而mWindow即PhoneWindow,这点在Activity布局加载流程中,已分析过。由于PhoneWindow是继承至Window,通过阅读源码分析知道,getWindowManager()方法,主要是window中完成实现的,所以我们具体来看看Window中的getWindowManager()方法


    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        mAppToken = appToken;
        mAppName = appName;
        if (wm == null) {
            wm = WindowManagerImpl.getDefault();//1.核心代码
        }
        mWindowManager = new LocalWindowManager(wm, hardwareAccelerated);//2.核心代码
    }

    public WindowManager getWindowManager() {
        return mWindowManager;
    }

这里,我们先来看一下注释1,WindowManagerImpl.getDefault(),这很明显是单例模式。我们继续来看看源码


    private final static WindowManagerImpl sWindowManager = new WindowManagerImpl();

    public static WindowManagerImpl getDefault() {
        return sWindowManager;
    }

这里wm就是WindowManagerImpl。我们来看看WindowManagerImpl类

public class WindowManagerImpl implements WindowManager {
 ......省略细节
}

我们再来看看注释2,也即LocalWindowManager类

private class LocalWindowManager extends WindowManagerImpl.CompatModeWrapper {

        private static final String PROPERTY_HARDWARE_UI = "persist.sys.ui.hw";

        private final boolean mHardwareAccelerated;

        LocalWindowManager(WindowManager wm, boolean hardwareAccelerated) {
            super(wm, getCompatInfo(mContext));
            mHardwareAccelerated = hardwareAccelerated ||
                    SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
        }

        public boolean isHardwareAccelerated() {
            return mHardwareAccelerated;
        }

        public final void addView(View view, ViewGroup.LayoutParams params) {
            ........
            super.addView(view, params);
        }
    }

我们继续来看看LocalWindowManager类继承的WindowManagerImpl的内部类CompatModeWrapper

 static class CompatModeWrapper implements WindowManager {
        private final WindowManagerImpl mWindowManager;
        private final Display mDefaultDisplay;
        private final CompatibilityInfoHolder mCompatibilityInfo;

        CompatModeWrapper(WindowManager wm, CompatibilityInfoHolder ci) {
            mWindowManager = wm instanceof CompatModeWrapper
                    ? ((CompatModeWrapper)wm).mWindowManager : (WindowManagerImpl)wm;
            if (ci == null) {
                mDefaultDisplay = mWindowManager.getDefaultDisplay();
            } else {
                mDefaultDisplay = Display.createCompatibleDisplay(
                        mWindowManager.getDefaultDisplay().getDisplayId(), ci);
            }

            mCompatibilityInfo = ci;
        }

        @Override
        public void addView(View view, android.view.ViewGroup.LayoutParams params) {
            mWindowManager.addView(view, params, mCompatibilityInfo);
        }

        @Override
        public void updateViewLayout(View view, android.view.ViewGroup.LayoutParams params) {
            mWindowManager.updateViewLayout(view, params);

        }

        @Override
        public void removeView(View view) {
            mWindowManager.removeView(view);
        }

        @Override
        public Display getDefaultDisplay() {
            return mDefaultDisplay;
        }

        @Override
        public void removeViewImmediate(View view) {
            mWindowManager.removeViewImmediate(view);
        }

        @Override
        public boolean isHardwareAccelerated() {
            return mWindowManager.isHardwareAccelerated();
        }
    }

WindowManagerImpl的内部类CompatModeWrapper实现了WindowManager接口,而WindowManager又实现了ViewManager接口

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

我们来看看ViewManager接口

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

这里实现ViewManager接口的有WindowManager,而WindowManagerImpl和CompatModeWrapper也都实现WindowManager接口,从而间接实现了ViewManager接口,也都实现的添加,更新和删除View的方法。

所以,在最开始处,以ViewManager定义的wm其实也就是LocalWindowManager,通过相互继承调用,其实最后调用的是WindowManagerImpl中的addView()方法,我们继续来看看此方法

 public void addView(View view) {
        addView(view, new WindowManager.LayoutParams(
            WindowManager.LayoutParams.TYPE_APPLICATION, 0, PixelFormat.OPAQUE));
    }

    public void addView(View view, ViewGroup.LayoutParams params) {
        addView(view, params, null, false);
    }

    public void addView(View view, ViewGroup.LayoutParams params, CompatibilityInfoHolder cih) {
        addView(view, params, cih, false);
    }

    private void addView(View view, ViewGroup.LayoutParams params,
            CompatibilityInfoHolder cih, boolean nest) {
        if (false) Log.v("WindowManager", "addView view=" + view);

        if (!(params instanceof WindowManager.LayoutParams)) {
            throw new IllegalArgumentException(
                    "Params must be WindowManager.LayoutParams");
        }

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

        ViewRootImpl root;
        View panelParentView = null;
        .......
            root = new ViewRootImpl(view.getContext());
            root.mAddNesting = 1;
            if (cih == null) {
                root.mCompatibilityInfo = new CompatibilityInfoHolder();
            } else {
                root.mCompatibilityInfo = cih;
            }

            view.setLayoutParams(wparams);

            if (mViews == null) {
                index = 1;
                mViews = new View[1];
                mRoots = new ViewRootImpl[1];
                mParams = new WindowManager.LayoutParams[1];
            } else {
                index = mViews.length + 1;
                Object[] old = mViews;
                mViews = new View[index]; 
                System.arraycopy(old, 0, mViews, 0, index-1);
                old = mRoots;
                mRoots = new ViewRootImpl[index];
                System.arraycopy(old, 0, mRoots, 0, index-1);
                old = mParams;
                mParams = new WindowManager.LayoutParams[index];
                System.arraycopy(old, 0, mParams, 0, index-1);
            }
            index--;

            mViews[index] = view;
            mRoots[index] = root;
            mParams[index] = wparams;
        }
        // do this last because it fires off messages to start doing things
        root.setView(view, wparams, panelParentView);
    }

这里有三个数组mViews,mRoots,mParams变量,mViews主要保存向Window中添加的View,mRoots主要保存实现绘制View的ViewRootImpl,mParams主要保存添加的Window参数,最后每一个添加的View都会调用root.setView(view, wparams, panelParentView)方法,实现View的绘制。关于这三个参数的作用,是因为WindowManager中可能添加多个Window,多个View,所以需要保存起来,方便删除和更新。

关于WindowManagerImpl的源码,这里需要注意一下,由于我用的版本是Andorid4.1.1_r1,源码如上,而在大于Andorid4.1.1_r11的版本,如Android5.1.1中的WindowManagerImpl源码的addView方法,主要是通过WindowManagerGlobal来实现的,逻辑也都和Andorid4.1.1_r1一样,只是把部分逻辑封装成WindowManagerGlobal,这里我就不多说,想了解的同学,可以自行查看。

到这里,DecorView添加入Window的流程就分析完了。接下来主要就是DecorView的绘制流程,也即View的绘制流程。

注:源码采用android-4.1.1_r1版本,建议下载源码然后自己走一遍流程,这样更能加深理解。

二、参考文档

Activity布局加载流程源码分析

Activity启动流程源码分析(应用中)

Android悬浮窗原理解析(Window)

展开阅读全文

Python数据分析与挖掘

01-08
92讲视频课+16大项目实战+源码+¥800元课程礼包+讲师社群1V1答疑+社群闭门分享会=99元   为什么学习数据分析?       人工智能、大数据时代有什么技能是可以运用在各种行业的?数据分析就是。       从海量数据中获得别人看不见的信息,创业者可以通过数据分析来优化产品,营销人员可以通过数据分析改进营销策略,产品经理可以通过数据分析洞察用户习惯,金融从业者可以通过数据分析规避投资风险,程序员可以通过数据分析进一步挖掘出数据价值,它和编程一样,本质上也是一个工具,通过数据来对现实事物进行分析和识别的能力。不管你从事什么行业,掌握了数据分析能力,往往在其岗位上更有竞争力。    本课程共包含五大模块: 一、先导篇: 通过分析数据分析师的一天,让学员了解全面了解成为一个数据分析师的所有必修功法,对数据分析师不在迷惑。   二、基础篇: 围绕Python基础语法介绍、数据预处理、数据可视化以及数据分析与挖掘......这些核心技能模块展开,帮助你快速而全面的掌握和了解成为一个数据分析师的所有必修功法。   三、数据采集篇: 通过网络爬虫实战解决数据分析的必经之路:数据从何来的问题,讲解常见的爬虫套路并利用三大实战帮助学员扎实数据采集能力,避免没有数据可分析的尴尬。   四、分析工具篇: 讲解数据分析避不开的科学计算库Numpy、数据分析工具Pandas及常见可视化工具Matplotlib。   五、算法篇: 算法是数据分析的精华,课程精选10大算法,包括分类、聚类、预测3大类型,每个算法都从原理和案例两个角度学习,让你不仅能用起来,了解原理,还能知道为什么这么做。
©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值