Android 窗口添加机制系列1-Activity

原创 2015年11月21日 16:16:22

参考:
1. Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析
2. Android4.0窗口机制token分析以及activitiy, dialog, toast 窗口创建过程分析

我们都知道Android屏幕显示的就是Window和各种View,其中顶层的其实是DecorView,然后被添加到了PhoneWindow中,然而Activity在其中的作用主要是管理生命周期、建立窗口等。也就是说Window相关的东西对于Android屏幕来说是至关重要的

Activity Window/WindowManager关系

ActivityThread类的performLaunchActivity方法中调运了activity.attach(…)方法进行初始化。
这个是不是很熟悉,可以参考我前一篇博客《Android Context详解》 这篇博客中有说

启动一个activity的时候,执行完application相关的动作之后,会去调用handleLaunchActivity,这个方法先调用performLaunchActivity方法,创建activity,调用onCreate,onStart等方法,然后调用handleResumeActivity方法去执行onResume方法(这个执行完后视图才在屏幕上刷新,用户可见)
同时有介绍attach方法中,还会为每个activity或者service绑定mApplication对象

        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类型的mWindow对象,实际为PhoneWindow类实现了抽象Window类
        mWindow = PolicyManager.makeNewWindow(this);
        ......
        //通过抽象Window类的setWindowManager方法给Window类的成员变量WindowManager赋值实例化
        mWindow.setWindowManager(
                (WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
                mToken, mComponent.flattenToString(),
                (info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);
        ......
        //把抽象Window类相关的WindowManager对象拿出来关联到Activity的WindowManager类型成员变量mWindowManager
        mWindowManager = mWindow.getWindowManager();
        ......
    }

mWindow实际上是PhoneWindow对象

    public Window makeNewWindow(Context context) {
        return new PhoneWindow(context);
    }

Activity类中的attach方法又创建了Window类型的新成员变量mWindow(PhoneWindow实现类)与Activity相关联,接着在Activity类的attach方法最后又通过mWindow.setWindowManager(…)方法创建了与Window相关联的WindowManager对象,最后又通过mWindow.getWindowManager()将Window的WindowManager成员变量赋值给Activity的WindowManager成员变量mWindowManager

    public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
            boolean hardwareAccelerated) {
        ......
        if (wm == null) {
            wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
        }
        //实例化Window类的WindowManager类型成员mWindowManager
        mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
public final class WindowManagerImpl implements WindowManager {
    ......
    private WindowManagerImpl(Display display, Window parentWindow) {
        mDisplay = display;
        mParentWindow = parentWindow;
    }
    ......
    public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
        return new WindowManagerImpl(mDisplay, parentWindow);
    }
    ......
}

这样就把Activity的Window与WindowManager关联起来了。Activity类的Window类型成员变量mWindow及WindowManager类型成员变量mWindowManager就是这么来的
接下来分析一下wm对象是怎么获取得到的

wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);

mContext其实实现类是ContextImpl,所以进入ContextImpl的getSystemService方法

    class ContextImpl extends Context {
    ......
    //静态代码块,类加载时执行一次
    static {
        ......
        //这里有一堆类似的XXX_SERVICE的注册
        ......
        registerService(WINDOW_SERVICE, new ServiceFetcher() {
                Display mDefaultDisplay;
                public Object getService(ContextImpl ctx) {
                    //搞一个Display实例
                    Display display = ctx.mDisplay;
                    if (display == null) {
                        if (mDefaultDisplay == null) {
                            DisplayManager dm = (DisplayManager)ctx.getOuterContext().
                                    getSystemService(Context.DISPLAY_SERVICE);
                            mDefaultDisplay = dm.getDisplay(Display.DEFAULT_DISPLAY);
                        }
                        display = mDefaultDisplay;
                    }
                    //返回一个WindowManagerImpl实例
                    return new WindowManagerImpl(display);
                }});
        ......
    }
    //这就是你在外面调运Context的getSystemService获取到的WindowManagerImpl实例
    @Override
    public Object getSystemService(String name) {
        ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
        return fetcher == null ? null : fetcher.getService(this);
    }
    //上面static代码块创建WindowManagerImpl实例用到的方法
    private static void registerService(String serviceName, ServiceFetcher fetcher) {
        if (!(fetcher instanceof StaticServiceFetcher)) {
            fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;
        }
        SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
    }
}

看见没有,我们都知道Java的静态代码块是类加载是执行一次的,也就相当于一个全局的,这样就相当于每个Application只有一个WindowManagerImpl(display)实例。

就是说如果最后调用是ContextImpl的getSystemService(Context.WINDOW_SERVICE)方法,那么返回的都是同一个WindowManagerImpl对象。此时注意activity基类中覆盖了getSystemService方法。

