美文网首页Android知识
Activity启动过程及界面绘制流程解析开篇

Activity启动过程及界面绘制流程解析开篇

作者: 此生红黑 | 来源:发表于2016-05-26 14:17 被阅读1865次
    1.前言

    关于activity的启动过程及界面绘制的流程的学习也已经有一段时间,是时候写一段文字来记录下学习的心得和体会了。一来可以归纳和总结所学的知识作为以后复习的资料,二来也可以给想学习android源码的同学一点启示。这也是写这篇文章的初衷。既然提到了android源码,有人可能心存疑惑,为什么我只做应用层的东西却要去研究android底层的一些代码。起初我也在这个问题上困扰过,可能是出于好奇心,对于我们写的程序最终为什么能显示在终端上始终充满疑问,正是这个原因让我开始着手学习关于android源码的一些东西。在学习源码之后,感觉这个问题已经烟消云散了,因为确实能学到一些东西,但是由于水平有限,在此不作过多的说明。如果你还心存疑惑,不妨先看下有没有必要阅读Android源码这篇文章,结合源码的学习,技术肯定能更上一个台阶。

    2.Binder机制

    在学习activity的启动过程及界面绘制的流程中,发现binder机制大量存在于android framework层的代码中,刚开始学的时候,确实是被binder机制搞得一个头两个大,所以在学习启动过程和绘制流程之前我们先来学习下binder机制。binder机制可以说是android源码比较复杂的一个部分,至今对binder机制还不是很懂,也只是了解个大概的流程,因为binder机制涉及到内核层,及c++的一些东西,而我对这些东西都不了解,所以在此也只能谈个大概。因为我们的主线是关于activity的启动流程及界面绘制,所以我接下来也只会在这个主线的基础分析binder机制。

    Binder机制的概念

    binder机制的这个概念来自老罗的博客,感谢老罗。

    Binder是Android系统进程间通信(IPC)方式之一,用于跨进程间的方法调用。从字面上理解binder是"粘结剂"的意思,那么google的工程师为什会以"粘结剂"来命名binder呢?这是因为binder是基于一种Client-Server通信方式,也就是我们所说的CS架构,在这个架构中存在着4个组件,分别是Client、Server、Service Manager和Binder驱动程序,binder这个"粘结剂"正是将这四个组件连接在一起。其中Client、Server运行在两个不同的进程,他们进行跨进程调用需要binder驱动作基础设施,Service Manager管理binder Server。

    初学binder的我们肯定对这个概念不太好理解,接下来我会通过aidl实例来初步介绍如何通过binder来完成进程间通信。

    以aidl实例初步了解binder机制

    现在思考一个情景:设想有两个进程A和B,A进程充当一个图书管理员的角色,B进程可以向A进程添加图书,当B进程收到A进程添加的图书时,通知A进程,图书已经添加成功。了解场景之后,我们通过aidl来实现这个需求。下文贴出binder服务端与客户端的代码。
    #######binder服务端
    使用一个远程Service模拟进程A,提供binder服务端。

    package com.shine.binderdemo;
    
    import android.app.Service;
    import android.content.Intent;
    import android.os.IBinder;
    import android.os.RemoteException;
    
    import java.util.concurrent.CopyOnWriteArrayList;
    
    public class MyService extends Service {
    
        private CopyOnWriteArrayList<Book> booklist;
        private IOnBookAddListener mListener;
    
        private IBinder mBinder = new IBookManager.Stub() {
    
            @Override
            public void addBook(Book book) throws RemoteException {
                booklist.add(book);
                if (mListener != null) {
                    mListener.onBookadd(book);
                }
            }
    
            @Override
            public void registerListener(IOnBookAddListener listener) throws RemoteException {
                mListener = listener;
            }
        };
    
        @Override
        public void onCreate() {
            super.onCreate();
            booklist = new CopyOnWriteArrayList();
        }
    
    
        @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    }
    
    

    在AndroidManifest.xml中通过process属性使MyService 运行在其他进程。
    有一点我们需要格外注意:我们看到在用来存放添加书籍的booklist是一个CopyOnWriteArrayList。为什么在这要用CopyOnWriteArrayList呢?这是因为binder服务端在接收到客户端的请求访问时都会在一个单独的线程中处理这个请求,所以会出现线程安全问题,在这个地方通过CopyOnWriteArrayList来避免出现的线程安全问题,这个过程在子线程中完成也可以通过客户端的代码来验证。
    #######binder客户端
    在activity中绑定服务来模拟进程B,通过binder跨进程调用A的添加图书的方法,实现binder客户端。

    package com.shine.binderdemo;
    
    import android.content.ComponentName;
    import android.content.Context;
    import android.content.Intent;
    import android.content.ServiceConnection;
    import android.os.Bundle;
    import android.os.IBinder;
    import android.os.RemoteException;
    import android.support.v7.app.AppCompatActivity;
    import android.view.View;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private IBookManager mBookManager;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            Intent intent = new Intent(this, MyService.class);
            bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
        }
    
        public void add(View view) {
            Book book = new Book();
            book.setBookId(1);
            book.setBookName("天下足球");
            try {
                mBookManager.addBook(book);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
    
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unbindService(mServiceConnection);
        }
    
        private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBookManager = IBookManager.Stub.asInterface(service);
                try {
                    mBookManager.registerListener(mListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
        private IOnBookAddListener mListener = new IOnBookAddListener.Stub() {
            @Override
            public void onBookadd(final Book book) throws RemoteException {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, book.toString(), Toast.LENGTH_SHORT).show();
                    }
                });
            }
    
        };
    }
    
    

    首先来验证服务端中mBinder 的addBook(Book book)方法确实是在一个子线程中进行的。

    private IOnBookAddListener mListener = new IOnBookAddListener.Stub() {
            @Override
            public void onBookadd(final Book book) throws RemoteException {
                //方法回调在子线程中
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, book.toString(), Toast.LENGTH_SHORT).show();
                    }
                });
            }
    
        };
    

    在onBookadd(final Book book) 回调中通过runOnUiThread(new Runnable())将线程切回主线程然后才能Toast提示。这也从侧面证明了binder服务端处理客户端的请求时会在一个子线程中处理。这里我们还有一个地方要注意,虽然binder服务会在一个子线程中处理客户端的请求,但是客户端请求的时却不会新开一个线程,从上面的代码我们可能还看不出什么,如果将服务端的添加图书的代码设置为耗时操作,运行程序,点击添加图书可能就会出现ANR。(这里就不验证了)所以在确定服务端处理请求时是耗时的操作的时候。有必要新开一个线程去请求。
    上面说了这么多,总结一句话:binder服务在处理客户端的请求时是在一个独立的线程中完成的,而客户端请求处理,不会新开一个线程,如果是耗时操作,则可能出现ANR。
    #######具体分析调用流程
    搞清楚这个问题之后我们进入主题:binder如何来进行跨进程间的调用。
    首先来看,在activity中点击添加图书会调用add(View view),然后调用mBookManager.addBook(book);就能成功的往MyService的bookList中添加一本书,这是为什么呢?我们的activity和service明明处于两个进程,确好像在同一个进程中直接持有了服务端实现addBook(Book book)方法的mBinder 的引用,通过这个引用就调用了MyService 所在进程的方法。要解释这个问题,我们自然而然的要分析activity中的mBookManager是怎么被赋值的:

    private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //mBookManager 在这里赋值
                mBookManager = IBookManager.Stub.asInterface(service);
                try {
                    mBookManager.registerListener(mListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    看到这里mBookManager = IBookManager.Stub.asInterface(service);我们可能会糊涂,这个IBookManager.Stub到底是个什么东西,为什么调用它的asInterface(service)方法就能得到mBinder 的引用?接下来我们就来分析IBookManager.Stub是个啥,它的asInterface(service)到底有什么奥秘。

    /*
     * This file is auto-generated.  DO NOT MODIFY.
     * Original file: D:\\WorkSpace\\MyApplication\\binderdemo\\src\\main\\aidl\\com\\shine\\binderdemo\\IBookManager.aidl
     */
    package com.shine.binderdemo;
    
    public interface IBookManager extends android.os.IInterface {
        /**
         * Local-side IPC implementation stub class.
         */
        public static abstract class Stub extends android.os.Binder implements com.shine.binderdemo.IBookManager {
            private static final java.lang.String DESCRIPTOR = "com.shine.binderdemo.IBookManager";
    
            /**
             * Construct the stub at attach it to the interface.
             */
            public Stub() {
                this.attachInterface(this, DESCRIPTOR);
            }
    
            /**
             * Cast an IBinder object into an com.shine.binderdemo.IBookManager interface,
             * generating a proxy if needed.
             */
            public static com.shine.binderdemo.IBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.shine.binderdemo.IBookManager))) {
                    return ((com.shine.binderdemo.IBookManager) iin);
                }
                return new com.shine.binderdemo.IBookManager.Stub.Proxy(obj);
            }
    
            @Override
            public android.os.IBinder asBinder() {
                return this;
            }
    
            @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    case TRANSACTION_addBook: {
                        data.enforceInterface(DESCRIPTOR);
                        com.shine.binderdemo.Book _arg0;
                        if ((0 != data.readInt())) {
                            _arg0 = com.shine.binderdemo.Book.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        this.addBook(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_registerListener: {
                        data.enforceInterface(DESCRIPTOR);
                        com.shine.binderdemo.IOnBookAddListener _arg0;
                        _arg0 = com.shine.binderdemo.IOnBookAddListener.Stub.asInterface(data.readStrongBinder());
                        this.registerListener(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    
            private static class Proxy implements com.shine.binderdemo.IBookManager {
                private android.os.IBinder mRemote;
    
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
    
                @Override
                public android.os.IBinder asBinder() {
                    return mRemote;
                }
    
                public java.lang.String getInterfaceDescriptor() {
                    return DESCRIPTOR;
                }
    
                @Override
                public void addBook(com.shine.binderdemo.Book book) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        if ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    
                @Override
                public void registerListener(com.shine.binderdemo.IOnBookAddListener listener) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        _data.writeStrongBinder((((listener != null)) ? (listener.asBinder()) : (null)));
                        mRemote.transact(Stub.TRANSACTION_registerListener, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
            }
    
            static final int TRANSACTION_addBook = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
            static final int TRANSACTION_registerListener = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
        }
    
        public void addBook(com.shine.binderdemo.Book book) throws android.os.RemoteException;
    
        public void registerListener(com.shine.binderdemo.IOnBookAddListener listener) throws android.os.RemoteException;
    }
    
    

    上面直接贴出了IBookManager.aidl编译之后生成的IBookManager.java的代码。这个代码初看之下很长,不容易读懂,下面我贴一张as里面关于这个类的结构图。


    结构图.png

    通过这个结构图大概可以看出Stub是IBookManager的一个内部类,有一个asInterface(android.os.IBinder obj)方法,这也是上面activity中给mBookManager 赋值中用到的一个方法,我们待会再来分析。Stub内部又有一个内部类Proxy ,从名字上来看它应该是一个代理类,那么它到底代理的那个类呢?

     public static com.shine.binderdemo.IBookManager asInterface(android.os.IBinder obj) {
                if ((obj == null)) {
                    return null;
                }
                android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
                if (((iin != null) && (iin instanceof com.shine.binderdemo.IBookManager))) {
                    return ((com.shine.binderdemo.IBookManager) iin);
                }
                //将IBinder类型的obj通过构造方法传入Proxy
                return new com.shine.binderdemo.IBookManager.Stub.Proxy(obj);
            }
    
    Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
    

    看完上面两段代码应该可以看出Proxy代理的就是一个IBinder类型的obj,到这里我们明白了mBookManager原来就是一个Proxy代理类。熟悉代理模式的话,我们知道代理类只是持有一个真实类的引用,真正功能都是由这个真实类实现的。在这个IBookManager.Stub.Proxy里面,真实类是什么呢?

     private static class Proxy implements com.shine.binderdemo.IBookManager {
                //mRemote是这个代理中的真实对象
                private android.os.IBinder mRemote;
    
                Proxy(android.os.IBinder remote) {
                    mRemote = remote;
                }
    
               ......
    
                @Override
                public void addBook(com.shine.binderdemo.Book book) throws android.os.RemoteException {
                    android.os.Parcel _data = android.os.Parcel.obtain();
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                        _data.writeInterfaceToken(DESCRIPTOR);
                        if ((book != null)) {
                            _data.writeInt(1);
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                        //mBookManager的addBook(Book book)方法实际上是调用 mRemote.transact(...)方法
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
               ......
    }
    

    这段代码的注释已经很明确的IBinder类型的mRemote是这个类的真实引用。
    mBookManager.addBook(Book book)方法最后会调用mRemote.transact(...)方法,那么这个mRemote是个啥呢?mRemote是如何传入Proxy呢?
    我们在之前的binder机制的概念时说过,binder机制涉及到4个组件,binder server ,binder client,binder内核驱动,Service Manager。在上面的情景中我们只分析了binder server 和binder client,接下来binder内核驱动(对于binder驱动,在下面只会提到它的作用,不涉及具体的代码,具体的代码分析我也不懂)就要出场了,而对于Service Manager,这个例子中却不会直接涉及,在activity的启动过程中会出现,到时候再分析,敬请期待。。。
    有了binder驱动介入,就可以解决mRemote到底是个啥了。先看下MyService的onBinder(...)方法

    @Override
        public IBinder onBind(Intent intent) {
            return mBinder;
        }
    
    private IBinder mBinder = new IBookManager.Stub() {
    
            @Override
            public void addBook(Book book) throws RemoteException {
                booklist.add(book);
                if (mListener != null) {
                    mListener.onBookadd(book);
                }
            }
    
            @Override
            public void registerListener(IOnBookAddListener listener) throws RemoteException {
                mListener = listener;
            }
        };
    

    这个mBinder是一个IBookManager.Stub()类型的变量,而IBookManager.Stub()继承Binder,所以mBinder是一个Binder类型的对象。这个binder类型的对象实际上就是binder服务端,在binder服务端开启的时候,同时会在binder内核建一个mRemote的binder对象,我们在上面提到的mRemote其实就是binder内核里面的mRemote binder对象。实际在binder进程间调用的时候必须要考虑的问题就是如何获取binder内核mRemote 对象。这个例子采用的是Service做binder服务端,而binderService中google的工程师已经为我们实现好了。在ServiceConnection里面有个回调方法可以获取binder内核的mRemote,如下:

    private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                //通过获取到的service(mRemote)生成IBookManager.Stub.Proxy对象
                mBookManager = IBookManager.Stub.asInterface(service);
                try {
                    mBookManager.registerListener(mListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    

    这样我们就获取到了binder内核的mRemote对象,同时也传入了IBookManager.Stub.Proxy,接着就可以使用mRemote来进行跨线程的调用了。
    接下来看下mBookManager到底是怎样实现addBook(Book,book)方法的,上面已经分析了会调用到IBookManager.Stub.Proxy.addBook(Book book)

    @Override
                public void addBook(com.shine.binderdemo.Book book) throws android.os.RemoteException {
                     //_data表示发送binder服务端的数据,这些数据需要通过Parcel (包裹)进行传递
                    android.os.Parcel _data = android.os.Parcel.obtain();
                   //_reply 表示binder服务端相应的数据,这些数据同样需要通过Parcel (包裹)进行传递
                    android.os.Parcel _reply = android.os.Parcel.obtain();
                    try {
                       //用来做安全检查,binder服务端会处理这个数据
                        _data.writeInterfaceToken(DESCRIPTOR);
                        if ((book != null)) {
                            _data.writeInt(1);
                            //Parcel (包裹)不仅可以传递基本类型的数据还可以传递对象,但是对象必须实现Parcelable接口
                            book.writeToParcel(_data, 0);
                        } else {
                            _data.writeInt(0);
                        }
                         //调用binder内核的mRemote对象往binder服务端发送信息
                        mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);
                        _reply.readException();
                    } finally {
                        _reply.recycle();
                        _data.recycle();
                    }
                }
    

    代码中注释已经很详细了,就不解释了,接着看下面,我们说过mRemote实际上是一个binder类型的对象, mRemote.transact(Stub.TRANSACTION_addBook, _data, _reply, 0);就会调用到Binder的transact(...)方法中

    /**
         * Default implementation rewinds the parcels and calls onTransact.  On
         * the remote side, transact calls into the binder to do the IPC.
         */
        public final boolean transact(int code, Parcel data, Parcel reply,
                int flags) throws RemoteException {
            if (false) Log.v("Binder", "Transact: " + code + " to " + this);
            if (data != null) {
                data.setDataPosition(0);
            }
            //调用binder服务端的onTransact(...)中
            boolean r = onTransact(code, data, reply, flags);
            if (reply != null) {
                reply.setDataPosition(0);
            }
            return r;
        }
    

    其中transact(...)有四个参数,分别是 code,data,reply,flag。
    code:整形的一个识别码,客户端传入,用于区分服务端执行哪个方法。
    data:客户端传入的Parcel类型的参数。
    reply:服务端返回的结果值,也是Parcel类型数据。
    flag:整形的一个标记,用于标记是否是否有返回值,0表示有返回值,1表示没有。
    接着再次涉及到binder内核驱动,具体的细节我也不太懂,直接的结论是流程会进入到binder服务端的IBookManager.Stub的onTransact(...)中:

     @Override
            public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException {
                switch (code) {
                    case INTERFACE_TRANSACTION: {
                        reply.writeString(DESCRIPTOR);
                        return true;
                    }
                    //根据transact第一个参数来确定请求的是哪个方法
                    case TRANSACTION_addBook: {
                        data.enforceInterface(DESCRIPTOR);
                        com.shine.binderdemo.Book _arg0;
                        if ((0 != data.readInt())) {//如果客户端传递是有非基本类型的数据从data中取出
                            _arg0 = com.shine.binderdemo.Book.CREATOR.createFromParcel(data);
                        } else {
                            _arg0 = null;
                        }
                        //取出来的数据传到MyService的mBinder的addBook(...)
                        this.addBook(_arg0);
                        //由于addBook(...)没有返回值,所以不需要通过reply返回结果
                        reply.writeNoException();
                        return true;
                    }
                    case TRANSACTION_registerListener: {
                        data.enforceInterface(DESCRIPTOR);
                        com.shine.binderdemo.IOnBookAddListener _arg0;
                        _arg0 = com.shine.binderdemo.IOnBookAddListener.Stub.asInterface(data.readStrongBinder());
                        this.registerListener(_arg0);
                        reply.writeNoException();
                        return true;
                    }
                }
                return super.onTransact(code, data, reply, flags);
            }
    

    通过上面从activity的addBool(Book book)开始,我们一步一步的分析了binder客户端如何调用binder服务端的方法,这个过程在binder内核驱动的基础上实现,让我们感觉好像是调用本地(同一个进程)方法一样,实质上底层为我们做了大量的工作。这样基于aidl实现的Binder跨进程调用就大概谈完了,对binder跨进程调用也应该有了一定的了解。
    #######binder小结
    跨进程调用的关键点在于如何获得服务端的binder对象在内核里面的引用(如上面分析的mRemote)。
    一般来说有两种途径,其一是通过Service Manager,这篇文章没有直接涉及Service Manager,但是在底层源码里面这种情况很常见,在Activity启动过程中用到的ActivityManagerService就是通过这种方式在客户端得到服务端的binder对象在内核里面的引用,我们以后再分析。其二是通过已经建立好的binder连接来获取这个引用。如上面的例子中用到的一样。

    private IOnBookAddListener mListener = new IOnBookAddListener.Stub() {
            @Override
            public void onBookadd(final Book book) throws RemoteException {
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        Toast.makeText(MainActivity.this, book.toString(), Toast.LENGTH_SHORT).show();
                    }
                });
            }
    
        };
    

    这是一个实现了接口方法的Binder服务,通过已经建立好的binde连接mBookManager传递给Myservice所在进程。

    private ServiceConnection mServiceConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mBookManager = IBookManager.Stub.asInterface(service);
                try {
                    //通过已经建立好的连接传送服务端binder的引用
                    mBookManager.registerListener(mListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
    
            @Override
            public void onServiceDisconnected(ComponentName name) {
    
            }
        };
    
    

    有一点需要注意,在此时activity所在的进程就成为了我们通常所说的binder服务端,而MyService则是binder客户端。这就是第二种获取binder服务引用的方式。再多谈一点,其实在这个例子中,两个建立的binder连接都是通过已将建立好的连接来传递的,除了mListener 这个binder引用的获得,mBinder也是这种情况。这里就不再详细讨论了,如果感兴趣可以学习一下bindService的源码,就肯定能发现这一点。最后贴上一张例子用到的uml类图:

    aidl.png
    3.总结

    这篇文章是学习技术以来的第一篇文章,很久以前就在谋划了,但是由于一些事情和水平的关系拖了很久,但是总算是写完了。在写作的过程中还是遇到了很多困难的,有时候知道的东西你不一定能写出来,需要的知识也不在一个层面。有些知识可能以为懂了,但是真正到了写的时候,还是发现不会。我觉得写技术博客是提升技术的一个很好的途径,希望以后我能保持。对binder有了概念之后,接下来会继续把Activity启动过程及界面绘制流程解析写完。先前的打算是在这篇文章里面再介绍一下handler相关知识的,毕竟在activity启动的过程中handler也同样重要,但是写binder的时候,发现知识还是有很多缺陷,只能留待下一次了。

    相关文章

      网友评论

        本文标题:Activity启动过程及界面绘制流程解析开篇

        本文链接:https://www.haomeiwen.com/subject/qttorttx.html