Activity、Window、View三者关系

目录介绍

  • 01.Window,View,子Window
  • 02.什么是Activity
  • 03.什么是Window
  • 04.什么是DecorView
  • 05.什么是View
  • 06.关系结构图
  • 07.Window建立过程
  • 08.建立机制分析php

    • 8.1 Activity实例的建立
    • 8.2 Activity中Window的建立
    • 8.3 DecorView的建立

弹窗系列博客

  • 01.Activity、Window、View三者关系java

    • 深刻分析Activity、Window、View三者之间的关系
  • 02.Toast源码深度分析android

    • 最简单的建立,简单改造避免重复建立,show()方法源码分析,scheduleTimeoutLocked吐司如何自动销毁的,TN类中的消息机制是如何执行的,普通应用的Toast显示数量是有限制的,用代码解释为什么Activity销毁后Toast仍会显示,Toast偶尔报错Unable to add window是如何产生的,Toast运行在子线程问题,Toast如何添加系统窗口的权限等等
  • 03.DialogFragment源码分析git

    • 最简单的使用方法,onCreate(@Nullable Bundle savedInstanceState)源码分析,重点分析弹窗展现和销毁源码,使用中show()方法遇到的IllegalStateException分析
  • 04.Dialog源码分析github

    • AlertDialog源码分析,经过AlertDialog.Builder对象设置属性,Dialog生命周期,Dialog中show方法展现弹窗分析,Dialog的dismiss销毁弹窗,Dialog弹窗问题分析等等
  • 05.PopupWindow源码分析segmentfault

    • 显示PopupWindow,注意问题宽和高属性,showAsDropDown()源码,dismiss()源码分析,PopupWindow和Dialog有什么区别?为什么弹窗点击一下就dismiss呢?
  • 06.Snackbar源码分析app

    • 最简单的建立,Snackbar的make方法源码分析,Snackbar的show显示与点击消失源码分析,显示和隐藏中动画源码分析,Snackbar的设计思路,为何Snackbar老是显示在最下面
  • 07.弹窗常见问题ide

    • DialogFragment使用中show()方法遇到的IllegalStateException,什么常见产生的?Toast偶尔报错Unable to add window,Toast运行在子线程致使崩溃如何解决?
  • 09.onAttachedToWindow和onDetachedFromWindow源码分析

    • onAttachedToWindow的调用过程,onDetachedFromWindow能够作什么?
  • 10.DecorView介绍布局

    • 什么是DecorView,DecorView的建立,DecorView的显示,深度解析

01.Window,View,子Window

  • 弹窗有哪些类型

    • 使用子窗口:在 Android 进程内,咱们能够直接使用类型为子窗口类型的窗口。在 Android 代码中的直接应用是 PopupWindow 或者是 Dialog 。这固然能够,不过这种窗口依赖于它的宿主窗口,它可用的条件是你的宿主窗口可用
    • 采用View系统:使用 View 系统去模拟一个窗口行为,且能更加快速的实现动画效果,好比SnackBar 就是采用这套方案
    • 使用系统窗口:好比吐司Toast

02.什么是Activity

  • Activity并不负责视图控制,它只是控制生命周期和处理事件。真正控制视图的是Window。一个Activity包含了一个Window,Window才是真正表明一个窗口。
  • Activity就像一个控制器,统筹视图的添加与显示,以及经过其余回调方法,来与Window、以及View进行交互。

03.什么是Window

  • Window是什么?

    • 表示一个窗口的概念,是全部View的直接管理者,任何视图都经过Window呈现(点击事件由Window->DecorView->View; Activity的setContentView底层经过Window完成)
    • Window是一个抽象类,具体实现是PhoneWindow。PhoneWindow中有个内部类DecorView,经过建立DecorView来加载Activity中设置的布局R.layout.activity_main
    • 建立Window须要经过WindowManager建立,经过WindowManager将DecorView加载其中,并将DecorView交给ViewRoot,进行视图绘制以及其余交互。
    • WindowManager是外界访问Window的入口
    • Window具体实现位于WindowManagerService中
    • WindowManager和WindowManagerService的交互是经过IPC完成
  • 如何经过WindowManager添加Window(代码实现)?

    • 以下所示

      //1. 控件 
      Button button = new Button(this); 
      button.setText("Window Button"); 
      //2. 布局参数 
      WindowManager.LayoutParams layoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT, WindowManager.LayoutParams.WRAP_CONTENT, 0, 0, PixelFormat.TRANSPARENT); 
      layoutParams.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED; 
      layoutParams.gravity = Gravity.LEFT | Gravity.TOP; 
      layoutParams.x = 100; 
      layoutParams.y = 300; 
      // 必需要有type否则会异常: the specified window type 0 is not valid 
      layoutParams.type = WindowManager.LayoutParams.TYPE_SYSTEM_ERROR; 
      //3. 获取WindowManager并添加控件到Window中 
      WindowManager windowManager = getWindowManager(); 
      windowManager.addView(button, layoutParams);
  • WindowManager的主要功能是什么?

    • 添加、更新、删除View

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

