IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> Android基础:Activity&Window&ViewRootImpl的关系 -> 正文阅读

[移动开发]Android基础:Activity&Window&ViewRootImpl的关系

前言

??为了描述Activity&Window&ViewRootImpl的关系,我们分别从以下三个阶段进行分析:

  1. Activity的启动流程;
  2. Activity的onCreate()阶段;
  3. Activity的resume流程;

一、Activity启动流程

??在Activity启动流程分析中分析过,App进程创建后,会在ActivityThread的performLaunchActivity()方法中会创建Activity实例。

1.1 ActivityThread.performLaunchActivity

??在ActivityThread.performLaunchActivity()执行流程中,和Window相关的代码从attach()方法开始分析:

public final class ActivityThread extends ClientTransactionHandler {
    private Activity performLaunchActivity(ActivityThread.ActivityClientRecord r, Intent customIntent) {
        Activity activity = null;
        java.lang.ClassLoader cl = appContext.getClassLoader();
        activity = mInstrumentation.newActivity(
                cl, component.getClassName(), r.intent);
        // 省略部分代码;从Activity的attach()方法开始分析
        activity.attach(appContext, this, getInstrumentation(), r.token,
                r.ident, app, r.intent, r.activityInfo, title, r.parent,
                r.embeddedID, r.lastNonConfigurationInstances, config,
                r.referrer, r.voiceInteractor, window, r.configCallback,
                r.assistToken);
    }
}

1.2 Window & PhoneWindow

??attach()方法中会涉及到创建Window。Window 是个抽象类,其具体实现类是 PhoneWindow,Activity 和 Dialog 中的 Window 对象都是 PhoneWindow。

??在Activity的attach()方法内创建了PhoneWindow对象,然后PhoneWindow内创建了WindowManager(WindowManager用来与系统进程system_server通信):

public class Activity {
    final void attach(Context context, ActivityThread aThread,
                      Instrumentation instr, IBinder token ...) {
        // 创建 PhoneWindow 对象
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setCallback(this);
        // 创建 WindowManagerImpl 对象
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        mWindowManager = mWindow.getWindowManager();
    }
}

??在mWindow.setWindowManager()方法内会创建WindowManager对象,代码分析如下。

1.3 WindowManager & WindowManagerImpl

??WindowManager是个接口,WindowManagerImpl其具体实现。每个Activity对应一个WindowManagerImpl。

public abstract class Window {
    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);
    }
}

??WindowManagerImpl中有个WindowManagerGlobal,所有WindowManagerGlobal都是用了这个单例,后面会涉及到:

public final class WindowManagerImpl implements WindowManager{
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
}

1.4 总结

??Activity的启动过程中,在ActivityThread的performLaunchActivity()方法中会创建Activity实例,接着Activity的attach()方法内会创建PhoneWindow,接着PhoneWindow会创建WindowManagerImpl,在创建WindowManagerImpl时会将mToken(IBinder类型)传给WindowManagerImpl,系统服务WindowManagerService和WindowManagerImpl就是通过mToken(IBinder类型)用Binder机制进行互相通信的。

二、Activity的onCreate()阶段

??在自定义Activity时,我们一般会在Activity的onCreate()方法内调用setContentView(),将layout布局设置给Activity:

public class MainActivity extends Activity{
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

??接下来,主要来看下这个过程有哪些涉及到Window的地方。

2.1 setContentView()

??在Activty的setContentView()方法内会调用PhoneWindow的setContentView()方法,PhoneWindow的setContentView()方法内会创建DecorView:

public class Activity {
    public void setContentView(@LayoutRes int layoutResID) {
        // 调用PhoneWindow的setContentView(),PhoneWindow内会创建DecorView
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
}

??PhoneWindow的setContentView()方法内创建DecorView的代码如下:

public class PhoneWindow extends Window implements MenuBuilder.Callback {
    public void setContentView(int layoutResID) {
        // 省略...
        if (mContentParent == null) {
            installDecor();
        } else if (!hasFeature(FEATURE_CONTENT_TRANSITIONS)) {
            mContentParent.removeAllViews();
        }
    }

