我正在通过公开公开的函数setRefreshing(app:XML中的刷新)将MutableLiveData绑定到SwipeRefreshLayout上,到那时一切正常……但是让我们介绍一下我的应用程序体系结构。
当我根据刷新状态更改其值时,我具有MutableLiveData的抽象ViewModel。
然后我有两个继承自此摘要的ViewModel(我将它们命名为FirstViewModel和SecondViewModel),将其命名为BaseRefreshViewModel。首先,我有两个几乎相同的XML文件,仅在“ XML”节点中有所不同,在第一个XML中,我导入FirstViewModel,在第二个XML中,则导入对应的SecondViewModel。
我太恐怖了,所以我将其合并为一个XML并导入此BaseRefreshViewModel(list_layout.xml):
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable name="viewModel"
type="my.package.BaseRefreshViewModel" />
</data>
<androidx.coordinatorlayout.widget.CoordinatorLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/coordinator_layout">
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:refreshing="@{viewModel.isRefreshing}"
android:id="@+id/swipe_layout">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/station_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:adapter="@{viewModel.stations}"/>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
</layout>
然后编译器开始疯狂-它说:
Cannot find a setter for <androidx.swiperefreshlayout.widget.SwipeRefreshLayout app:refreshing> that accepts parameter type 'androidx.lifecycle.MutableLiveData'
If a binding adapter provides the setter, check that the adapter is annotated correctly and that the parameter type matches.
好吧,所以我写了我自己的BindingAdapter(在SwipeRefreshLayout中当然更改为app:refresh):
@BindingAdapter("refresh")
fun setRefreshing(view: SwipeRefreshLayout, refreshing: Boolean) {
view.isRefreshing = refreshing
}
还是同样的问题,然后我将BindingAdapter更改为:
@BindingAdapter("refresh")
fun setRefreshing(view: SwipeRefreshLayout, refreshing: MutableLiveData<Boolean>) {
refreshing.value?.let { view.isRefreshing }
}
它开始编译,但是运行后我的应用崩溃并出现错误:
Caused by: java.lang.ClassCastException: java.lang.Boolean cannot be cast to androidx.lifecycle.MutableLiveData
不要拉扯Sherlock ...有趣的是,当我将XML文件中的导入从BaseRefreshViewModel更改为FirstViewModel / SecondViewModel时,即使没有BindingAdapter,它也可以开始编译(我当然不能像这样保留它,因为我有我绑定到适配器的ViewModels中的对象的其他列表)。
这是我的ViewModel初始化片段:
lateinit var stationViewModel: FirstViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
stationViewModel = ViewModelProviders.of(requireActivity()).get(FirstViewModel::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
binding = DataBindingUtil.inflate(inflater, R.layout.list_layout, container, false)
binding.viewModel = stationViewModel
binding.lifecycleOwner = this
return binding.root
}
ViewModel本身
abstract class BaseRefreshViewModel(application: Application) : AndroidViewModel(application) {
val isRefreshing = MutableLiveData<Boolean>().apply { value = false }
val receiver = object : StatusReceiver.Receiver {
override fun onReceiveResult(resultCode: Int, resultData: Bundle) {
when (resultCode) {
StatusReceiver.STATUS_RUNNING -> isRefreshing.value = true
StatusReceiver.STATUS_IDLE -> isRefreshing.value = false
StatusReceiver.STATUS_NO_CONNECTION -> isRefreshing.value = false
StatusReceiver.STATUS_ERROR -> isRefreshing.value = false
}
}
}
abstract fun refresh()
}
如何在不回到创建两个导入了不同ViewModel的XML文件的情况下超越此限制?
我使用Android Studio 3.5 Beta 5只是为了利用DataBinding中改进的错误消息。
更新:
当我将MutableLiveData更改为ObservableBoolean()时,它可以编译并运行良好...但是我不想坚持这一点,我想利用LiveData的生命周期优势。我想这只是说明Databinding编译器现在是如何被窃听的。
摘要:
工作(两个不同的xml,几乎相同)
工作中(一个xml文件,但没有LiveData)
不起作用(一个带有LiveData的xml文件)
答案 0 :(得分:1)
今天也遇到了此错误。 一种可能但很麻烦的解决方法是使BindAdapter接受Object,然后将其强制转换为所需的对象。
更改
@BindingAdapter("refresh")
fun setRefreshing(view: SwipeRefreshLayout, refreshing: Boolean)
到@BindingAdapter("refresh")
fun setRefreshing(view: SwipeRefreshLayout, refreshing: Object)
,然后将其refreshing
投射到Boolean
答案 1 :(得分:1)
另一种选择是使用数据绑定3.4.1,它可以按预期工作。
dataBinding {
enabled = true
version = "3.4.1"
}
答案 2 :(得分:1)
在Kotlin项目上应用插件kotlin-kapt
后为我工作
apply plugin: 'kotlin-kapt'
此后,将LiveData<T>
绑定到字段时将其解包到T
中。
为了记录,我还包括了这些库
// Lifecycle
implementation 'androidx.lifecycle:lifecycle-extensions:2.1.0'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0-rc01'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0-rc01'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.2.0-rc01'
答案 3 :(得分:0)
嗨,希望你做得好。
问题出在app:refreshing="@{viewModel.isRefreshing}"
。
属性 app:refershing 仅接受布尔值值。而您正尝试给它一个 LiveData 值。导致
Caused by: java.lang.ClassCastException: java.lang.Boolean cannot be cast to androidx.lifecycle.MutableLiveData
所以您可以做的是:
在 Data 标签
中创建 Boolean 类型的变量<variable
name="refreshing"
type="Boolean" />
观察您的MutableLiveData
yourBinding.setRefreshing(yourObserverBooleanVariable);
注意:我是根据Java语法编写的
答案 4 :(得分:0)
在您的XML中:
<android.support.v4.widget.SwipeRefreshLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:refreshing="@{viewModel.isLoading}"
app:onRefreshListener="@{() -> viewModel.onRefresh()}">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/station_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:adapter="@{viewModel.stations}"/>
</android.support.v4.widget.SwipeRefreshLayout>
在您的ViewModel中:
public MutableLiveData <Boolean >isLoading = new MutableLiveData ();
/* Needs to be public for Databinding */
public void onRefresh() {
isLoading.setValue(true);
// your logic
}
public void onError(Exception oops){
isLoading.setValue(false);
Log.e("Stack", oops);
}