DecorView添加WindowManager流程

还记得我在《Android View视图层次》 中说过么?

在onCreate中调用了setContentView,所以把除了decorView之外的所有的view都已经添加进去了,形成了一个视图层次结构。然后ActivityThread的handleResumeActivity方法把decorView添加到了phonewindow中去了

复习一下

        final void handleResumeActivity(IBinder token,
            boolean clearHide, boolean isForward, boolean reallyResume) {
        // If we are getting ready to gc after going to the background, well
        // we are back active so skip it.
        ......
        // TODO Push resumeArgs into the activity for consideration
        ActivityClientRecord r = performResumeActivity(token, clearHide);

        if (r != null) {
            ......
            // If the window hasn't yet been added to the window manager,
            // and this guy didn't finish itself or start another activity,
            // then go ahead and add the window.
            ......
            // If the window has already been added, but during resume
            // we started another activity, then don't yet make the
            // window visible.
            ......
            // The window is now visible if it has been added, we are not
            // simply finishing, and we are not starting another activity.
            if (!r.activity.mFinished && willBeVisible
                    && r.activity.mDecor != null && !r.hideForNow) {
                ......
                if (r.activity.mVisibleFromClient) {
                    r.activity.makeVisible();
                }
            }
            ......
        } else {
            // If an exception was thrown when trying to resume, then
            // just end this activity.
            ......
        }
    }

Activity中makeVisible方法,把这个DecorView添加到wm中。。

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

看见makeVisible方法的wm变量没,这个变量就是Window类中通过调运WindowManagerImpl的createLocalWindowManager创建的WindowManagerImpl对象实例
WindowManagerImpl的addView方法如下:

public final class WindowManagerImpl implements WindowManager {
    //继承自Object的单例类
    private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
    ......
    public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) {
        applyDefaultToken(params);
        //mParentWindow是上面分析的在Activity中获取WindowManagerImpl实例化时传入的当前Window
        //view是Activity中最顶层的mDecor
        mGlobal.addView(view, params, mDisplay, mParentWindow);
    }
    ......
}

可以看到mGlobal是单例模式的WindowManagerGlobal成员mGlobal,addView最终调运了WindowManagerGlobal的addView

public final class WindowManagerGlobal {
    ......
    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>();

    ......
    public void addView(View view, ViewGroup.LayoutParams params,
            Display display, Window parentWindow) {
        ......
        //获取Activity的Window的getWindow().getAttributes()的LayoutParams 
        final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
        //如果是Activity中调运的,parentWindow=Window,如果不是Activity的,譬如是Context的静态代码块的实例化则parentWindow为null
        if (parentWindow != null) {
            //依据当前Activity的Window调节sub Window的LayoutParams
            parentWindow.adjustLayoutParamsForSubWindow(wparams);
        } else {
            ......
        }

        ViewRootImpl root;
        ......
        synchronized (mLock) {
            ......
            //为当前Window创建ViewRoot
            root = new ViewRootImpl(view.getContext(), display);
            view.setLayoutParams(wparams);
            //把当前Window相关的东西存入各自的List中,在remove中会删掉
            mViews.add(view);
            mRoots.add(root);
            mParams.add(wparams);
        }

        // do this last because it fires off messages to start doing things
        try {
            //把View和ViewRoot关联起来,很重要!!!
            root.setView(view, wparams, panelParentView);
        } catch (RuntimeException e) {
            ......
        }
    }
    ......
}

关键的几个地方,下面一一分析
WindowManagerGlobal.addView方法中第一个重要的地方
1. parentWindow.adjustLayoutParamsForSubWindow(wparams);
wparams是个什么鬼呢?
这个参数首先是从makeVisible方法执行wm.addView(mDecor, getWindow().getAttributes());传下来的
Window.java中

    private final WindowManager.LayoutParams mWindowAttributes =
        new WindowManager.LayoutParams();
    public final WindowManager.LayoutParams getAttributes() {
        return mWindowAttributes;
    }

