Android本地广播LocalBroadcastManager使用

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/zhe_ge_sha_shou/article/details/85223956

LocalBroadcastManager 简介

学习Android的同鞋一定知道四大组件,四大组件有:
四大组件
四大组件中的BroadcastReceiver是全局广播,即发送广播时可能被多个App接收到,有时候从安全角度考虑,为了数据的安全传递,是不是有办法避免被多个App接收广播,于是有了本地广播,本地广播只会在自己的App内传播,用于在同一个应用内的不同组件间发送Broadcast进行通信。使用本地广播,需要用到support库中的LocalBroadcastManager。

LocalBroadcastManager使用

这里先列出LocalBroadcastManager中常用的方法:

LocalBroadcastManager中方法 说明
getInstance(Context context) 获取本地广播实例
registerReceiver(BroadcastReceiver receiver, IntentFilter filter) 注册广播
unregisterReceiver(BroadcastReceiver receiver) 解注册
sendBroadcast(Intent intent) 发送广播(内部使用Handler,保证onReceive在主线程中调用)
sendBroadcastSync(Intent intent) 同步发送广播,如果消息队列中消息太多,会导致广播接收者接收广播太慢,可使用这个方法同步发送广播
  • 获取LocalBroadcastManager对象
    LocalBroadcastManager被设计为一个单例类,通过getInstance方法获取实例,参数需要一个上下文对象
// java
LocalBroadcastManager localManager= LocalBroadcastManager.getInstance(mContext);
// kotlin
val localManager = LocalBroadcastManager.getInstance(mContext)
  • 注册观察者
    和全局广播的思想一样,如果要接收广播,那么需要先注册一个广播,才能接收到匹配的广播。本地广播不能通过在AndroidManifest文件中静态声明注册,只能通过动态注册的方法注册,这里注册时需要调用registerReceiver方法,需要传递两个参数BroadcastReceiverIntentFilter
//java
LocalBroadcastManager localManager = LocalBroadcastManager.getInstance(mContext);
BroadcastReceiver receiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        Toast.makeText(context, "收到广播", Toast.LENGTH_SHORT).show();
    }
};
IntentFilter intentFilter = new IntentFilter("LocalBroadcastManager-test");
localManager.registerReceiver(receiver, intentFilter);//注册广播
//kotlin
val localManager = LocalBroadcastManager.getInstance(mContext)
val broadReceiver = object : BroadcastReceiver() {
    override fun onReceive(context: Context?, intent: Intent?) {
        Toast.makeText(context, "收到广播", Toast.LENGTH_SHORT).show()
    }
}
val intentFilter = IntentFilter("LocalBroadcastManager-test")
localManager.registerReceiver(broadReceiver, intentFilter)
  • 通过本地发送广播
    通过上面定义BroadcastReceiver来接收广播处理,现在可以发送广播试试了
//java
localManager.sendBroadcast(new Intent("LocalBroadcastManager-test"));
//kotlin
localManager.sendBroadcast(Intent("LocalBroadcastManager-test"))

运行效果

LocalBroadcastManager 源码分析

LocalBroadcastManager位于android.support.v4.content包下

因为本地广播基于观察者模式设计,所以将LocalBroadcastManager设计成单例,被观察者只有一个嘛,以下是获取实例和私有构造方法

// 忽略部分代码
public static LocalBroadcastManager getInstance(@NonNull Context context) {
    Object var1 = mLock;
    synchronized(mLock) {
        if (mInstance == null) {
            mInstance = new LocalBroadcastManager(context.getApplicationContext());
        }

        return mInstance;
    }
}

private LocalBroadcastManager(Context context) {
    this.mAppContext = context;
    //UI线程的Looper,说明可以在子线程获取实例、发送广播
    this.mHandler = new Handler(context.getMainLooper()) {
        public void handleMessage(Message msg) {
            switch(msg.what) {
            case 1:
                LocalBroadcastManager.this.executePendingBroadcasts();
                break;
            default:
                super.handleMessage(msg);
            }
        }
    };
}

在LocalBroadcastManager中有两个内部静态类,封装了BroadcastReceiver和IntentFilter

// 忽略部分代码
private static final class ReceiverRecord {
    final IntentFilter filter;//注册广播时的intentFilter
    final BroadcastReceiver receiver;//注册广播时的broadcastReceiver
    boolean broadcasting;//是否添加到广播队列
    boolean dead;//死亡标识 