04.什么是DecorView

  • DecorView是FrameLayout的子类,它能够被认为是Android视图树的根节点视图。

    • DecorView做为顶级View,通常状况下它内部包含一个竖直方向的LinearLayout,在这个LinearLayout里面有上下三个部分,上面是个ViewStub,延迟加载的视图(应该是设置ActionBar,根据Theme设置),中间的是标题栏(根据Theme设置,有的布局没有),下面的是内容栏。
    • 具体状况和Android版本及主体有关,以其中一个布局为例,以下所示:
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:fitsSystemWindows="true"
        android:orientation="vertical">
        <!-- Popout bar for action modes -->
        <ViewStub
            android:id="@+id/action_mode_bar_stub"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:inflatedId="@+id/action_mode_bar"
            android:layout="@layout/action_mode_bar"
            android:theme="?attr/actionBarTheme" />
    
        <FrameLayout
            style="?android:attr/windowTitleBackgroundStyle"
            android:layout_width="match_parent"
            android:layout_height="?android:attr/windowTitleSize">
    
            <TextView
                android:id="@android:id/title"
                style="?android:attr/windowTitleStyle"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:background="@null"
                android:fadingEdge="horizontal"
                android:gravity="center_vertical" />
        </FrameLayout>
    
        <FrameLayout
            android:id="@android:id/content"
            android:layout_width="match_parent"
            android:layout_height="0dip"
            android:layout_weight="1"
            android:foreground="?android:attr/windowContentOverlay"
            android:foregroundGravity="fill_horizontal|top" />
    </LinearLayout>
  • 在Activity中经过setContentView所设置的布局文件其实就是被加到内容栏之中的,成为其惟一子View,就是上面的id为content的FrameLayout中,在代码中能够经过content来获得对应加载的布局。

    ViewGroup content = (ViewGroup)findViewById(android.R.id.content);
    ViewGroup rootView = (ViewGroup) content.getChildAt(0);

06.关系结构图

  • Activity 与 PhoneWindow 与 DecorView 关系图

    • image

07.Window建立过程

  • App点击桌面图片启动过程

    • image
  • window启动流程

    • image
  • Activity 与 PhoneWindow 与 DecorView 之间什么关系?

    • 一个 Activity 对应一个 Window 也就是 PhoneWindow,一个 PhoneWindow 持有一个 DecorView 的实例,DecorView 自己是一个 FrameLayout。

08.建立机制分析

8.1 Activity实例的建立

  • ActivityThread中执行performLaunchActivity,从而生成了Activity的实例。源码以下所示,ActivityThread类中源码

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
        ...
        Activity activity = null;
        try {
            java.lang.ClassLoader cl = r.packageInfo.getClassLoader();
            activity = mInstrumentation.newActivity(
                    cl, component.getClassName(), r.intent);
            ...
        } catch (Exception e) {
            ...
        }
    
        try {
            ...
            if (activity != null) {
                ...
                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);
                ...
            }
            ...
        } catch (SuperNotCalledException e) {
            throw e;
        } catch (Exception e) {
            ...
        }
    
        return activity;
    }

8.2 Activity中Window的建立

  • 从上面的performLaunchActivity能够看出,在建立Activity实例的同时,会调用Activity的内部方法attach
  • 在attach该方法中完成window的初始化。源码以下所示,Activity类中源码

    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) {
    
        mWindow = new PhoneWindow(this, window, activityConfigCallback);
        mWindow.setWindowControllerCallback(this);
        mWindow.setCallback(this);
        mWindow.setOnWindowDismissedCallback(this);
        mWindow.getLayoutInflater().setPrivateFactory(this);
        if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
            mWindow.setSoftInputMode(info.softInputMode);
        }
        if (info.uiOptions != 0) {
            mWindow.setUiOptions(info.uiOptions);
        }
    }

8.3 DecorView的建立

  • 用户执行Activity的setContentView方法,内部是调用PhoneWindow的setContentView方法,在PhoneWindow中完成DecorView的建立。流程

    • 1.Activity中的setContentView
    • 2.PhoneWindow中的setContentView
    • 3.PhoneWindow中的installDecor
    public void setContentView(@LayoutRes int layoutResID) {
        getWindow().setContentView(layoutResID);
        initWindowDecorActionBar();
    }
    
    @Override
    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();
            mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
            mDecor.setIsRootNamespace(true);
            if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
            }
        }
        ...
    }

关于其余内容介绍

01.关于博客汇总连接

02.关于个人博客

GitHub连接:https://github.com/yangchong211

相关文章
相关标签/搜索