当前位置: 首页 > news >正文

Android使用Flow封装一个FlowBus工具类

Android中使用Flow封装一个FlowBus工具类

​ 做过Android的同学应该都使用过EvenutBus、Rxbus、LiveDataBus、LiveData等,这些第三方不仅要导入依赖包,而且还要注册和取消注册,使用起来非常麻烦,稍不注意就导致内存泄漏,自从接触了Flow、SharedFlow之后感觉使用起来方便多了,于是产生了一个封装通用事件工具类的想法,直接上代码.

1.FlowBus:

/*** @auth: njb* @date: 2024/7/18 10:17* @desc: 基于Flow封装的FlowBus*/
object FlowBus {private const val TAG = "FlowBus"private val busMap = mutableMapOf<String, FlowEventBus<*>>()private val busStickMap = mutableMapOf<String, FlowStickEventBus<*>>()@Synchronizedfun <T> with(key: String): FlowEventBus<T> {var flowEventBus = busMap[key]if (flowEventBus == null) {flowEventBus = FlowEventBus<T>(key)busMap[key] = flowEventBus}return flowEventBus as FlowEventBus<T>}@Synchronizedfun <T> withStick(key: String): FlowStickEventBus<T> {var stickEventBus = busStickMap[key]if (stickEventBus == null) {stickEventBus = FlowStickEventBus<T>(key)busStickMap[key] = stickEventBus}return stickEventBus as FlowStickEventBus<T>}open class FlowEventBus<T>(private val key: String) : DefaultLifecycleObserver {//私有对象用于发送消息private val _events: MutableSharedFlow<T> by lazy {obtainEvent()}//暴露的公有对象用于接收消息private val events = _events.asSharedFlow()open fun obtainEvent(): MutableSharedFlow<T> =MutableSharedFlow(0, 1, BufferOverflow.DROP_OLDEST)//在主线程中接收数据fun register(lifecycleOwner: LifecycleOwner,action: (t: T) -> Unit){lifecycleOwner.lifecycleScope.launch {events.collect {try {action(it)}catch (e:Exception){e.printStackTrace()Log.e(TAG, "FlowBus - Error:$e")}}}}//在协程中接收数据fun register(scope: CoroutineScope,action: (t: T) -> Unit){scope.launch {events.collect{try {action(it)}catch (e:Exception){e.printStackTrace()Log.e(TAG, "FlowBus - Error:$e")}}}}//在协程中发送数据suspend fun post(event: T){_events.emit(event)}//在主线程中发送数据fun post(scope: CoroutineScope,event: T){scope.launch {_events.emit(event)}}override fun onDestroy(owner: LifecycleOwner) {super.onDestroy(owner)Log.w(TAG, "FlowBus ==== 自动onDestroy")val subscriptCount = _events.subscriptionCount.valueif (subscriptCount <= 0)busMap.remove(key)}// 手动调用的销毁方法,用于Service、广播等fun destroy() {Log.w(TAG, "FlowBus ==== 手动销毁")val subscriptionCount = _events.subscriptionCount.valueif (subscriptionCount <= 0) {busMap.remove(key)}}}class FlowStickEventBus<T>(key: String) : FlowEventBus<T>(key) {override fun obtainEvent(): MutableSharedFlow<T> =MutableSharedFlow(1, 1, BufferOverflow.DROP_OLDEST)}}

2.在Activity中的使用:

2.1传递参数给主界面Activity:

/*** @auth: njb* @date: 2024/9/10 23:49* @desc: 描述*/
class TestActivity :AppCompatActivity(){private val textView:TextView by lazy { findViewById(R.id.tv_test) }override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_test)initFlowBus()}private fun initFlowBus() {val messageEvent = MessageEvent()messageEvent.message = "stop"messageEvent.state = falsetextView.setOnClickListener {lifecycleScope.launch {FlowBus.with<MessageEvent>("test").post(this, messageEvent)finish()}}}
}

2.2 MainActivity接收:

/*** 初始化*/
private fun initView() {binding.rvWallpaper.apply {layoutManager = GridLayoutManager(this@MainActivity, 2)adapter = wallPaperAdapter}binding.btnGetWallpaper.setOnClickListener {lifecycleScope.launch {mainViewModel.mainIntentChannel.send(MainIntent.GetWallpaper)}val intent = Intent(this@MainActivity,TestActivity::class.java)startActivity(intent)}FlowBus.with<MessageEvent>("test").register(this@MainActivity) {LogUtils.d(TAG,it.toString())if(it.message == "stop"){LogUtils.d(TAG,"===接收到的消息为==="+it.message)}}FlowBus.with<MessageEvent>("mineFragment").register(this@MainActivity) {LogUtils.d(TAG,it.toString())if(it.message == "onMine"){LogUtils.d(TAG,"===接收到的消息为1111==="+it.message)}}
}

