美文网首页
BroadcastReceiver

BroadcastReceiver

作者: hdychi | 来源:发表于2018-07-27 14:59 被阅读0次

一、简介

广播作为Android四大组件之一,可以用于多进程间的通信、消息的传递等。大致形式是一方发送广播,BrocastReceiver(广播接收者)接收广播。BroadcastReceiver有静态注册和动态注册两种形式。

二、静态注册

在网上能看到很多这样的教程:

定义一个自定义的Receiver:

package com.meituan.huangdanyang.practise;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Process;
import android.util.Log;

public class NormalReceiver extends BroadcastReceiver{
    private static final String TAG = "Normal Receiver";
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i(TAG,"收到广播");
        String msg = intent.getStringExtra("msg");
        System.out.println("msg is " + msg);
        System.out.println("当前进程:" + Process.myPid());
    }
}

在AndroiManifest.xml中定义广播接收者:

 <receiver android:name=".NormalReceiver">
            <intent-filter>
                <action android:name="com.meituan.huangdanyang.practise.action"/>
            </intent-filter>
        </receiver>

发送广播时这样发送:


Intent intent = new Intent("com.meituan.huangdanyang.practise.action");
sendBroadcast(intent);

但是,这样的隐式注册方法在Android 8.0系统已经不适用了。

实际上,在实践中,Android 8.0这样注册广播使用隐式Intent,Receiver是不会接收到的。

官方文档如下:

Implicit Broadcast Exceptions

As part of the Android 8.0 (API level 26) Background Execution Limits, apps that target the API level 26 or higher can no longer register broadcast receivers for implicit broadcasts in their manifest.

那么,如果要静态注册广播,要怎么弄呢?当然是上显示Intent了:

   Intent intent = new Intent();
   intent.setClass(this,NormalReceiver.class);
   intent.putExtra("msg","from activity");
   sendBroadcast(intent);

这样子NormalReceiver就可以接收到广播了。

屏幕快照 2018-07-27 下午2.27.21.png

二、动态注册

动态注册广播时,就可以使用隐式Intent了。

动态注册时,不需要在AndroidManifest.xml中先行注册广播了。

动态注册接收器时,需要有一个Action非空的IntentFilter来用隐式Intent发广播:

 IntentFilter intentFilter = new IntentFilter(NORMAL_ACTION);
 normalReceiver = new NormalReceiver();
registerReceiver(normalReceiver,intentFilter);

发送广播代码如下:

 Intent intent = new Intent(NORMAL_ACTION);
 intent.putExtra("msg","from activity");
 sendBroadcast(intent);

三、多进程通信

创建一个Service,运行在非主进程的进程中,并且注册广播接收器:

BindService.java:

package com.meituan.huangdanyang.practise;

import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;

import static com.meituan.huangdanyang.practise.BindService.MyBinder.NORMAL_ACTION;

public class BindService extends BaseService {
    private MyBinder mBinder = new MyBinder();

    @Override
    public void onCreate() {
        super.onCreate();
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(NORMAL_ACTION);
        NormalReceiver normalReceiver = new NormalReceiver();
        registerReceiver(normalReceiver,intentFilter);
    }

    @Override
    public String getName() {
        return "Bind Service";
    }

    @Override
    public IBinder getBinder() {
        return mBinder;
    }

    class MyBinder extends IMyAidlInterface.Stub{
        public static final String NORMAL_ACTION = "com.meituan.huangdanyang.practise.action";

        @Override
        public void sendMsg() throws RemoteException {
            Intent intent = new Intent(NORMAL_ACTION);
            intent.putExtra("msg","from service");
            sendBroadcast(intent);
        }
    }
}

在AndroidManifest.xml中注册Service:

 <service android:name=".BindService"
            android:process="@string/new_process"/>

注册service时,如果不标明android:process,就默认在应用的主进程里。标明后就在新的进程里。

(1)AIDL通信

在App模块下,创建一个aidl接口:

IMyAidlInterface.aidl:

// IMyAidlInterface.aidl
package com.meituan.huangdanyang.practise;

// Declare any non-default types here with import statements

interface IMyAidlInterface {
    /**
     * Demonstrates some basic types that you can use as parameters
     * and return values in AIDL.
     */
     void sendMsg();
}

在Service中定义一个内部类继承自IMyAidlInterface.Stub实现这个接口:

 class MyBinder extends IMyAidlInterface.Stub{
        public static final String NORMAL_ACTION = "com.meituan.huangdanyang.practise.action";

        @Override
        public void sendMsg() throws RemoteException {
            Intent intent = new Intent(NORMAL_ACTION);
            intent.putExtra("msg","from service");
            sendBroadcast(intent);
        }
 }

在bindService时,连接service后,可以获得一个IMyAidlInterface的对象:

 private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            mBinder = IMyAidlInterface.Stub.asInterface(iBinder);
            Log.i(TAG,"onServiceConnected");
        }

        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            Log.i(TAG,"onServiceDisconnected");
        }
 };

之后就可以用mBinder调用MyBinder类的sendMsg()方法

(2)广播

在Service.onCreate中,注册一个BroadcastReceiver:

  IntentFilter intentFilter = new IntentFilter();
   intentFilter.addAction(NORMAL_ACTION);
  NormalReceiver normalReceiver = new NormalReceiver();
   registerReceiver(normalReceiver,intentFilter);

之后在Activity中像之前那样发送广播就可以让Service注册的Receiver接收到了。

考虑这样的情况,在Service和Activity中分别注册一个Receiver,并且用两个按钮,一个点击后利用AIDL通信令Service发送广播,一个点击后从Acitity发送广播。

屏幕快照 2018-07-27 下午2.49.42.png

点击send broadcast后的结果为:

07-27 14:50:33.276 6399-6399/com.meituan.huangdanyang.practise.process I/Normal Receiver: 收到广播
07-27 14:50:33.276 6399-6399/com.meituan.huangdanyang.practise.process I/System.out: msg is from activity
07-27 14:50:33.277 6399-6399/com.meituan.huangdanyang.practise.process I/System.out: 当前进程:6399
07-27 14:50:33.284 6364-6364/com.meituan.huangdanyang.practise I/Normal Receiver: 收到广播
07-27 14:50:33.285 6364-6364/com.meituan.huangdanyang.practise I/System.out: msg is from activity
    当前进程:6364

两个进程的Receiver都会收到来自Activity的广播。

同理点击Service send broadcast:

07-27 14:52:54.820 6364-6364/com.meituan.huangdanyang.practise I/Normal Receiver: 收到广播
07-27 14:52:54.820 6364-6364/com.meituan.huangdanyang.practise I/System.out: msg is from service
07-27 14:52:54.821 6364-6364/com.meituan.huangdanyang.practise I/System.out: 当前进程:6364

07-27 14:52:54.811 6399-6399/com.meituan.huangdanyang.practise.process I/Normal Receiver: 收到广播
07-27 14:52:54.811 6399-6399/com.meituan.huangdanyang.practise.process I/System.out: msg is from service
    当前进程:6399

也都会收到广播。

(3)原理

Android多进程通信的原理是Binder机制,关于Binder机制,可以看一下这个博客:http://weishu.me/2016/01/12/binder-index-for-newer/

相关文章

网友评论

      本文标题:BroadcastReceiver

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