Android如何使用Flow封裝一個FlowBus工具類
Android中使用Flow封裝一個FlowBus工具類
? 做過Android的同學應該都使用過EvenutBus、Rxbus、LiveDataBus、LiveData等,這些第三方不僅要導入依賴包,而且還要注冊和取消注冊,使用起來非常麻煩,稍不注意就導致內(nèi)存泄漏,自從接觸了Flow、SharedFlow之后感覺使用起來方便多了,于是產(chǎn)生了一個封裝通用事件工具類的想法,直接上代碼.
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<*>>() @Synchronized fun <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> } @Synchronized fun <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 { //私有對象用于發(fā)送消息 private val _events: MutableSharedFlow<T> by lazy { obtainEvent() } //暴露的公有對象用于接收消息 private val events = _events.asSharedFlow() open fun obtainEvent(): MutableSharedFlow<T> = MutableSharedFlow(0, 1, BufferOverflow.DROP_OLDEST) //在主線程中接收數(shù)據(jù) 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") } } } } //在協(xié)程中接收數(shù)據(jù) 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") } } } } //在協(xié)程中發(fā)送數(shù)據(jù) suspend fun post(event: T){ _events.emit(event) } //在主線程中發(fā)送數(shù)據(jù) 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.value if (subscriptCount <= 0) busMap.remove(key) } // 手動調(diào)用的銷毀方法,用于Service、廣播等 fun destroy() { Log.w(TAG, "FlowBus ==== 手動銷毀") val subscriptionCount = _events.subscriptionCount.value if (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傳遞參數(shù)給主界面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 = false textView.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 發(fā)送數(shù)據(jù)
package com.cloud.flowbusdemo.fragment import 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.launch private 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: FragmentMineBinding private val TAG = "MineFragment" private var name: String? = null private var age: Int? = null override 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 的參數(shù)為 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 = false binding.let { it.tvTitle.text = name it.tvAge.text = age.toString() it.tvTitle.setOnClickListener { lifecycleScope.launch { FlowBus.with<MessageEvent>("mineFragment").post(this, messageEvent) } } } } }
3.2 接收數(shù)據(jù):
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發(fā)送數(shù)據(jù):
private fun initService() { val intent = Intent(this@MainActivity, FlowBusTestService::class.java) intent.putExtra("sockUrl","") startService(intent) }
4.2接收數(shù)據(jù):
/** * @auth: njb * @date: 2024/9/22 23:32 * @desc: 描述 */ class FlowBusTestService:Service() { private var sock5Url:String ?= null private 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發(fā)送數(shù)據(jù):
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 + "===發(fā)送數(shù)據(jù)失敗====" + errorResponse.description) val messageEvent = MessageEvent() messageEvent.message = "發(fā)送數(shù)據(jù)失敗--->" + errorResponse.description FloatWindowManager.log("發(fā)送數(shù)據(jù)失敗") } override fun <T> onMessage(msg: String, t: T) { LogUtils.e(TAG,"===接收到消息 String===$msg") val messageEvent = MessageEvent() messageEvent.message = msg FloatWindowManager.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接收數(shù)據(jù):
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.sockUrl LogUtils.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.實現(xiàn)的效果如下:
7.項目demo源碼如下:
https://gitee.com/jackning_admin/flowbus-demo
到此這篇關(guān)于Android使用Flow封裝一個FlowBus工具類的文章就介紹到這了,更多相關(guān)Android FlowBus工具類內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android開發(fā)中MJRefresh自定義刷新動畫效果
本文給大家介紹了MJRefresh自定義刷新動畫效果,包括常見用法等相關(guān)知識,非常不錯,具有參考借鑒價值,感興趣的朋友一起看看吧2016-11-11Android5.0以上實現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面)
下面小編就為大家分享一篇Android5.0以上實現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01Android ViewPager實現(xiàn)圖片輪播效果
這篇文章主要為大家詳細介紹了Android ViewPager實現(xiàn)圖片輪播效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09Android開發(fā)Jetpack組件ViewModel與LiveData使用講解
Jetpack是一個由多個技術(shù)庫組成的套件,可幫助開發(fā)者遵循最佳做法,減少樣板代碼并編寫可在各種Android版本和設(shè)備中一致運行的代碼,讓開發(fā)者精力集中編寫重要的代碼2022-09-09