3.在Fragment中的使用:

3.1 发送数据

package com.cloud.flowbusdemo.fragmentimport android.os.Bundle
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.lifecycle.lifecycleScope
import com.cloud.flowbusdemo.databinding.FragmentMineBinding
import com.cloud.flowbusdemo.flow.FlowBus
import com.cloud.flowbusdemo.model.MessageEvent
import kotlinx.coroutines.launchprivate const val ARG_PARAM_NAME = "name"
private const val ARG_PARAM_AGE = "age"
/*** @auth: njb* @date: 2024/9/17 19:43* @desc: 描述*/
class MineFragment :Fragment(){private lateinit var binding: FragmentMineBindingprivate val TAG = "MineFragment"private var name: String? = nullprivate var age: Int? = nulloverride fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)arguments?.let {name = it.getString(ARG_PARAM_NAME)age = it.getInt(ARG_PARAM_AGE)}Log.i(TAG, "MainFragment 传递到 MineFragment 的参数为 name = $name , age = $age")Log.d(TAG, "姓名:" + name + "年龄:" + age)}override fun onCreateView(inflater: LayoutInflater,container: ViewGroup?,savedInstanceState: Bundle?): View {binding = FragmentMineBinding.inflate(layoutInflater)initView()return binding.root}private fun initView() {val messageEvent = MessageEvent()messageEvent.message = "onMine"messageEvent.state = falsebinding.let {it.tvTitle.text = nameit.tvAge.text  = age.toString()it.tvTitle.setOnClickListener {lifecycleScope.launch {FlowBus.with<MessageEvent>("mineFragment").post(this, messageEvent)}}}}
}

在这里插入图片描述

3.2 接收数据:

private fun initView() {binding.rvWallpaper.apply {layoutManager = GridLayoutManager(this@MainActivity, 2)adapter = wallPaperAdapter}binding.btnGetWallpaper.setOnClickListener {lifecycleScope.launch {mainViewModel.mainIntentChannel.send(MainIntent.GetWallpaper)}val intent = Intent(this@MainActivity,TestActivity::class.java)startActivity(intent)}FlowBus.with<MessageEvent>("test").register(this@MainActivity) {LogUtils.d(TAG,it.toString())if(it.message == "stop"){LogUtils.d(TAG,"===接收到的消息为==="+it.message)}}FlowBus.with<MessageEvent>("mineFragment").register(this@MainActivity) {LogUtils.d(TAG,it.toString())if(it.message == "onMine"){LogUtils.d(TAG,"===接收到的消息为1111==="+it.message)}}
}

在这里插入图片描述

4.在Service中的使用:

4.1发送数据:

private fun initService() {val intent = Intent(this@MainActivity, FlowBusTestService::class.java)intent.putExtra("sockUrl","")startService(intent)
}

4.2接收数据:

/*** @auth: njb* @date: 2024/9/22 23:32* @desc: 描述*/
class FlowBusTestService:Service() {private var sock5Url:String ?= nullprivate val TAG = "FlowBusTestService"override fun onBind(intent: Intent?): IBinder? {return null}override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {intent?.let {this.sock5Url = intent.getStringExtra("sockUrl")LogUtils.d(TAG,"====收到的ip为==="+this.sock5Url)}return if (intent?.action == Constants.ACTION_DISCONNECT) {disconnect()START_NOT_STICKY} else {connect()START_STICKY}}private fun connect() {}private fun disconnect() {}
}

5.在Websock中的使用:

5.1发送数据:

private fun connectWebSocket() {LogUtils.e(TAG, "===connectUrl===$currentWebSocketUrl")try {if (mWebSocketManager == null) {return}mWebSocketManager?.addListener(object : SocketListener {override fun onConnected() {LogUtils.e(TAG, "===连接成功====")val messageEvent = MessageEvent()messageEvent.message = "socket连接成功"FloatWindowManager.log("socket连接成功")CoroutineScope(Dispatchers.Main).launch{FlowBus.with<MessageEvent>("onConnected").post(this,messageEvent)}}override fun onConnectFailed(throwable: Throwable) {LogUtils.e(TAG, "===连接失败====")val messageEvent = MessageEvent()messageEvent.message = "socket连接失败:$currentWebSocketUrl"FloatWindowManager.log("socket连接失败")}override fun onDisconnect() {LogUtils.e(TAG, "===断开连接====")val messageEvent = MessageEvent()messageEvent.message = "socket断开连接"FloatWindowManager.log("socket断开连接")}override fun onSendDataError(errorResponse: ErrorResponse) {LogUtils.e(TAG + "===发送数据失败====" + errorResponse.description)val messageEvent = MessageEvent()messageEvent.message = "发送数据失败--->" + errorResponse.descriptionFloatWindowManager.log("发送数据失败")}override fun <T> onMessage(msg: String, t: T) {LogUtils.e(TAG,"===接收到消息 String===$msg")val messageEvent = MessageEvent()messageEvent.message = msgFloatWindowManager.log("===接收到消息===$msg")taskManager?.onHandleMsg(msg)}override fun <T> onMessage(bytes: ByteBuffer, t: T) {LogUtils.e(TAG, "===接收到消息byteBuffer===="+GsonUtils.toJson(bytes))val rBuffer = ByteBuffer.allocate(1024)val charset = Charset.forName("UTF-8")try {val receiveText =charset.newDecoder().decode(rBuffer.asReadOnlyBuffer()).toString()LogUtils.e(TAG, "===接收到消息byteBuffer====$receiveText")val messageEvent = MessageEvent()messageEvent.message = receiveText// FloatWindowManager.log("===收到消息 byte===$receiveText")} catch (e: CharacterCodingException) {throw RuntimeException(e)}}override fun onPing(pingData: Framedata) {LogUtils.e(TAG, "===心跳onPing===$pingData")}override fun onPong(framedata: Framedata) {LogUtils.e(TAG, "===心跳onPong===$framedata")val messageEvent = MessageEvent()messageEvent.message = format.format(Date()) + "  | 心跳onPong->"FloatWindowManager.log("===心跳onPong===${format.format(Date())}${"->"}$currentWebSocketUrl")}})mWebSocketManager?.start()} catch (e: Exception) {e.printStackTrace()}
}

5.2接收数据:

private fun initFlowBus() {FlowBus.with<MessageEvent>("onConnected").register(this@MainActivity) {LogUtils.d(TAG, "收到消息为:$it")}FlowBus.with<MessageEvent>("onStartVpn").register(this@MainActivity) {LogUtils.d(TAG, "收到vpn消息为:$it")CoroutineScope(Dispatchers.Main).launch {if (it.message == "start" && it.state && Constants.SWITCH_IP) {this@MainActivity.sockUrl = it.sockUrlLogUtils.d(TAG, "收到代理地址为:${it.sockUrl}")AppUtils.prepareVpn(this@MainActivity,it.sockUrl)// prepareVpn()}}}FlowBus.with<MessageEvent>("onStopVpn").register(this@MainActivity) {LogUtils.d(TAG, "收到vpn消息为:$it")if (it.message == "stop" && !it.state) {AppUtils.stopVpn(this@MainActivity)}}
}

在这里插入图片描述

6.实现的效果如下:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

7.项目demo源码如下:

https://gitee.com/jackning_admin/flowbus-demo

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • Linux-vim使用
  • Android Camera 预览角度和拍照保存图片角度相关
  • DNF Decouple and Feedback Network for Seeing in the Dark
  • 网络安全:构建数字世界的坚固防线
  • 【设计模式】万字详解:深入掌握五大基础行为模式
  • QT For Android开发-打开PPT文件
  • 使用ffmpeg实现音视频文件格式转换
  • 深入解析Linux驱动开发中的I2C时序及I2C高频面试题
  • web基础—dvwa靶场(七)SQL Injection
  • 深度deepin初体验(一)系统详细安装过程 | 国产系统
  • patch 命令:补丁的应用
  • SpringBoot+Aop+注解方式 实现多数据源动态切换
  • [游戏技术]L4D服务器报错解决
  • 31省市农业地图大数据
  • 开源RK3588 AI Module7,并与Jetson Nano生态兼容的低功耗AI模块
  • echarts的各种常用效果展示
  • JS+CSS实现数字滚动
  • Js基础知识(四) - js运行原理与机制
  • k8s 面向应用开发者的基础命令
  • LeetCode18.四数之和 JavaScript
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • Object.assign方法不能实现深复制
  • text-decoration与color属性
  • 编写高质量JavaScript代码之并发
  • 关于for循环的简单归纳
  • 记录一下第一次使用npm
  • 微服务入门【系列视频课程】
  • 我这样减少了26.5M Java内存!
  • 智能网联汽车信息安全
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • ​【原创】基于SSM的酒店预约管理系统(酒店管理系统毕业设计)
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • #微信小程序:微信小程序常见的配置传旨
  • $().each和$.each的区别
  • $.extend({},旧的,新的);合并对象,后面的覆盖前面的
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (1)常见O(n^2)排序算法解析
  • (C11) 泛型表达式
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (回溯) LeetCode 46. 全排列
  • (回溯) LeetCode 78. 子集
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (四)进入MySQL 【事务】
  • (五)IO流之ByteArrayInput/OutputStream
  • (小白学Java)Java简介和基本配置
  • (转)c++ std::pair 与 std::make
  • ***详解账号泄露:全球约1亿用户已泄露
  • .DFS.
  • .NET Compact Framework 多线程环境下的UI异步刷新
  • .net core 连接数据库,通过数据库生成Modell
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .Net mvc总结