记得我们说的特性吧,stateflow会在旧值和新值相同的情况下不做更新,但有时我们需要在每次retry某些动作,比如重新连线、重新载入等等
这时,我们就需要用shareFlow了,我这边直接跟别人借例子
class Biller (
private val context: Context,
) : PurchasesUpdatedListener, BillingClientStateListener {
private var billingClient: BillingClient =
BillingClient.newBuilder(context)
.setListener(this)
.enablePendingPurchases()
.build()
private val billingClientStatus = MutableSharedFlow<Int>(
replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
override fun onBillingSetupFinished(result: BillingResult) {
billingClientStatus.tryEmit(result.responseCode)
}
override fun onBillingServiceDisconnected() {
billingClientStatus.tryEmit(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
}
// ...
// Suspend until billingClientStatus == BillingClient.BillingResponseCode.OK
private suspend fun requireBillingClientSetup(): Boolean =
withTimeoutOrNull(TIMEOUT_MILLIS) {
billingClientStatus.first { it == BillingClient.BillingResponseCode.OK }
true
} ?: false
init {
billingClientStatus.tryEmit(BillingClient.BillingResponseCode.SERVICE_DISCONNECTED)
billingClientStatus.observe(ProcessLifecycleOwner.get()) {
when (it) {
BillingClient.BillingResponseCode.OK -> with (billingClient) {
updateSkuPrices()
handlePurchases()
}
else -> {
delay(RETRY_MILLIS)
billingClient.startConnection(this@Biller)
}
}
}
}
private companion object {
private const val TIMEOUT_MILLIS = 2000L
private const val RETRY_MILLIS = 3000L
}
}
这边是以 Google's Billing Client library作为范例,那直接切重点出来讲,在when 判断时,如果result不是ok,那就会先延迟几秒再连线,很重要,这边是需要扗失败的情况下做某些事情,而这个某些事情会触发下一个result
我直接借例子,因为我想不到好例子,socket会自动重连,ui不用更新,webview不用reload,如果你们有好的例子或情境也可以告诉我
jast有写一篇关於singleLiveEvent转换到stateflow的文章,开门
来个取代liveData吧,这篇的范例和前一篇一样,没甚麽好讲的
唯一要注意的就是stateflow不会更新和旧值一样的新值,其余细节,就看前一篇吧
//viewModel
private val _postStateFlow = MutableStateFlow(Post(0,0,"",""))
val postStateFlow = _postStateFlow
init {
viewModelScope.launch {
repo.postFlow.collect {
_postStateFlow.value = it
}
}
}
//fragment
lifecycleScope.launch {
repeatOnLifecycle(Lifecycle.State.STARTED){
viewModel.postStateFlow.collect {
Timber.d(it.toString())
}
}
}
让stateflow能够大放厥词说livedata已经被取代的功能,无非就是databinding了,尽管我自己也什麽再用databinding的功能,但或许是某些开发者的首选,这边就当作棒各位开个门,写个简单的范例
首先layout
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="viewModel"
type="com.kenny.androidplayground.databinding.DBindingViewModel" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".databinding.DataBindingFragment">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@{viewModel.name}"
android:textSize="36sp"
android:background="#333"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/name_field"
/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
android:id="@+id/typing_field"
android:text="@={viewModel.newTypingName}"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
class DataBindingFragment : Fragment() {
private lateinit var binding:FragmentDataBindingBinding
private val viewModel by viewModels<DBindingViewModel>()
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_data_binding, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
binding = FragmentDataBindingBinding.bind(view)
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner
}
}
到这边都还是一般databinding的写法(根据我几个月前的记忆),解说一下,在xml里面,我把editText和Textview的text设置为viewModel里面的变数
且在fragment这边指定了viewModel的instance给xml,那麽最後完成viewModel吧
class DBindingViewModel: ViewModel() {
private val _name = MutableStateFlow<String?>(null)
val name: StateFlow<String?> = _name
val newTypingName = MutableStateFlow<String?>(null)
init {
viewModelScope.launch {
newTypingName
.map {
"edtext enter: $it"
}
.collect {
_name.value = it
}
}
}
}
should-we-choose-kotlins-stateflow-or-sharedflow-to-substitute-for-android-s-livedata
LiveData:还没普及就让我去世?我去你的 Kotlin 协程
今日我们要来使用Kibana内的警报功能,看如何设定Alert让我们能收到异常的通知。 设定Aler...
前言 Hi, 我是鱼板伯爵今天要讲 StatelessWidget & StatfulWid...
-图片来源:Toussaint Ilboudo 我碰到了有关卢克小组中的暴力攻击事件的帖子,并恭敬...
在制作专案时,大多都是与他人共同协作,当一起开发的人越来越多时,就更需要有一套规则或模式来进行合作,...
今天开始会带大家来操作一下 NiFi 如何来与 GCP 相关的服务做整合与设定,首先会先介绍 Goo...