    private void installDecor() {
        if (mDecor == null) {
            mDecor = generateDecor(-1);
        } else {
            mDecor.setWindow(this);
        }
    }

    protected DecorView generateDecor(int featureId) {
        // 省略...
        return new DecorView(context, featureId, this, getAttributes());
    }
}

2.2 总结

??在Activty的setContentView()方法内会调用PhoneWindow的setContentView()方法,PhoneWindow的setContentView()方法内会创建DecorView,之后PhoneWindow和DecorView彼此关联。

三、Activity的resume流程

??与Activity启动流程类似,Activity的resume流程也会经历系统进程然后调用到ActivityThread,下面首先来看下ActivityThread.handleResumeActivity()的逻辑。

3.1 ActivityThread.handleResumeActivity()

??在ActivityThread.handleResumeActivity()中,主要分析两个部分:(1)WindowManagerGlobal内创建ViewRootImpl;(2)WindowManager与DecorView相关联的过程。
重点了解第一个部分,第二个部分简单了解即可。

public final class ActivityThread {

    public void handleResumeActivity(IBinder token, boolean finalStateRequest, boolean isForward,
                                     String reason) {
        final android.app.ActivityThread.ActivityClientRecord r = performResumeActivity(token, finalStateRequest, reason);
        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();
            if (a.mVisibleFromClient) {
                if (!a.mWindowAdded) {
                    a.mWindowAdded = true;
                    // 1.内部会调用WindowManagerGlobal创建ViewRootImpl
                    wm.addView(decor, l);
                } else {
                    a.onWindowAttributesChanged(l);
                }
            }
        }
        if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) {
            ViewRootImpl impl = r.window.getDecorView().getViewRootImpl();
            if (r.activity.mVisibleFromClient) {
                // 2.将启动流程中创建的WindowManager与onCreate阶段创建的DecorView关联起来
                r.activity.makeVisible();
            }
        }
        Looper.myQueue().addIdleHandler(new android.app.ActivityThread.Idler());
    }
}

3.2 WindowManagerImpl

??在第一章的Activity启动流程中分析过,启动流程中会创建一个PhoneWindow和一个WindowManagerImpl,每个Activity对应一个WindowManagerImpl。WindowManagerImpl内持有WindowManagerGlobal单例。

public final class WindowManagerImpl {
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();

    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow,
                mContext.getUserId());
    }
}

3.2.1 WindowManagerGlobal

??WindowManagerGlobal是单例类,且调用系统服务的相关代码WindowManagerGlobal.getWindowManagerService()、WindowManagerGlobal.getWindowSession()也是单例实现:

public final class 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"));
                try {
                    if (sWindowManagerService != null) {
                        ValueAnimator.setDurationScale(
                                sWindowManagerService.getCurrentAnimatorScale());
                        sUseBLASTAdapter = sWindowManagerService.useBLAST();
                    }
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowManagerService;
        }
    }

    public static IWindowSession getWindowSession() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                    IWindowManager windowManager = getWindowManagerService();
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }
}

??WindowManagerGlobal单例类内管理着所有DecorView,ViewRootImpl也是在WindowManagerGlobal.addView()内完成创建的,代码分析如下:

public final class WindowManagerGlobal {
    // 所有view
    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>();
            
    public void addView(View view, ViewGroup.LayoutParams params,
                        Display display, Window parentWindow, int userId) {
        ViewRootImpl root;
        View panelParentView = null;
        synchronized (mLock) {
            // 1.创建ViewRootImpl
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            // 2.把decorView放入list
            mViews.add(view);
            // 3.把ViewRootImpl放入list
            mRoots.add(root);
            mParams.add(wparams);
            // 4.ViewRootImpl内创建SurfaceHolder,并调用系统服务进程创建Surface与SurfaceFlinger
            root.setView(view, wparams, panelParentView, userId);
        }
    }