可以看到,LayoutParams其实是WindowManager的一个内部类。这个内部类很重要,表示的是窗口的一些布局参数
WindowManager.LayoutParams中

    public static class LayoutParams extends ViewGroup.LayoutParams
            implements Parcelable {
        //WindowType:开始应用程序窗口
        public static final int FIRST_APPLICATION_WINDOW = 1;
        //WindowType:所有程序窗口的base窗口,其他应用程序窗口都显示在它上面
        public static final int TYPE_BASE_APPLICATION   = 1;
        //WindowType:普通应用程序窗口,token必须设置为Activity的token来指定窗口属于谁
        public static final int TYPE_APPLICATION        = 2;
        ............
        //WindowType:结束应用程序窗口
        public static final int LAST_APPLICATION_WINDOW = 99;

        //WindowType:SubWindows子窗口,子窗口的Z序和坐标空间都依赖于他们的宿主窗口
        public static final int FIRST_SUB_WINDOW        = 1000;
        ...........
        //WindowType:子窗口结束
        public static final int LAST_SUB_WINDOW         = 1999;

        public int type;
        public int gravity;
        /**
         * Identifier for this window.  This will usually be filled in for
         * you.
         */
        public IBinder token = null;
        public LayoutParams() {
            super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
            type = TYPE_APPLICATION;
            format = PixelFormat.OPAQUE;
        }
    }

这个类里面申请了很多常量,就不贴出来了,想要具体了解,看这里吧,Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析

  1. 应用程序窗口。一般应用程序的窗口,比如我们应用程序的Activity的窗口。
  2. 子窗口。一般在Activity里面的窗口,比如对话框等。
  3. 系统窗口。系统的窗口,比如输入法,Toast,墙纸等。

同时此时也说明

Activity窗体的WindowManager.LayoutParams类型是TYPE_APPLICATION。同时重点留意一下这里的type和token属性。

WindowManager.LayoutParams介绍完了,那么parentWindow.adjustLayoutParamsForSubWindow(wparams);这行代码的具体作用是什么呢?
Window.java中

    void adjustLayoutParamsForSubWindow(WindowManager.LayoutParams wp) {
        CharSequence curTitle = wp.getTitle();
        //如果是子窗口,那么就把wp的token参数设置为decorview的getWindowToken
        if (wp.type >= WindowManager.LayoutParams.FIRST_SUB_WINDOW &&
            wp.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW) {
            if (wp.token == null) {
                View decor = peekDecorView();
                if (decor != null) {
                    wp.token = decor.getWindowToken();
                }
            }
            if (curTitle == null || curTitle.length() == 0) {
                String title;
                if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA) {
                    title="Media";
                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA_OVERLAY) {
                    title="MediaOvr";
                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_PANEL) {
                    title="Panel";
                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL) {
                    title="SubPanel";
                } else if (wp.type == WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG) {
                    title="AtchDlg";
                } else {
                    title=Integer.toString(wp.type);
                }
                if (mAppName != null) {
                    title += ":" + mAppName;
                }
                wp.setTitle(title);
            }
        } else { //如果不是子窗口类型,那么把wp的token设置为window的mAppToken
            if (wp.token == null) {
                wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;//把wp的token设置为window的mAppToken
            }
            if ((curTitle == null || curTitle.length() == 0)
                    && mAppName != null) {
                wp.setTitle(mAppName);
            }
        }
        if (wp.packageName == null) {
            wp.packageName = mContext.getPackageName();
        }
        if (mHardwareAccelerated) {
            wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
        }
    }

上文我们知道,activity窗口的type是TYPE_APPLICATION,所以此时会执行到
wp.token = mContainer == null ? mAppToken : mContainer.mAppToken;
mContainer一般为空,那么window的mAppToken对象又是什么鬼呢?
记不记得上文中acitivty做attach的时候,把windowmanager和window绑定的时候调用的setWindowManager方法

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

看到木有,mAppToken = appToken;setWindowManager方法中appToken参数其实是activity中的mToken参数,这个参数其实就是performLaunchActivity中传递下来的

所以最后的结论是:

WindowManager.LayoutParams wp中的token其实就是activity的token

WindowManagerGlobal.addView方法中第二个重要的地方
2. root = new ViewRootImpl(view.getContext(), display);
此时说明了会为每个windowmanager都创建一个ViewRootImpl对象,ViewRootImpl很熟悉吧?《Android View绘制流程》
View绘制的流程都是从ViewRootImpl发起的!!!

WindowManagerGlobal.addView方法中第三个重要的地方
3. root.setView(view, wparams, panelParentView);

