Android中Intent連接不同組件的原理

一、什麼是Intent

1、概念

Intent翻譯過來是”意圖、目的”的意思,是連接四大組件的橋樑,作爲中介傳輸信息.

2、類型

Intent分爲兩種,顯示和隱示.顯示需要指定目標組件信息,隱示則只需要指定被目標組件響應的信息(action和category等信息).

3、屬性

component(組件):目的組件
action(動作):用來表現意圖的行動
category(類別):用來表現動作的類別
data(數據):表示與動作要操縱的數據
type(數據類型):對於data範例的描寫
extras(擴展信息):擴展信息
Flags(標誌位):期望這個意圖的運行模式
.
二、連接不同組件的原理

這裏以Activity裏啓動Service爲例,來分析原理.

Intent intent = new Intent(MainActivity.this, MainService.class); startService(intent);

1、點擊跳轉到Intent帶有這兩個參數的構造方法

    public class Intent implements Parcelable, Cloneable {
            ...... 
    public Intent(Context packageContext, Class<?> cls) {
        mComponent = new ComponentName(packageContext, cls);
    }       
            ...... 
            }

在這裏只是新建了ComponentName實例.

2、好,回到startService(intent),點擊會跳轉到ContextWrapper類

public class ContextWrapper extends Context {
     Context mBase; 
     ...... 
     @Override public ComponentName startService(Intent service) { 
     return mBase.startService(service); 
     } 
     ...... 
     }

3、在這個方法裏調用mBase的startService方法,這個mBase其實是ContextIml的實例,ContextIml也繼承自Context,代碼位於/frameworks/base/core/java/android/app/ContextImpl.java。
這裏順便介紹下Context、ContextWrapper 、ContextImpl的關係.直接
放圖吧。

這裏寫圖片描述

4、好,繼續看ContextImpl類中的startService實現.
PS:給大家推薦一個在線看源碼的網站 點擊打開

class ContextImpl extends Context { 
            ...... 
            @Override 
            public ComponentName startService(Intent service) {
                try {
                    service.setAllowFds(false); 
                    ComponentName cn=ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver())); 
                    if (cn != null && cn.getPackageName().equals()) { 
                        throw new SecurityException( + service + + cn.getClassName()); 
                        } 
                    return cn; 
                    } catch (RemoteException e) {
                        return null; 
                        } 
                } 
            ...... 
            }

5、在這裏調用了ActivityManagerNative的getDefault方法返回的是gDefault.get()方法.

public abstract class ActivityManagerNative extends Binder implements IActivityManager {
            ...... 
            static public IActivityManager getDefault() {
                return gDefault.get(); 
                } 
            ......
        }

6、gDefault.get()方法返回的是IActivityManager對象.IActivityManager是一個Binder對象.

{ 
            ...... 
            private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {
                protected IActivityManager create() {
                    IBinder b = ServiceManager.getService();
                    if (false) {
                        Log.v(, + b); 
                        } 
                    IActivityManager am = asInterface(b); 
                    if (false) {
                        Log.v(, + am); 
                        } 
                    return am; 
                    } 
                }; 
            ...... 
                }

7、回到第4步.

ActivityManagerNative.getDefault().startService( mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(getContentResolver()));

調用了IActivityManager的startService方法,IActivityManager是一個抽象類,由它的實現類ActivityManagerProxy來實現.

8、看下它的實現

class ActivityManagerProxy implements IActivityManager { 
            ...... 
            public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) throws RemoteException { 
                Parcel data = Parcel.obtain(); 
                Parcel reply = Parcel.obtain(); 
                data.writeInterfaceToken(IActivityManager.descriptor); 
                data.writeStrongBinder(caller != null ? caller.asBinder() : null); 
                service.writeToParcel(data, 0); 
                data.writeString(resolvedType); 
                mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); 
                reply.readException(); 
                ComponentName res = ComponentName.readFromParcel(reply); 
                data.recycle(); 
                reply.recycle(); 
                return res; 
                } 
            ...... 
            }

startService傳入是三個參數:IApplicationThread 、Intent 、resolvedType.

第一個參數IApplicationThread是一個接口, 由主進程ActivityThread創建的一個Binder對象.第二個參數Intent 不用說了第三個參數是Intent 的MIME類型

9、接下來關鍵的一行代碼

mRemote.transact(START_SERVICE_TRANSACTION, data, reply, 0); 

這個transact方法會進入Binder驅動程序.Binder驅動程序喚醒正在等待的ActivityManagerService進程,最後進入到ActivityManagerService的startService函數中。

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
            { 
                ...... 
                public ComponentName startService(IApplicationThread caller, Intent service, String resolvedType) {
                    // Refuse possible leaked file descriptors 
                    if (service != null && service.hasFileDescriptors() == true) {
                        throw new IllegalArgumentException(); 
                        } 
                    synchronized(this) {
                        final int callingPid = Binder.getCallingPid(); 
                        final int callingUid = Binder.getCallingUid(); 
                        final long origId = Binder.clearCallingIdentity(); 
                        ComponentName res = startServiceLocked(caller, service, resolvedType, callingPid, callingUid); Binder.restoreCallingIdentity(origId); return res; 
                        } 
                    } 
                ...... 
                }
                }
            }
        }

10、從Binder裏獲取到pid和uid,添加這兩個參數到startServiceLocked方法.

public final class ActivityManagerService extends ActivityManagerNative implements Watchdog.Monitor, BatteryStatsImpl.BatteryCallback {
            { 
                ...... 
                ComponentName startServiceLocked(IApplicationThread caller,Intent service, String resolvedType,int callingPid, int callingUid) { 
                    ...... 
                    ServiceLookupResult res =retrieveServiceLocked(service, resolvedType,callingPid, callingUid); 
                    ServiceRecord r = res.record; 
                    ...... 
                    return r.name; 
                    } 
                ...... 
                }
        }

11、在這個方法裏,調用retrieveServiceLocked方法解析service這個Intent.至此,Intent的使命基本結束了,我就不繼續追蹤服務的啓動了.大家感興趣可以自己往下跟蹤.

三、總結

Intent是作爲一個參數,攜帶相關的信息.

1、由主進程通過Binder進入AMS進程
2、 在AMS進程獲取和管理要啓動的服務的相關信息
3、 由AMS進程回到該主進程啓動服務

而Intent一直是貫穿始終的.

最後附上從網上找到的整個流程圖,,幫大家理

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章