    public static IWindowSession getWindowSession() {
        synchronized (android.view.WindowManagerGlobal.class) {
            if (sWindowSession == null) {
                try {
                    InputMethodManager.ensureDefaultInstanceForDefaultDisplayIfNecessary();
                    IWindowManager windowManager = getWindowManagerService();
                    // 调用系统服务WindowManagerService,系统服务进程会创建 Surface 与 SurfaceFlinger
                    sWindowSession = windowManager.openSession(
                            new IWindowSessionCallback.Stub() {
                                @Override
                                public void onAnimatorScaleChanged(float scale) {
                                    ValueAnimator.setDurationScale(scale);
                                }
                            });
                } catch (RemoteException e) {
                    throw e.rethrowFromSystemServer();
                }
            }
            return sWindowSession;
        }
    }
}

3.2.2 ViewRootImpl

??ViewRootImpl是一个很常见的类了,ViewRootImpl不是一个View,我们所熟悉的View绘制流程中的performMeasure()、performLayout()、performDraw()都是在performTraversals()方法中顺序调用的。本次不涉及到绘制流程分析,只分析ViewRootImpl创建过程中做了哪些操作。

??ViewRootImpl创建过程中,创建了SurfaceHolder,并调用系统服务进程WindowManagerService,系统服务进程会创建Surface与SurfaceFlinger:

public final class ViewRootImpl implements ViewParent,
        View.AttachInfo.Callbacks, ThreadedRenderer.DrawCallbacks {
        
    public ViewRootImpl(Context context, Display display) {
        // 获取 IWindowSession 的代理类
        this(context, display, android.view.WindowManagerGlobal.getWindowSession(),
                false /* useSfChoreographer */);
    }

    public ViewRootImpl(Context context, Display display, IWindowSession session,
                        boolean useSfChoreographer) {
        mContext = context;
        // 默认值是WindowManagerGlobal单例的WindowManagerGlobal.getWindowSession()
        mWindowSession = session;
        mDisplay = display;
        mBasePackageName = context.getBasePackageName();
        mThread = Thread.currentThread();
        mWindow = new android.view.ViewRootImpl.W(this);
        mChoreographer = useSfChoreographer
                ? Choreographer.getSfInstance() : Choreographer.getInstance();
        mDisplayManager = (DisplayManager)context.getSystemService(Context.DISPLAY_SERVICE);
    }

    public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView,
                        int userId) {
        synchronized (this) {
            if (mView == null) {
                mView = view;
                if (view instanceof RootViewSurfaceTaker) {
                    mSurfaceHolderCallback =
                            ((RootViewSurfaceTaker)view).willYouTakeTheSurface();
                    if (mSurfaceHolderCallback != null) {
                        // 1.创建SurfaceHolder
                        mSurfaceHolder = new android.view.ViewRootImpl.TakenSurfaceHolder();
                        mSurfaceHolder.setFormat(PixelFormat.UNKNOWN);
                        mSurfaceHolder.addCallback(mSurfaceHolderCallback);
                    }
                }
                requestLayout();
                // 2.mWindowSession会调用系统服务WindowManagerService,系统服务进程会创建Surface与SurfaceFlinger
                res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes,
                        getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame,
                        mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                        mAttachInfo.mDisplayCutout, inputChannel,
                        mTempInsets, mTempControls);
                setFrame(mTmpFrame);
            }
        }
    }
}

3.3 Activity.makeVisible()

??将启动流程中创建的WindowManager与onCreate阶段创建的DecorView关联起来的代码比较简单:

public class Activity {
    void makeVisible() {
        if (!mWindowAdded) {
            ViewManager wm = getWindowManager();
            wm.addView(mDecor, getWindow().getAttributes());
            mWindowAdded = true;
        }
        mDecor.setVisibility(View.VISIBLE);
    }
}

