之前博文《 Android学习笔记之——Broadcast机制》已经介绍了broadcast的接收的机制。本博文学习一下如何取发布broadcast。
目录
发送标准广播
在发送广播之前,我们还是需要先定义一个广播接收器来准备接收此广播才行,不然发出去也是白发。因此新建一个MyBroadcastReceiver的类,代码如下所示:
package com.example.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.
Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
}
}
然后在AndroidManifest.xml中对这个广播接收器进行修改:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.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">
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
</receiver>
<receiver
android:name=".BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这里的action就是发布这个工程的消息了
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
</intent-filter>
定义完接收机后,来定义一下发布。接下来修改activity_main.xml中的代码,如下所示:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Send Broadcast"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
在布局文件中定义了一个按钮,用于作为发送广播的触发点。然后修改MainActivity中的代码,如下所示:
package com.example.broadcasttest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
//完成该activity各种初始化操作,如加载布局、绑定事件等
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//构建一个intent对象,将要发送的广播加入
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
//调用setComponent方法指定广播接收器(模拟器需要这一步才可以实现成功)
intent.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.MyBroadcastReceiver"));
sendBroadcast(intent);//调用了Context的sendBroadcast() 方法将广播发送出去
}
});
}
}
注意:这里在用sendBroadcast(intent)把广播发送出去之前调用了 setComponent方法指定广播接收器,效果图如下(此处我是模拟器测试需要调用该方法,但是真机测试没有该方法也能接收到)
结果如下图所示
broadcast和activity一样都是通过intent进行传递的~
发送有序广播
广播是一种可以跨进程的通信方式,在一个应用程序内发出的广播,其他的应用程序应该也是可以收到的。
新建AnotherBroadcastReceiver,用于接收上一part中自定义的广播 ,代码如下所示:
package com.example.broadcasttest;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.widget.Toast;
public class AnotherBroadcastReceiver 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, "received in AnotherBroadcastReceived", Toast.LENGTH_SHORT).show();
}
}
仍然是在广播接收器的onReceive() 方法中弹出了一段文本信息。然后在AndroidManifest.xml中对这个广播接收器进行修改,代码如下所示:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.example.broadcasttest.MY_BROADCAST" />
<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">
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
对应的mainactivity
package com.example.broadcasttest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
//完成该activity各种初始化操作,如加载布局、绑定事件等
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//构建一个intent对象,将要发送的广播加入
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
//调用setComponent方法指定广播接收器(模拟器需要这一步才可以实现成功)
intent.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.MyBroadcastReceiver"));
sendBroadcast(intent);//调用了Context的sendBroadcast() 方法将广播发送出去
Intent intent1 = new Intent("com.example.broadcasttest.MY_BROADCAST");
intent1.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.AnotherBroadcastReceiver"));
sendBroadcast(intent1);
}
});
}
}
AnotherBroadcastReceiver同样接收的是com.example.broadcasttest.MY_BROADCAST 这条广播。运行代码会发现,点击一下按钮,会出现两次提醒信息
发送有序广播只需要改动一行代码,即将sendBroadcast() 方法改成sendOrderedBroadcast() 方法
package com.example.broadcasttest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
//完成该activity各种初始化操作,如加载布局、绑定事件等
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button button= (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//构建一个intent对象,将要发送的广播加入
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
//调用setComponent方法指定广播接收器(模拟器需要这一步才可以实现成功)
intent.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.MyBroadcastReceiver"));
// sendBroadcast(intent);//调用了Context的sendBroadcast() 方法将广播发送出去
sendOrderedBroadcast(intent, null);
//sendOrderedBroadcast() 方法接收两个参数,
// 第一个参数仍然是Intent ,
// 第二个参数是一个与权限相关的字符串,这里传入null 就行了
Intent intent1 = new Intent("com.example.broadcasttest.MY_BROADCAST");
intent1.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.AnotherBroadcastReceiver"));
sendOrderedBroadcast(intent1, null);
}
});
}
}
然后通过AndroidManifest.xml中的代码设定接收的先后顺序。通过android:priority 属性给广播接收器设置了优先级,优先级比较高的广播接收器就可以先收到广播。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.broadcasttest">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="com.example.broadcasttest.MY_BROADCAST" />
<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">
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<receiver
android:name=".MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.example.broadcasttest.MY_BROADCAST" />
</intent-filter>
</receiver>
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
设置了优先权后,就可以决定广播的优先权了哈~
使用本地广播
前面发送和接收的广播全部属于系统全局广播,即发出的广播可以被其他任何应用程序接收到,并且也可以接收来自于其他任何应用程序的广播。这样就很容易引起安全性的问题,比如说发送的一些携带关键性数据的广播有可能被其他的应用程序截获,或者其他的程序不停地向我们的广播接收器里发送各种垃圾广播。为了能够简单地解决广播的安全性问题,Android引入了一套本地广播机制,使用这个机制发出的广播只能够在应用程序的内部进行传递,并且广播接收器也只能接收来自本应用程序发出的广播,这样所有的安全性问题就都不存在了。
本地广播主要就是使用了一个LocalBroadcastManager来对广播进行管理,并提供了发送广播和注册广播接收器的方法。修改MainActivity中的代码,如下所示:
package com.example.broadcasttest;
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
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;
//完成该activity各种初始化操作,如加载布局、绑定事件等
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
localBroadcastManager= LocalBroadcastManager.getInstance(MainActivity.this);//先获取一个实例
Button button= (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Intent intent1 = new Intent("com.example.broadcasttest.MY_BROADCAST");
// intent1.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.AnotherBroadcastReceiver"));
// sendOrderedBroadcast(intent1, null);
// //构建一个intent对象,将要发送的广播加入
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");//注意要发送的名称跟下面的匹配
// //调用setComponent方法指定广播接收器(模拟器需要这一步才可以实现成功)
// intent.setComponent(new ComponentName("com.example.broadcasttest","com.example.broadcasttest.MyBroadcastReceiver"));
localBroadcastManager.sendBroadcast(intent); //发送本地广播
//调用的是LocalBroadcastManager的sendBroadcast() 方法来发送广播
sendBroadcast(intent);//调用了Context的sendBroadcast() 方法将广播发送出去
// sendOrderedBroadcast(intent, null);
// //sendOrderedBroadcast() 方法接收两个参数,
// // 第一个参数仍然是Intent ,
// // 第二个参数是一个与权限相关的字符串,这里传入null 就行了
}
});
//注册一个本地广播监听器
intentFilter=new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");//这个action是上面发送的
localReceiver = new LocalReceiver();
localBroadcastManager.registerReceiver(localReceiver, intentFilter);//通过上面定义的实例来注册广播接收器
}
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
//定义这个localreceiver的类来接收local的广播
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
}
}
}
本地广播是无法通过静态注册的方式来接收的。其实这也完全可以理解,因为静态注册主要就是为了让程序在未启动的情况下也能收到广播,而发送本地广播时,我们的程序肯定是已经启动了,因此也完全不需要使用静态注册的功能。
参考资料
https://blog.csdn.net/dreamer2333/article/details/98204685
https://blog.csdn.net/riqthen/article/details/53436527