广播BroadcastReceiver
1.分类
标准广播:异步,所有广播接收器同时接收到,效率高但不可截断
有序广播:同步,同一时刻只有一个接收器接收到,优先级高的先收到,可截断
2.注册方式
在代码中注册(动态注册),灵活性好,但只能程序启动之后才能进行
在AndroidManifest.xml中注册(静态注册)
动态注册监听网络
新建一个类,继承BroadcastReceiver,重写onReceive方法。通过getSystemService()方法获取ConnectivityManager的一个实例,这是一个系统服务器类,专门管理网络连接的,然后调用他的 getActiveNetworkInfo()方法获取 NetworkInfo 的实例,接着调用 NetworkInfo 的isAvailable()方法判断是否联网
package com.example.tingyu.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intentFilter=new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
//android.net.conn.CONNECTIVITY_CHANGE专门用来判断网络变化,想监听什么广播,添加对应的action
networkChangeReceiver=new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver,intentFilter);
}
@Override
//动态注册的广播接收器一定要取消注册
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
ConnectivityManager connectionManager=(ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo=connectionManager.getActiveNetworkInfo();
if(networkInfo!=null&&networkInfo.isAvailable()) {
Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show();
}
else{
Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
}
}
}
}
在网络发生改变的时候toast提醒用户
静态注册开机启动
程序未启动情况下就能接收到广播
首先在MainActivity目录下新建一个类new->other->Broadcast Receiver,勾选Export和Enable按钮,在接下来的注册文件中也会自动生成这两项
https://i.loli.net/2018/08/10/5b6cfeb7d345e.png
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tingyu.broadcasttest">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
//监视系统开机广播的权限
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<receiver
android:name=".MyReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
</application>
</manifest>
package com.example.tingyu.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class MyReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
//throw new UnsupportedOperationException("Not yet implemented");
}
}
注册文件有了receiver和activity用法差不多,intent-filter里添加想要的广播即可。然后重启模拟器,就可以开机时看到广播了
3.发送自定义广播
发送系统全局广播
发送标准广播
(1)首先需要定义一个广播接收器接收广播,其实在之前静态注册的时候我们定义的那个类就是广播接收器。同样的,我们注册一个MyBroadcastReceiver继承自BroadcastReceiver
(2)然后再在AndroidMabifest.xml中进行注册。
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
这里接受一个值为com.example.broadcasttest.MY_BROADCAST得 广播,接下来我们将传送一个这样的广播
(3)修改布局文件activity_main.xml,定义一个按钮,作为广播触发点
(4)再修改MainActivity中代码
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button)findViewById(R.id.broadcastbutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
}
});
}
}
构造一个Intent对象,在其中传入一条广播,再调用Context的sendBroadcast方法将广播发出去
最终效果如下:
[![1533886284743.png](https://i.loli.net/2018/08/10/5b6d40f759cd7.png)](https://i.loli.net/2018/08/10/5b6d40f759cd7.png)
发送有序广播
(1)新建一个名为BroadcastTest2的项目new->new project
(2)新建广播接收器类,使得它接收到的广播与BroadcastTest保持一致,也就是注册类里AndroidManifest.xml中这里保持一致
<receiver
android:name=".anotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>;
</intent-filter>
(3)sendBroadcast(intent);是发送标准广播,sendOrderedBroadcast(intent,null);是发送有序广播,差别不大,第二个null参数是一个与权限有关的字符串。在MainActivity中修改
package com.example.tingyu.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button=(Button)findViewById(R.id.broadcastbutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent=new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent,null);
//差别在这里
}
});
}
}
也可以拦截广播,在广播接收器类中进行修改
package com.example.tingyu.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// TODO: This method is called when the BroadcastReceiver is receiving
// an Intent broadcast.
//throw new UnsupportedOperationException("Not yet implemented");
Toast.makeText(context, "receive in MyBroadcastReceiver", Toast.LENGTH_LONG).show();
abortBroadcast();//将广播拦截,不再继续传递
}
}
(4)在注册地方修改如下,这样就有了优先级
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
最后点击按钮后只弹出MyBroadcastReceiver收到消息,第二个接收器没有弹出,有序广播带拦截功能发送成功
发送局部广播
系统全局广播安全性不高,数据乱传,局部广播只针对一个应用内部传播数据
实现思想就是用一个LocalBroadcastManager对广播进行管理,并提供发送广播和注册广播接收器的方法
package com.example.tingyu.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager = LocalBroadcastManager.getInstance(this);//获取实例
Button button = (Button) findViewById(R.id.broadcastbutton);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManager.sendBroadcast(intent);
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
}
//注册本地广播监听器
protected void onDestroy()
{
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver{
public void onReceive(Context context,Intent intent){
Toast.makeText(context,"receved local broadcast",Toast.LENGTH_SHORT).show();
}
}
}
与动态注册代码相同,只是通过LocalBroadcastManager的getInstance()方法来获取实例,注册的时候使用它的registerReceiver方法,发送广播时调用sendBroadcast方法
参考书籍:郭霖《第一行代码》