我是靠谱客的博主 瘦瘦睫毛,最近开发中收集的这篇文章主要介绍Android广播的源码解析,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

最近打算把Android基础的一些知识再深入一点,所以就打算从四大组件开始入手,广播是经常使用的,但是也仅仅只停留在会用,却不知其原理,就着这个机会把源码给撸一遍吧。

public class MainActivity extends Activity{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        registerReceiver(broadcastReceiver, new IntentFilter("broadcast_test"));
        sendBroadcast(new Intent("broadcast_test"));
    }

    BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if(intent.getAction().equals("broadcast_test")){
                Log.d("broadcast","receice");
            }
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unregisterReceiver(broadcastReceiver);
    }
}

本文不打算讲解广播的使用方法,就直接从动态注册广播开始好了,涉及到的源码为Android API 23。

上面demo中的registerReceiver(broadcastReceiver, new IntentFilter("broadcast_test"))执行的是ContextWrapper的方法:

@Override
public Intent registerReceiver(
    BroadcastReceiver receiver, IntentFilter filter) {
    return mBase.registerReceiver(receiver, filter);
}
ContextWrapper的真正方法实现类为ContextImpl,也就是说mBase是ContextImpl的实例,对于这一块不是很了解的朋友可以看郭霖大神的这篇博客Android Context完全解析,你所不知道的Context的各种细节,由于这部分源码很多加了/** {@hide} */的注释,所以在Android Studio里面不能直接看到相关代码,我们要到SDK的路径sdksourcesandroid-23androidapp下去查看相关代码。

class ContextImpl extends Context {
    
    /*省略其它无关代码*/
    
    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
        return registerReceiver(receiver, filter, null, null);
    }

    @Override
    public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter,
                                   String broadcastPermission, Handler scheduler) {
        return registerReceiverInternal(receiver, getUserId(),
                filter, broadcastPermission, scheduler, getOuterContext());
    }

    private Intent registerReceiverInternal(BroadcastReceiver receiver, int userId,
                                            IntentFilter filter, String broadcastPermission,
                                            Handler scheduler, Context context) {
        IIntentReceiver rd = null;
        if (receiver != null) {
            if (mPackageInfo != null && context != null) {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();//获取主线程的Handler
                }
                rd = mPackageInfo.getReceiverDispatcher(
                        receiver, context, scheduler,
                        mMainThread.getInstrumentation(), true);
            } else {
                if (scheduler == null) {
                    scheduler = mMainThread.getHandler();
                }
                rd = new LoadedApk.ReceiverDispatcher(
                        receiver, context, scheduler, null, true).getIIntentReceiver();
            }
        }
        try {
            return ActivityManagerNative.getDefault().registerReceiver(
                    mMainThread.getApplicationThread(), mBasePackageName,
                    rd, filter, broadcastPermission, userId);
        } catch (RemoteException e) {
            return null;
        }
    }
}

mPackageInfo是LoadedApk的实例对象,mMainThread是ActivityThread的实例对象,IIntentReceiver是有一个接口,其对象rd是一个实现了Binder对象(我没有找到IIntentReceiver的源码,是查阅相关资料才知道的)。


public final class LoadedApk {

    /*省略其它代码*/

    private final ArrayMap<Context, ArrayMap<BroadcastReceiver, ReceiverDispatcher>> mReceivers
            = new ArrayMap<Context, ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>>();

    public IIntentReceiver getReceiverDispatcher(BroadcastReceiver r,
                                                 Context context, Handler handler,
                                                 Instrumentation instrumentation, boolean registered) {
        synchronized (mReceivers) {
            LoadedApk.ReceiverDispatcher rd = null;
            ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher> map = null;
            if (registered) {
                map = mReceivers.get(context);
                if (map != null) {
                    rd = map.get(r);
                }
            }
            if (rd == null) {
                rd = new ReceiverDispatcher(r, context, handler,
                        instrumentation, registered);
                if (registered) {
                    if (map == null) {
                        map = new ArrayMap<BroadcastReceiver, LoadedApk.ReceiverDispatcher>();
                        mReceivers.put(context, map);
                    }
                    map.put(r, rd);
                }
            } else {
                rd.validate(context, handler);
            }
            rd.mForgotten = false;
            return rd.getIIntentReceiver();//最终返回一个Binder对象
        }
    }

    static final class ReceiverDispatcher {

        final static class InnerReceiver extends IIntentReceiver.Stub {
            /*省略其它代码*/
        }

        final IIntentReceiver.Stub mIIntentReceiver;

        ReceiverDispatcher(BroadcastReceiver receiver, Context context,
                           Handler activityThread, Instrumentation instrumentation,
                           boolean registered) {
            /*省略其它代码*/
            mIIntentReceiver = new InnerReceiver(this, !registered);
        }

        IIntentReceiver getIIntentReceiver() {
            return mIIntentReceiver;
        }
    }

}
从LoadedApk的getReceiverDispatcher方法我们可以知道几点:

1、每一个注册的广播接收器都有对应的ReceiverDispatcher(即Binder对象)。

2、广播接收器和ReceiverDispatcher以键值对的形式存在map中。

3、存储广播接收器和ReceiverDispatcher的map与context也以键值对的形式存储在map中。

那么有一个问题来了,LoadedApk到底有什么用?它的注释文档就一句话“Local state maintained about a currently loaded .apk.”,大概意思就是当前加载的APK在内存中的状态,如果查看代码还会发现,它存储的还有Service等。

这时候该走到ContextWrapper.registerReceiverInternal的try-catch代码块了,在try中ActivityManagerNative.getDefault()方法返回一个ActivityManagerProxy对象,ActivityManagerProxy相关代码:

class ActivityManagerProxy implements IActivityManager {
    
    /*省略其它代码*/
    
    public ActivityManagerProxy(IBinder remote) {
        mRemote = remote;
    }

    public Intent registerReceiver(IApplicationThread caller, String packageName,
                                   IIntentReceiver receiver,
                                   IntentFilter filter, String perm, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        data.writeString(packageName);
        data.writeStrongBinder(receiver != null ? receiver.asBinder() : null);
        filter.writeToParcel(data, 0);
        data.writeString(perm);
        data.writeInt(userId);
        //此处与ActivityServiceManager通信
        mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);
        reply.readException();
        Intent intent = null;
        int haveIntent = reply.readInt();
        if (haveIntent != 0) {
            intent = Intent.CREATOR.createFromParcel(reply);
        }
        reply.recycle();
        data.recycle();
        return intent;
    }
}
关键代码mRemote.transact(REGISTER_RECEIVER_TRANSACTION, data, reply, 0);涉及到的进程间通信不是今天的内容,真要说我也说不清,我们就不深究了,只要知道它的作用就是调用了ActivityManagerService的注册方法。 ActivityManagerService的代码就不贴了,简单来说它的注册方法就是以调用方法的App的进程ID为唯一标识,生成一个ReceiverList存放所有注册的广播接收器。至此,就完成了广播接收器的注册过程,也就是说所有app的广播接收器都会存在ActivityManagerService中。

接下来就是广播的发送了,同样sendBroadcast(new Intent("broadcast_test"))方法的真正实现也是在ContextImpl中

class ContextImpl extends Context {
    
    /*省略其它代码*/
    
    public void sendBroadcast(Intent intent) {
        warnIfCallingFromSystemProcess();
        String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
        try {
            intent.prepareToLeaveProcess();
            ActivityManagerNative.getDefault().broadcastIntent(
                    mMainThread.getApplicationThread(), intent, resolvedType, null,
                    Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
                    getUserId());
        } catch (RemoteException e) {
            throw new RuntimeException("Failure from system", e);
        }
    }
}
ActivityManagerNative.getDefault()是不是很熟悉呢,没错,和注册一样都是调用了 ActivityManagerProxy的方法

class ActivityManagerProxy implements IActivityManager {

    /*省略其它代码*/

    public int broadcastIntent(IApplicationThread caller,
                               Intent intent, String resolvedType, IIntentReceiver resultTo,
                               int resultCode, String resultData, Bundle map,
                               String[] requiredPermissions, int appOp, Bundle options, boolean serialized,
                               boolean sticky, int userId) throws RemoteException {
        Parcel data = Parcel.obtain();
        Parcel reply = Parcel.obtain();
        data.writeInterfaceToken(IActivityManager.descriptor);
        data.writeStrongBinder(caller != null ? caller.asBinder() : null);
        intent.writeToParcel(data, 0);
        data.writeString(resolvedType);
        data.writeStrongBinder(resultTo != null ? resultTo.asBinder() : null);
        data.writeInt(resultCode);
        data.writeString(resultData);
        data.writeBundle(map);
        data.writeStringArray(requiredPermissions);
        data.writeInt(appOp);
        data.writeBundle(options);
        data.writeInt(serialized ? 1 : 0);
        data.writeInt(sticky ? 1 : 0);
        data.writeInt(userId);
        //此处与ActivityServiceManager通信
        mRemote.transact(BROADCAST_INTENT_TRANSACTION, data, reply, 0);
        reply.readException();
        int res = reply.readInt();
        reply.recycle();
        data.recycle();
        return res;
    }
}
不一样的方法,还是熟悉的味道。发送广播也是调用的ActivityManagerService的方法,具体代码也不贴了(主要是我没有在6.0的源码里找到这个类)。 ActivityManagerService在发送的过程中的工作就是根据发送的广播的Action找到相应的广播接收器(手机上所有注册的广播接收器都在这里存着了,找一个还不容易嘛)。ActivityManagerService内部有一个Handler会循环处理发送的广播,处理的过程就是利用Binder机制将广播分发给相应的广播接收器的ReceiverDispatcher

static final class ReceiverDispatcher {

    /*省略其它代码*/

    final static class InnerReceiver extends IIntentReceiver.Stub {

        final class Args extends BroadcastReceiver.PendingResult implements Runnable {

            public void run() {
                try {
                    ClassLoader cl = mReceiver.getClass().getClassLoader();
                    intent.setExtrasClassLoader(cl);
                    setExtrasClassLoader(cl);
                    receiver.setPendingResult(this);
                    receiver.onReceive(mContext, intent);
                } catch (Exception e) {

                }

            }
        }
    }

}
ReceiverDispatcher实现了Runnable接口,最终会回调到相应BroadcastReceiver的onReceive方法。那么会在哪个线程中处理这个任务呢,还记得注册广播时的scheduler吗,就是在这个里面被post进去的。这样一来,整个广播的注册和发送接收事件就完成了。

我这里只是大致梳理了最基础的广播使用过程,没有对细节深入,仔细探索的话还有粘性广播的处理、广播优先级的处理、广播注销的处理等等,那我就不再多啰嗦啦。(再啰嗦一句,广播的这种订阅--发布过程就是观察者模式的体现)







参考资料  《Android源码设计模式解析与实践》

最后

以上就是瘦瘦睫毛为你收集整理的Android广播的源码解析的全部内容,希望文章能够帮你解决Android广播的源码解析所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(60)

评论列表共有 0 条评论

立即
投稿
返回
顶部