zoukankan      html  css  js  c++  java
  • activity&window&windowManager&view&viewGroup&application&context&applicationContext

    原文链接: http://blog.csdn.net/xieqibao/article/details/6570080

    一。 Android 之 Window、WindowManager 与窗口管理

    其实在android中真正展示给用户的是window和view,activity在android中所其的作用主要是处理一些逻辑问题,比如生命周期的管理、建立窗口等。在android中,窗口的管理还是比较重要的一块,因为他直接负责把内容展示给用户,并和用户进行交互。响应用户的输入等。

    在讲窗口管理时,有必要先说下ViewManager这个接口,这个接口主要有以下的实现子接口和实现类,分别是:WindowManager和ViewGroup里面还有三个重要的方法:

         * addView();

         * updateViewLayout();

         * removeView();

    在WindowManager中,addView方法表示的是将主窗口中的顶级view(也就是DecorView)添加到WindowManager中,并建立会话。接下来会详细介绍。我们先来看看Window

    Window:

    Window是android中的窗口,表示顶级窗口的意思,也就是主窗口,它有两个实现类,PhoneWindow和MidWindow,我们一般的activity对应的主要是PhoneWindow,在activity中经常使用的setContentView等方法也是在这个里面实现的。

    @Override

    public void setContentView(View view,ViewGroup.LayoutParams params) {

        if (mContentParent == null) {

        installDecor();

    } else {

        mContentParent.removeAllViews();

    }

    mContentParent.addView(view, params);

    final Callback cb = getCallback();

    if (cb != null) {

    cb.onContentChanged(); //窗口类容发生变化时更新

    }

    }

    每个主窗口中都有一个View,称之为DecorView,是主窗口中的顶级view(实际上就是ViewGroup),在View中有两个成员变量叫做mParent、mChildren,它是用来管理view的上下级关系的。而ViewGroup是对一组View的管理。因此,在ViewGroup中建立了所有view的关系网。而最终ViewGroup附属在主窗口上。这样就很容易在窗口中通过findViewById找到具体的View了。view中的事件处理也是根据这个路径来处理的。

    我们再来看看ActivityThead中的两个重要的方法(至于ActivityThead将在一篇中详细介绍):

    performLaunchActivity( );

    handleResumeActivity( );

    在performLaunchActivity中,会调用activity.attach方法建立一个window, 在handleResumeActivity方法中启动activity的时候,会将主窗口加入到WindowManager中

    View decor =r.window.getDecorView(); //获得窗口的顶级View

    decor.setVisibility(View.INVISIBLE);

    ViewManager wm= a.getWindowManager(); //WindowManager继承自ViewManager

    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); //实际上是把主窗口的顶级view加入到WindowMangaer

    }

    我们再来看看WindowManager。

    WindowManager:

    WindowManager主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等。

    通过Context.getSystemService(Context.WINDOW_SERVICE)的方式可以获得WindowManager的实例.

    WindowManager继承自ViewManager,里面涉及到窗口管理的三个重要方法,分别是:

         * addView();

         * updateViewLayout();

         * removeView(); 

    在WindowManager中还有一个重要的静态类LayoutParams.通过它可以设置和获得当前窗口的一些属性。

    我们先来看看addView()方法,在addView中,会利用LayoutParams获得window的View属性,并为每个window创建ViewRoot,ViewRoot是View和WindowManager之间的桥梁,真正把View传递给WindowManager的是通过ViewRoot的setView()方法,ViewRoot实现了View和WindowManager之间的消息传递。在将主窗口添加到WindowManger时,它首先会建立一个代理对象:

    wm=(WindowManagerImpl)context.getSystemService(Context.WINDOW_SERVICE)

    并且打开会话(IWindowSession),之后Window将通过该会话与WindowManager建立联系,

    来看下setView方法:

    try {

        res =sWindowSession.add(mWindow, mWindowAttributes,

        getHostVisibility(), mAttachInfo.mContentInsets);

    } catch (RemoteException e) {

        mAdded = false;

        mView = null;

        mAttachInfo.mRootView =null;

        unscheduleTraversals();

        throw newRuntimeException("Adding window failed", e);

    } finally {

        if (restore) {

        attrs.restore();

        }

    }

    在这段代码中,ViewRoot通过IWindowSession把窗口添加到WindowManager中。ViewRoot继承了Handler,实际上它的本质就是一个Handler,窗口中View的事件处理、消息发送、回调等将通过ViewRoot来处理。

    这样就完成了把窗口添加到WindowManager中,并交由WindowManager来管理窗口的view、事件、消息收集处理等。

    二。Android 之ActivityThead、ActivityManagerService 与activity的管理和创建

    在android中,Activity是四大组件中比较重要的一个(当然其他的也比较重要),那么android中是怎样管理这些activity的?应用的进程和主线程是怎么创建的,应用的消息循环又是在什么时候创建的?在这篇文章中将详细介绍:

    先来看下涉及到的类,通过以下类图对整体先有个大概的印象:

    ActivityThread:

    ActivityThread主要用来启动应用程序的主线程,并且管理在应用端跟用户打交道的activity。在应用端的activity信息全部被存储在ActivityThread的成员变量mActivities中。

    final HashMap<IBinder, ActivityRecord> mActivities= new  HashMap<IBinder, ActivityRecord>();  

    也就是说,在mActivities中,记录了应用程序创建的所有activity实例记录,对应的是ActivityRecord。

    ActivityThread是怎么启动应用程序的呢?ActivityThread中有一个main函数,在这个里面,将启动应用程序并建立消息循环。在之前也介绍过,系统会为主线程自动创建消息循环。

        /*** 应用程序的启动入口 . ,主线程在启动的时候系统会自动建立消息循环机制。 */
            public static final void main(String[] args) {
                SamplingProfilerIntegration.start();
                Process.setArgV0("<pre-initialized>");
                Looper.prepareMainLooper();
                ActivityThread thread = new ActivityThread();
                thread.attach(false);
                Looper.loop();
                if (Process.supportsProcesses()) {
                    throw new RuntimeException("Main thread loop unexpectedly exited");
                }
                thread.detach();
                String name = (thread.mInitialApplication != null) ? thread.mInitialApplication
                        .getPackageName() : "<unknown>";
                Slog.i(TAG, "Main thread of " + name + " is now exiting");
            }

    在建立消息循环之前,会通过thread.attach(false)来初始化应用程序的运行环境,并建立activityThread和ActivityManagerService之间的桥mAppThread, mAppThread是IApplicationThread的一个实例。

      android.ddm.DdmHandleAppName.setAppName("<pre-initialized>");
              RuntimeInit.setApplicationObject(mAppThread.asBinder());
              IActivityManager mgr = ActivityManagerNative.getDefault();
              try {
                  mgr.attachApplication(mAppThread);
              } catch (RemoteException ex) {
              }

    注意:每个应用程序对应着一个ActivityThread实例,应用程序由ActivityThread.main打开消息循环。每个应用程序同时也对应着一个ApplicationThread对象。该对象是activityThread和ActivityManagerService之间的桥梁。

    在attach中还做了一件事情,就是通过代理调用attachApplication,并利用binder的transact机制,在ActivityManagerService中建立了ProcessRecord信息。

    之后通过该ProcessRecord就可以获得该ActivityThread中的所有ActivityRecord记录。下面会介绍。

    ActivityManagerService:

    在ActivityManagerService中,也有一个用来管理activity的地方:mHistory栈,这个mHistory栈里存放的是服务端的activity记录HistoryActivity(class HistoryRecord extendsIApplicationToken.Stub)。处于栈顶的就是当前running状态的activity。

    我们来看一下Activity的startActivity方法的请求过程:

    从该时序图中可以看出,Activity.startActivity()方法最终是通过代理类和Binder机制,在ActivityManagerService.startActivity方法中执行的。

    那么在ActivityManagerService的startActivity中,主要做了那些事情?我们来看下里面比较重要的代码段:

    • 根据activity、ProcessRecord等信息创建HistoryRecord实例r
      1. HistoryRecord r = new HistoryRecord(this, callerApp, callingUid,intent, resolvedType, aInfo, mConfiguration,resultRecord, resultWho, requestCode, componentSpecified); 
    • 把r加入到mHistory中。
      1. mHistory.add(addPos, r);  
    • activity被加入到mHistory之后,只是说明在服务端可以找到该activity记录了,但是在客户端目前还没有该activity记录。还需要通过ProcessRecord中的thread(IApplication)变量,调用它的scheduleLaunchActivity方法在ActivityThread中创建新的ActivityRecord记录(之前我们说过,客户端的activity是用ActivityRecord记录的,并放在mActivities中)。
      1. app.thread.scheduleLaunchActivity(new Intent(r.intent), r,System.identityHashCode(r),                    r.info, r.icicle, results, newIntents, !andResume,                    isNextTransitionForward()); 

    涉及的主要类图:

    再来看下ApplicationThread中的scheduleLaunchActivity方法:

    1. public final void scheduleLaunchActivi(Intent intent, IBinder token, int ident,  ActivityInfo info, Bundle state, List<ResultInfo> pendingResults, List<Intent> pendingNewIntents,
    2. boolean notResumed, boolean isForward) {
    3.             ActivityRecord r = new ActivityRecor();
    4. r.token = token;
    5.            r.ident = ident;
    6.            r.intent = intent;
    7.             r.activityInfo = info; 
    8.           r.state = state;
    9.            r.pendingResults = pendingResults;
    10.            r.pendingIntents = pendingNewIntents;
    11.            r.startsNotResumed = notResumed;            r.isForward = isForward;            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);        } 

    在这个里面主要是根据服务端返回回来的信息创建客户端activity记录ActivityRecord. 并通过Handler发送消息到消息队列,进入消息循环。在ActivityThread.handleMessage()中处理消息。最终在handleLaunchActivity方法中把ActivityRecord记录加入到mActivities(mActivities.put(r.token,r))中,并启动activity(涉及到window、view、windowManager,详情请看handleResumeActivity()方法和上一篇关于window、WindowManager的介绍)

    总结:

    1. 在客户端和服务端分别有一个管理activity的地方,服务端是在mHistory中,处于mHistory栈顶的就是当前处于running状态的activity,客户端是在mActivities中。
    2. 在startActivity时,首先会在ActivityManagerService中建立HistoryRecord,并加入到mHistory中,然后通过scheduleLaunchActivity在客户端创建ActivityRecord记录并加入到mActivities中。最终在ActivityThread发起请求,进入消息循环,完成activity的启动和窗口的管理等
  • 相关阅读:
    CSS之各种居中
    三步教会你装系统
    65条最常用正则表达式
    MongoDB介绍
    MongoDB基本命令用
    log4j配置
    使用spring + ActiveMQ 总结
    log4j配置文件
    如何入侵局域网电脑
    目标检测的图像特征提取
  • 原文地址:https://www.cnblogs.com/olvo/p/2482553.html
Copyright © 2011-2022 走看看