    ReceiverRecord(IntentFilter _filter, BroadcastReceiver _receiver) {
        this.filter = _filter;
        this.receiver = _receiver;
    }

    public String toString() {
        StringBuilder builder = new StringBuilder(128);
        builder.append("Receiver{");
        builder.append(this.receiver);
        builder.append(" filter=");
        builder.append(this.filter);
        if (this.dead) {
            builder.append(" DEAD");
        }

        builder.append("}");
        return builder.toString();
    }
}

private static final class BroadcastRecord {
    final Intent intent;//发送广播的intent
    final ArrayList<LocalBroadcastManager.ReceiverRecord> receivers;//发送广播intent匹配的receivers

    BroadcastRecord(Intent _intent, ArrayList<LocalBroadcastManager.ReceiverRecord> _receivers) {
        this.intent = _intent;
        this.receivers = _receivers;
    }
}

下面看下注册观察都和解注册的代码

// 保存所有注册BroadcastReceiver的HashMap
private final HashMap<BroadcastReceiver, ArrayList<LocalBroadcastManager.ReceiverRecord>> mReceivers = new HashMap();
//保存所有注册BroadcastReceiver中IntentFilter的action
private final HashMap<String, ArrayList<LocalBroadcastManager.ReceiverRecord>> mActions = new HashMap();

public void registerReceiver(@NonNull BroadcastReceiver receiver, @NonNull IntentFilter filter) {
    HashMap var3 = this.mReceivers;
    synchronized(this.mReceivers) {
       // 创建一个LocalBroadcastManager.ReceiverRecord对象
        LocalBroadcastManager.ReceiverRecord entry = new LocalBroadcastManager.ReceiverRecord(filter, receiver);
        // 从mReceivers中获取是否存在的LocalBroadcastManager.ReceiverRecord对象
        ArrayList<LocalBroadcastManager.ReceiverRecord> filters = (ArrayList)this.mReceivers.get(receiver);
        if (filters == null) {
           //如果mReceivers不存在要注册的receiver,则创建一个新的,保存到Mreceivers中
            filters = new ArrayList(1);
            this.mReceivers.put(receiver, filters);//保存receiver对应的LocalBroadcastManager.ReceiverRecord
        }
        filters.add(entry);

        for(int i = 0; i < filter.countActions(); ++i) {
            // 遍历获取filter中所有的action,保存到mActions中
            String action = filter.getAction(i);
            ArrayList<LocalBroadcastManager.ReceiverRecord> entries = (ArrayList)this.mActions.get(action);
            if (entries == null) {
                entries = new ArrayList(1);
                this.mActions.put(action, entries);//保存action对应的LocalBroadcastManager.ReceiverRecord
            }
            entries.add(entry);
        }
    }
}

public void unregisterReceiver(@NonNull BroadcastReceiver receiver) {
    HashMap var2 = this.mReceivers;
    synchronized(this.mReceivers) {
       //mReceivers中移除已注册的receiver
        ArrayList<LocalBroadcastManager.ReceiverRecord> filters = (ArrayList)this.mReceivers.remove(receiver);
        if (filters != null) {//移除成功不为null
            for(int i = filters.size() - 1; i >= 0; --i) {
                LocalBroadcastManager.ReceiverRecord filter = (LocalBroadcastManager.ReceiverRecord)filters.get(i);
                filter.dead = true;//死亡标识

                for(int j = 0; j < filter.filter.countActions(); ++j) {
                    String action = filter.filter.getAction(j);
                    ArrayList<LocalBroadcastManager.ReceiverRecord> receivers = (ArrayList)this.mActions.get(action);
                    if (receivers != null) {
                        for(int k = receivers.size() - 1; k >= 0; --k) {
                            LocalBroadcastManager.ReceiverRecord rec = (LocalBroadcastManager.ReceiverRecord)receivers.get(k);
                            if (rec.receiver == receiver) {
                                rec.dead = true;//标识死亡
                                receivers.remove(k);//先移除mAction中action对应List中的
                            }
                        }

                        if (receivers.size() <= 0) {
                            this.mActions.remove(action);//如果action对应的list为0,移除mAction中的action
                        }
                    }
                }
            }
        }
    }
}

发送广播的逻辑

