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-11
Android5.0以上實現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面)
下面小編就為大家分享一篇Android5.0以上實現(xiàn)全透明的狀態(tài)欄方法(仿網(wǎng)易云界面),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-01-01
Android ViewPager實現(xiàn)圖片輪播效果
這篇文章主要為大家詳細介紹了Android ViewPager實現(xiàn)圖片輪播效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09
Android開發(fā)Jetpack組件ViewModel與LiveData使用講解
Jetpack是一個由多個技術(shù)庫組成的套件,可幫助開發(fā)者遵循最佳做法,減少樣板代碼并編寫可在各種Android版本和設備中一致運行的代碼,讓開發(fā)者精力集中編寫重要的代碼2022-09-09