ViewRootImpl.setView方法

            public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {
                .......
                // Schedule the first layout -before- adding to the window
                // manager, to make sure we do the relayout before receiving
                // any other events from the system.
                requestLayout();
                ......
                try {
                    res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
                            getHostVisibility(), mDisplay.getDisplayId(),
                            mAttachInfo.mContentInsets, mAttachInfo.mStableInsets,
                            mAttachInfo.mOutsets, mInputChannel);
                }

                if (DEBUG_LAYOUT) Log.v(TAG, "Added window " + mWindow);
                if (res < WindowManagerGlobal.ADD_OKAY) {
                    mAttachInfo.mRootView = null;
                    mAdded = false;
                    mFallbackEventHandler.setView(null);
                    unscheduleTraversals();
                    setAccessibilityFocus(null, null);
                    switch (res) {
                        case WindowManagerGlobal.ADD_BAD_APP_TOKEN:
                        case WindowManagerGlobal.ADD_BAD_SUBWINDOW_TOKEN:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- token " + attrs.token
                                    + " is not valid; is your activity running?");
                        case WindowManagerGlobal.ADD_NOT_APP_TOKEN:
                            throw new WindowManager.BadTokenException(
                                    "Unable to add window -- token " + attrs.token
                                    + " is not for an application");

                .........
            }

首先会调用requestLayout();这个方法有木有很熟悉,这个方法会依次调用scheduleTraversals,doTraversal,performTraversals,然后是测量measure,布局layout,绘画draw流程。现在终于明白了吧,为什么view绘制的流程会从ViewRootImpl的performTraversals开始。

其实requestLayout和invalidate方法最终都是会调用ViewRootImpl的performTraversals,只是前者会重新导致view及其parent view的测量,布局流程,而invalidate只会导致当前view的绘画过程

另一方面
res = mWindowSession.addToDisplay..
这里其实就是调用Session对象的addToDisplay方法,进而调用WMS(WindowManagerService)的addWindow。。。看看mWindowSession对象在哪里生成的

    public ViewRootImpl(Context context, Display display) {
        mContext = context;
        mWindowSession = WindowManagerGlobal.getWindowSession();
        mWindow = new W(this);
        ....
    }
    static class W extends IWindow.Stub {

WindowManagerGlobal.getWindowSession方法

    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 IWindowManager getWindowManagerService() {
        synchronized (WindowManagerGlobal.class) {
            if (sWindowManagerService == null) {
                sWindowManagerService = IWindowManager.Stub.asInterface(
                        ServiceManager.getService("window"));
            }
            return sWindowManagerService;
        }
    }

看到没有,mWindowSession其实就是ServiceManager.getService(“window”),window系统服务的openSession方法返回的。然后可以看到,Session类中持有WindowManagerService对象的引用

    final WindowManagerService mService;
    @Override
    public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
            int viewVisibility, int displayId, Rect outContentInsets,
            InputChannel outInputChannel) {
        return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
                outContentInsets, outInputChannel);
    }

所以最后其实调用的是WindowManagerService的addWindow方法,现在知道传说中WMS的作用了吧,实际上就是是用来管理窗口的,最终都是交给WMS来管理

  1. 另外注意一下,可以看到addWindow中压根就没有window对象的参数,其实到了WMS那层,压根就没有窗口这一概念,其实人家管理的是View。WMS中addView中传进去的其实是IWindow,这个其实是ViewRootImpl中的W对象,mWindow
  2. ViewRootImpl负责管理视图树和与WMS交互,与WMS交互是通过WindowSession。而且ViewRootImpl也负责UI界面的布局与渲染,负责把一些事件分发至Activity,以便Activity可以截获事件。大多数情况下,它管理Activity顶层视图DecorView,它相当于MVC模型中的Controller。
  3. 从上面可以看出来,是mWindowSession.addToDisplay()这个方法把mWindow传递给我WMS,WMS就持有了当前ViewRootlmpl的代理,就可以调用W对象让ViewRootlmpl做一些事情了。
  4. 这样,双方都有了对方的接口,WMS中的Session注册到WindowManagerGlobal的成员WindowSession中,ViewRootImpl::W注册到WindowState中的成员mClient中。前者是为了App改变View结构时请求WMS为其更新布局。后者代表了App端的一个添加到WMS中的View,每一个像这样通过WindowManager接口中addView()添加的窗口都有一个对应的ViewRootImpl,也有一个相应的ViewRootImpl::W。它可以理解为是ViewRootImpl中暴露给WMS的接口,这样WMS可以通过这个接口和App端通信。

WindowSession是ViewRootImpl获取之后,主动和WMS通信的

    public int addWindow(Session session, IWindow client, int seq,
            WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
            Rect outContentInsets, InputChannel outInputChannel) {
        ........
        boolean addToken = false;
        WindowToken token = mTokenMap.get(attrs.token);
        .......
        else if (type >= FIRST_APPLICATION_WINDOW && type <= LAST_APPLICATION_WINDOW) {
                AppWindowToken atoken = token.appWindowToken;
                if (atoken == null) {
                    Slog.w(TAG, "Attempted to add window with non-application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_NOT_APP_TOKEN;
                } else if (atoken.removed) {
                    Slog.w(TAG, "Attempted to add window with exiting application token "
                          + token + ".  Aborting.");
                    return WindowManagerGlobal.ADD_APP_EXITING;
                }
                if (type == TYPE_APPLICATION_STARTING && atoken.firstWindowDrawn) {
                    // No need for this guy!
                    if (localLOGV) Slog.v(
                            TAG, "**** NO NEED TO START: " + attrs.getTitle());
                    return WindowManagerGlobal.ADD_STARTING_NOT_NEEDED;
                }
            }
        }
        ........
    }