public boolean sendBroadcast(@NonNull Intent intent) {
    HashMap var2 = this.mReceivers;
    synchronized(this.mReceivers) {
        String action = intent.getAction();
        String type = intent.resolveTypeIfNeeded(this.mAppContext.getContentResolver());
        Uri data = intent.getData();
        String scheme = intent.getScheme();
        Set<String> categories = intent.getCategories();
        boolean debug = (intent.getFlags() & 8) != 0;
        if (debug) {
            Log.v("LocalBroadcastManager", "Resolving type " + type + " scheme " + scheme + " of intent " + intent);
        }
	// 获取匹配的action的ReceiverRecord对象
        ArrayList<LocalBroadcastManager.ReceiverRecord> entries = (ArrayList)this.mActions.get(intent.getAction());
        if (entries != null) {
            if (debug) {
                Log.v("LocalBroadcastManager", "Action list: " + entries);
            }

            ArrayList<LocalBroadcastManager.ReceiverRecord> receivers = null;

            int i;
            //遍历匹配到action的广播
            for(i = 0; i < entries.size(); ++i) {
                LocalBroadcastManager.ReceiverRecord receiver = (LocalBroadcastManager.ReceiverRecord)entries.get(i);
                if (debug) {
                    Log.v("LocalBroadcastManager", "Matching against filter " + receiver.filter);
                }

                if (receiver.broadcasting) {
                    if (debug) {
                        Log.v("LocalBroadcastManager", "  Filter's target already added");
                    }
                } else {
                    int match = receiver.filter.match(action, type, scheme, data, categories, "LocalBroadcastManager");
                    if (match >= 0) {
                        if (debug) {
                            Log.v("LocalBroadcastManager", "  Filter matched!  match=0x" + Integer.toHexString(match));
                        }

                        if (receivers == null) {
                            receivers = new ArrayList();
                        }

                        receivers.add(receiver);
                        receiver.broadcasting = true;
                    } else if (debug) {
                        String reason;
                        switch(match) {
                        case -4:
                            reason = "category";
                            break;
                        case -3:
                            reason = "action";
                            break;
                        case -2:
                            reason = "data";
                            break;
                        case -1:
                            reason = "type";
                            break;
                        default:
                            reason = "unknown reason";
                        }

                        Log.v("LocalBroadcastManager", "  Filter did not match: " + reason);
                    }
                }
            }

            if (receivers != null) {
                for(i = 0; i < receivers.size(); ++i) {
                    ((LocalBroadcastManager.ReceiverRecord)receivers.get(i)).broadcasting = false;
                }
		// 添加到广播队列
                this.mPendingBroadcasts.add(new LocalBroadcastManager.BroadcastRecord(intent, receivers));
                if (!this.mHandler.hasMessages(1)) {
                  //发送消息
                    this.mHandler.sendEmptyMessage(1);
                }

                return true;
            }
        }

        return false;
    }
}

sendBroadcastSync方法有些不同,可自行查看源码
下面来看下处理广播的逻辑

void executePendingBroadcasts() {
    while(true) {
        HashMap var2 = this.mReceivers;
        LocalBroadcastManager.BroadcastRecord[] brs;
        synchronized(this.mReceivers) {
            int N = this.mPendingBroadcasts.size();
            if (N <= 0) {
                return;
            }

            brs = new LocalBroadcastManager.BroadcastRecord[N];
            this.mPendingBroadcasts.toArray(brs); //转换array
            this.mPendingBroadcasts.clear();//清空操作
        }

        for(int i = 0; i < brs.length; ++i) {
            LocalBroadcastManager.BroadcastRecord br = brs[i];
            int nbr = br.receivers.size();
	       // 遍历回调onReceiver方法
            for(int j = 0; j < nbr; ++j) {
                LocalBroadcastManager.ReceiverRecord rec = (LocalBroadcastManager.ReceiverRecord)br.receivers.get(j);
                if (!rec.dead) {//如果没有dead调用onReceiver方法
                    rec.receiver.onReceive(this.mAppContext, br.intent);
                }
            }
        }
    }
}

到这里就把整个逻辑分析了,主要逻辑有:

  • 在LocalBroadcastManager中通过registerReceiver中注册广播,保存到mReceiversmActions
  • 通过sendBroadcast中匹配mActions中的BroadcastReceiver,将匹配到的对象保存到mPendingBroadcasts
  • 最终调用executePendingBroadcasts来发送广播

猜你喜欢

转载自blog.csdn.net/zhe_ge_sha_shou/article/details/85223956
今日推荐