Android中的每个应用程序都可以对自己感兴趣的⼴播进行注册,这样该程序就只会收到自己所关心的广播内容,这些广播可能是来自于系统的,也可能是来自于其他应用程序的。
Android提供了⼀套完整的API,允许应用程序自由地发送和接收广播。
接收广播的方法:BroadcastReceiver
标准广播:是⼀种完全异步执行的广播,在广播发出之后,所有的BroadcastReceiver几乎会在同⼀时刻收到这条广播消息,因此它们之间没有任何先后顺序可⾔。这种⼴播的效率会比较⾼,但同时也意味着它是无法被截断的。有序广播:则是⼀种同步执行的广播,在广播发出之后,同⼀时刻只会有⼀个BroadcastReceiver能够收到这条广播消息,当这个BroadcastReceiver中的逻辑执行完毕后,广播才会继续传递。所以此时的BroadcastReceiver是有先后顺序的,优先级高的BroadcastReceiver就可以先收到广播消息,并且前面的BroadcastReceiver还可以截断正在传递的广播,这样后面的BroadcastReceiver就无法收到广播消息了。 接收系统广播
注册BroadcastReceiver的方法:
动态注册:代码中注册,可以自由的控制注册与注销,但只能在程序启动之后才能接受广播。静态注册:在AndroidManifest.xml中注册,不允许接收隐式广播 动态注册监听时间变化
新建⼀个继承于BroadcastReceiver的类,并重写父类的onReceive()方法。
当有广播到来时,onReceive()方法就会得到执行,具体的逻辑就可以在这个方法中处理。
class MainActivity : AppCompatActivity() { private lateinit var mainbinding: ActivityMainBinding lateinit var timeChangeReceiver: TimeChangeReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) //使用ViewBinding的标准写法 mainbinding = ActivityMainBinding.inflate(layoutInflater) setContentView(mainbinding.root) //在action中设定想要接受的广播类型 val intentFilter = IntentFilter() intentFilter.addAction("android.intent.action.TIME_TICK") //时间变化时广播的值为“” timeChangeReceiver = TimeChangeReceiver() //创建实例 registerReceiver(timeChangeReceiver,intentFilter) //进行注册 } override fun onDestroy() { super.onDestroy() //动态注册的BroadcastReceiver最后一定要取消注册 unregisterReceiver(timeChangeReceiver) } inner class TimeChangeReceiver : BroadcastReceiver(){ //内部类 override fun onReceive(context: Context?, intent: Intent?) { //接收到广播后执行 Toast.makeText(context,"Time has changed",Toast.LENGTH_SHORT).show() } } }快捷方式创建BroadcasrReceiver
快速创建BroadcasrReceiver类
d出窗口:
用上述方式新建BootCompleteReceiver类
class BootCompleteReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"Boot Complete",Toast.LENGTH_SHORT).show() } }
在AndroidManifest.xml中注册
上述的快捷方式会帮助你自动注册
紫色箭头指向的
橙色箭头指向的
不要在onReceive()方法中添加过多的逻辑或者进行任何的耗时 *** 作
BroadcastReceiver中是不允许开启线程的,当onReceive()方法运行了较长时间而没有结束时,程序会出现错误。
首先需要一个BroadcastReceiver来接受这个广播
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"receiver in MyBroadCastReceiver", Toast.LENGTH_SHORT).show() } }
在AndroidManifest.xml中注册,并声明接受广播的值
在activity_main.xml中添加一个button用于作为发送代码的触发点
在MainActivity中设置点击事件
mainbinding.button.setOnClickListener { val intent = Intent("com.example.broadcasttestkt.MY_BROADCAST") intent.setPackage(packageName) //传入当前应用程序的包名 sendBroadcast(intent) //发送标准广播 }注意
在Android 8.0系统之后,静态注册的BroadcastReceiver是无法接收隐式广播的,而默认情况下我们发出的自定义广播恰恰都是隐式广播。因此这里⼀定要调用setPackage()方法,指定这条广播是发送给哪个应用程序的,从而让它变成⼀条显式广播,否则静态注册的BroadcastReceiver将无法接收到这条广播。
标准广播的工作流程实践首先需要再新建一个BroadcastReceiver来接受这个广播
class AnotherBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"receiver in MyBroadCastReceiver", Toast.LENGTH_SHORT).show() } }
在AndroidManifest.xml中注册,并声明接受广播的值
再点击button时,会分别d出两次Toast
可以说明在标准广播发出后,所有的BroadcastReceiver几乎会在同时接受到这个广播消息
将标准广播改为有序广播只需要改动一行代码
mainbinding.button.setOnClickListener { val intent = Intent("com.example.broadcasttestkt.MY_BROADCAST") intent.setPackage(packageName) //sendBroadcast(intent) //发送标准广播 sendOrderedBroadcast(intent,null) //发送有序广播 第二个参数是权限相关字符串 }
在AndroidManifest.xml中设置接受广播的优先级,优先级高的先接收
在优先级高的MyBroadcastReceiver中设置广播截断
class MyBroadcastReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context,"receiver in MyBroadCastReceiver", Toast.LENGTH_SHORT).show() abortBroadcast() //广播截断 } }
再次点击button时就只有只d出一次消息提示了
首先创建ActivityCollector类,用于管理所有的Activity
object ActivityCollector { private val activities = ArrayList() fun addActivity(activity: Activity){ activities.add(activity) } fun removeActivity(activity: Activity){ activities.remove(activity) } fun finishAll(){ for (activity in activities){ if (!activity.isFinishing){ activity.finish() } } activities.clear() } }
创建baseActivtiy类作为所有Activity的父类
open class baseActivity : AppCompatActivity(){ override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ActivityCollector.addActivity(this) } override fun onDestroy() { super.onDestroy() ActivityCollector.removeActivity(this) } }
编写activity_login.xml作为登录界面
在LoginActivity中编写登录逻辑
class LoginActivity : baseActivity() { private lateinit var loginBinding: ActivityLoginBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) loginBinding = ActivityLoginBinding.inflate(layoutInflater) setContentView(loginBinding.root) loginBinding.login.setOnClickListener { val account = loginBinding.accountEdit.text.toString() //获取用户输入用户名 val password = loginBinding.passwordEdit.text.toString() //获取用户输入密码 if (account == "admin" && password == "123456"){ //如果用户名密码正确,使用intent跳转到MainAvtivity val intent = Intent(this,MainActivity::class.java) startActivity(intent) finish() }else{ //用户名密码错误提示 Toast.makeText(this,"account or password is invalid",Toast.LENGTH_SHORT).show() } } } }
在activity_main.xml中添加一个button,并在MainActivity中编写点击事件
class MainActivity : baseActivity() { private lateinit var mainBinding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) mainBinding = ActivityMainBinding.inflate(layoutInflater) setContentView(mainBinding.root) mainBinding.forceOffline.setOnClickListener { //点击按钮,发送广播 val intent = Intent("com.example.broadcastbestpractices.FORCE_OFFLINE") sendBroadcast(intent) } } }
BroadcastReceiver中需要d出⼀个对话框来阻塞用户的正常 *** 作,但如果创建的是⼀个静态注册的BroadcastReceiver,是没有办法在onReceive()方法里d出对话框这样的UI控件的,而也不可能在每个Activity中都注册⼀个动态的BroadcastReceiver。
所以解决方案是:baseActivity中动态注册⼀个BroadcastReceiver就可以了,因为所有的Activity都继承自baseActivity。
open class baseActivity : AppCompatActivity(){ lateinit var receiver: ForceOfflineReceiver override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) ActivityCollector.addActivity(this) } override fun onResume() { super.onResume() val intentFilter = IntentFilter() intentFilter.addAction("com.example.broadcastbestpractices.FORCE_OFFLINE") receiver = ForceOfflineReceiver() registerReceiver(receiver,intentFilter) } override fun onPause() { super.onPause() unregisterReceiver(receiver) } override fun onDestroy() { super.onDestroy() ActivityCollector.removeActivity(this) } inner class ForceOfflineReceiver : BroadcastReceiver(){ override fun onReceive(context: Context?, intent: Intent?) { alertDialog.Builder(context!!).apply { //构建对话框 setTitle("Warning") setMessage("You are forced to be offline.Please try to login again.") setCancelable(false) //对话框设置为不可取消 setPositiveButton("OK"){ _, _ -> //注册确定按钮 销毁所有Activity并重新启动LoginActivity ActivityCollector.finishAll() val restartIntent = Intent(context,LoginActivity::class.java) context.startActivity(restartIntent) } show() } } } }
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)