第一行代码Android个人笔记(四)——广播

一、注册广播监听

1、动态注册

  1. 建立广播的监听类
  2. 建立过滤器
  3. 在过滤器中添加监听的动作
  4. 注册广播
  5. 取消注册
lateinit var timeChangeReceiver: TimeChangeReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val intentFilter = IntentFilter()//建立过滤器
        intentFilter.addAction("android.intent.action.TIME_TICK")//监听的动作
        timeChangeReceiver = TimeChangeReceiver()//接受广播的类
        registerReceiver(timeChangeReceiver, intentFilter)//注册广播

    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeChangeReceiver)//一定要取消注册
    }

    //接收广播的类,需要继承BroadcastReceiver
    inner class TimeChangeReceiver:BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            Toast.makeText(context,"Time has changed", Toast.LENGTH_SHORT).show()
        }
    }

2、静态注册

  1. 建立广播的监听类
  2. Manifest.xml注册广播监听
    如果使用如图方式添加广播类,会自动注册截图
  3. Manifest.xml注册广播动作
<receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
  1. 某些操作(如监听开机)需要授予权限
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

二、发送自定义广播

1、发送标准广播

val intent = Intent("com.lrgy.broadcasttest.MY_BROADCAST")//构建包含对应广播的Intent对象
            intent.setPackage(packageName)//对于静态注册的隐式广播,一定要调用该方法以确定作用的应用程序,使他成为一条显式广播
            sendBroadcast(intent)//发送广播

2、发送有序广播

有序和无序的差别其实不大只需要修改以下几点:

  1. 发送广播时使用
 sendOrderedBroadcast(intent, null)//发送广播
  1. 在广播注册时指定优先级,优先级高的先接收到广播
    android:priority="200"
        <receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="200">
                <action android:name="com.lrgy.broadcasttest.MY_BROADCAST"/>
            </intent-filter>
        </receiver>

  1. 可以在广播中截断广播的传递
abortBroadcast()

三、广播的最佳实践——强制下线功能

分析:强制下线需要在任何一个页面都实现:收到下线命令,即刻下线的功能。因此为每个activity都写这个功能并不合适,所以需要使用广播。

思路:收到下线广播——触发对应receiver——关闭所有activity——启动登录界面activity

  1. 建立ActivityCollector方便管理所有的Activity
//单例类,伪静态方法
object ActivityCollector {

    private val activities = ArrayList<Activity>()

    fun addActivity(activity: Activity){
        activities.add(activity)
    }

    fun removeActivity(activity: Activity){
        activities.remove(activity)
    }

    fun finishAll(){
        //finish所有activity
        for (activity in activities){
            if (!activity.isFinishing){
                activity.finish()
            }
        }
        activities.clear()//将集合中的所有activity元素清空
    }

}
  1. 建立BaseActivity类,使得所有activity都可以被ActivityCollector控制
/*该项目中所有Activity的父类*/
//添加open才可以被继承
open class BaseActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("BaseActivity", javaClass.simpleName)//javaClass相当于java中的getClass方法,获取当前类的对象
        ActivityCollector.addActivity(this)
    }
    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }
}
  1. 在LoginActivity中添加登录验证
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_login)

        login.setOnClickListener {
            val account = accountEdit.text.toString()
            val password = passwordEdit.text.toString()
            if (account == "admin" && password == "123"){
                val intent = Intent(this, MainActivity::class.java)
                startActivity(intent)
                finish()
            }else{
                Toast.makeText(this, "error", Toast.LENGTH_SHORT).show()
            }
        }
    }
  1. 在MainActivity中添加触发下线的功能
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        forceOffLine.setOnClickListener {
            val intent = Intent("com.lrgy.boardcastbestpractice.FORCE_OFFLINE")
            sendBroadcast(intent)
        }
    }
  1. 在BaseActivity中可以为每个Activity注册和取消注册广播
    特别地,这里使用了内部类进行动态绑定
//自定义广播的对象
    lateinit var receiver: ForceOfflineReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        Log.d("BaseActivity", javaClass.simpleName)//javaClass相当于java中的getClass方法,获取当前类的对象

        ActivityCollector.addActivity(this)
    }

    override fun onResume() {
        super.onResume()

        val intentFilter = IntentFilter()//广播过滤器
        intentFilter.addAction("com.lrgy.boardcastbestpractice.FORCE_OFFLINE")
        receiver = ForceOfflineReceiver()

        //这里在onResume里注册的原因是:避免非栈顶元素有广播的注册,发生WindowManager$BadTokenException: Unable to add window异常
        registerReceiver(receiver,intentFilter)//注册广播绑定
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(receiver)//!!!!!注意一定要在onPause里取消注册
    }

    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 will offline")
                setCancelable(false)//设置为不可取消
                setPositiveButton("OK"){ _, _ ->//省略了参数:dialog, which
                    ActivityCollector.finishAll()//销毁所有activity

                    //启动LoginActivity
                    val i = Intent(context, LoginActivity::class.java)
                    context.startActivity(i)
                }
                show()
            }
        }
    }
  1. 别忘了在Mainifest中修改第一个页面
<activity android:name=".LoginActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
        <activity android:name=".MainActivity">
        </activity>

四、kotlin课堂

1、高阶函数

  1. 创建方式
fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int{
    val result = operation(num1, num2)
    return result
}
  1. 调用方法

可以使用引用函数的方式

	//【::函数名】 可以引用函数
	val result1 = num1AndNum2(num1, num2, ::plus)
	
fun plus(num1: Int, num2: Int): Int{
    return num1 + num2
}

也可以使用lamda表达式

val result2 = num1AndNum2(num1, num2){ n1, n2 ->
        n1 + n2
    }
  1. 使用内联函数(inline关键字)可以消除运行时带来的额外开销
inline fun num1AndNum2(num1: Int, num2: Int, operation: (Int, Int) -> Int): Int{
    val result = operation(num1, num2)
    return result
}

如果只想将其中一个高阶函数变成内联函数,可以使用noinline关键字

inline fun inlineTest(block1: () -> Unit, noinline block2: () -> Unit){
}
  1. 内联函数和非内联函数的区别
    除了可以消除运行时带来的额外开销之外,内联函数中是可以使用retrun关键字来返回的,但是非内联函数只能进行局部返回。(return@函数名)
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值