看到没有,此时会去判断窗口的WindowManager.LayoutParams的token是否匹配,如果不匹配就报错
WindowManager.LayoutParams attrs
AppWindowToken atoken = token.appWindowToken;
想要知道更多token相关的知识请参考
Android4.0窗口机制token分析以及activitiy, dialog, toast 窗口创建过程分析

注意一下这里:下篇文章分析Dialog机制的时候,如果context使用不当,就会
return WindowManagerGlobal.ADD_NOT_APP_TOKEN;进而导致异常

throw new WindowManager.BadTokenException( "Unable to add window -- token " + attrs.token+ " is not for an application");

到这里终于分析完了,我们现在终于明白了

  1. activity和window/WindowManager的关系: 每个activity都有一个PhoneWindow和WindowManagerImpl对象
  2. ViewRootImpl的作用: 每个activity都会有一个ViewRootImpl对象,实际功能其实都是交给ViewRootImpl来处理的
  3. WMS(WindowManagerService)的作用: ViewRootImpl实际上是通过IBinder跨进程调用通过Session,然后交给WMS来管理的
  4. View是从什么时候开始绘制的: 当setContentView加载完所有的view,包括decorview时。调用ActivityThread的handleResumeActivity方法使View可见,然后把顶层的DecorView添加到windowmanager中,最终调用ViewRootImpl的setView方法,这其中调用requestLayout方法,导致了整个View视图层次的测量布局绘画过程。
版权声明:本文为博主原创文章,转载请注明出处,http://blog.csdn.net/mr_liabill

Android 带你彻底理解 Window 和 WindowManager

任何 View 都是附属在一个 Window 上面的,Window 表示一个窗口的概念,也是一个抽象的概念,Window 并不是实际存在的,它是以 View 的形式存在的。WindowManager ...
  • yhaolpz
  • yhaolpz
  • 2017年04月05日 23:31
  • 9004

Android源码解析(十八)-->Activity布局绘制流程

这篇文章是承接上一篇文章来写的,大家都知道Activity在Android体系中扮演者一个界面展示的角色,通过上一篇文章的分析,我们知道Activity是通过Window来控制界面的展示的,一个Win...

Android 一个窗口是怎么创建出来的?

前言 在WmS看来窗口并不是Window类,而是一个View类。WmS收到用户消息后,需要把消息发送到窗口,View类其实并不能直接接受传递过来的消息,而接受消息的必须是IWindow类,实现IWi...

Zygote进程启动过程源代码分析

Android系统借用Binder通信机制实现了C/S架构设计,客户端应用程序如需要实现某些功能,只需请求指定的服务,由服务端来实现。Android服务包括以上的系统服务和应用服务,系统服务是指And...

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析

【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重劳动成果】1 背景之所以写这一篇博客的原因是因为之前有写过一篇《Android应用setContentV...
  • yanbober
  • yanbober
  • 2015年06月08日 20:50
  • 33807

一、ANDROID应用ACTIVITY、DIALOG、POPWINDOW、TOAST窗口添加机制及源码分析

浅析Window与WindowManager相关关系及源码 通过上面那幅图可以很直观的看见,Android屏幕显示的就是Window和各种View,Activity在其中的作用主要是管理生命周期...

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析

【工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处,尊重劳动成果】 1 背景 之所以写这一篇博客的原因是因为之前有写过一篇《Android应用setConte...
  • asdcls
  • asdcls
  • 2015年06月17日 15:18
  • 1507

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《五》-Toast

5 Android应用Toast窗口添加显示机制源码 5-1 基础知识准备在开始分析这几个窗口之前需要脑补一点东东,我们从应用层开发来直观脑补,这样下面分析源码时就不蛋疼了。如下是一个我们写的两个应...

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《一》

浅析 Android 窗口的加载机制 以及Dialog PopWindow Toast显示机制

Android应用Activity、Dialog、PopWindow、Toast窗口添加机制及源码分析 《三》-Dialog

Dialog的需要主要的问题 以及实现机制
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android 窗口添加机制系列1-Activity
举报原因:
原因补充:

(最多只允许输入30个字)