3.4 总结

  1. 在Activity的启动流程中,会创建一个PhoneWindow和一个WindowManagerImpl,每个Activity对应一个WindowManagerImpl。
  2. 在Activty的setContentView()方法内会调用PhoneWindow的setContentView()方法,PhoneWindow的setContentView()方法内会创建DecorView:
  3. 在Activity的resume流程中,会调用WindowManagerGlobal创建ViewRootImpl,接着ViewRootImpl会创建SurfaceHolder,并通过WindowManagerGlobal.getWindowSession()调用系统服务WindowManagerService创建Surface与SurfaceFlinger;
  4. 每个PhoneWindow都持有WindowManagerGlobal单例,WindowManagerGlobal管理着所有的ViewRootImpl和DecorView.
    ??至此,Activity&Window&ViewRootImpl的关系分析结束。

四、Dialog

??在Dialog的创建过程中,也与Activity相似的创建PhoneWindow、ViewRootImp流程。例如,一般自定义Dialog的的操作如下:

Dialog dialog = new Dialog(this);
dialog.setContentView(R.layout.bc_dialog_layout);
dialog.show();

??其中主要来分析Dialog构造函数和Dialog.setContent()、Dialog.show()方法,在构造函数中创建了PhoneWindow,在Dialog.setContent()方法中创建了DecorView、在Dialog.show()方法中创建了ViewRootImp:

public class Dialog{

    private Activity mOwnerActivity;
    private final WindowManager mWindowManager;
    final Context mContext;
    final Window mWindow;
    View mDecor;

    Dialog(Context context, int themeResId, boolean createContextThemeWrapper) {
        // 获取WindowManager
        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        // 创建PhoneWindow
        final Window w = new PhoneWindow(mContext);
        mWindow = w;
        w.setCallback(this);
        w.setOnWindowDismissedCallback(this);
        w.setOnWindowSwipeDismissedCallback(() -> {
            if (mCancelable) {
                cancel();
            }
        });
        w.setWindowManager(mWindowManager, null, null);
        w.setGravity(Gravity.CENTER);
        mListenersHandler = new android.app.Dialog.ListenersHandler(this);
    }

    public void setContentView(int layoutResID) {
        mWindow.setContentView(layoutResID);
    }

    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;
        }
        onStart();
        mDecor = mWindow.getDecorView();
        WindowManager.LayoutParams l = mWindow.getAttributes();

        // addView流程与上面分析的类似,里面创建了ViewRootImpl
        mWindowManager.addView(mDecor, l);
        mShowing = true;
        sendShowMessage();
    }
}

五、抽象的Window

??Window本身是一个抽象的概念,例如按照以下方式也可以显示一个View,这个过程并没有真正创建PhoneWindow,但是把自定义view所在抽象window的parentWindow设置为了Activity的Window。

// window内要展示的view
View view = LayoutInflater.from(this).inflate(R.layout.layout_bc_window, null);
int flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
        | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
// window的参数
WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(
        WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT,
        WindowManager.LayoutParams.TYPE_SYSTEM_ERROR, flags,
        PixelFormat.TRANSPARENT);
layoutParams.gravity = Gravity.CENTER;
layoutParams.x = 0;
layoutParams.y = 0;
// 获取WindowManager
WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
// WindowManager添加自定义view及windowLayoutParams;
// 方法内会创建一个decorView、ViewRootImpl,然后将自定义view添加到decorView中
windowManager.addView(view, layoutParams);

The End

欢迎关注我,一起解锁更多技能:BC的掘金主页~💐?BC的CSDN主页~💐💐
个人信息汇总.png

在线查看Android源码:https://cs.android.com/

Android源码下载:https://source.android.google.cn/setup/downloading?hl=zh-cn

Anroid studio内源码查看方法:https://github.com/anggrayudi/android-hidden-api

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:54:07  更:2022-04-18 17:57:37 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 21:27:00-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码