绑定变量为空。如何让UI中的观察者等到查询的Livedata从数据库中执行?
Binding variable is null.. How to let the observer in UI wait till the queried Livedata is excuted from database?
我正在尝试从数据库中获取数据,然后将其以片段形式绑定到 XML。
所以我有存储库将数据从数据库获取到 ViewModel,UI 片段正在观察结果,然后将数据绑定到 XML。
但问题是应用程序正在崩溃,说数据为空,即使我正在取消观察者中的空数据。
我已经尝试在后台线程上执行查询,它似乎在返回数据(照片)时正常工作。
我认为问题在于查询需要时间,片段中的 Observer 没有等到查询完成。
所以查询没问题,我完全按照 Google 示例进行操作,但无法找出问题所在。
提前致谢。
_PhotoRepository
class PhotoRepository @Inject constructor(
private val photoDao: PhotoDoa
) {
fun loadPhotoById(photoId: Int): LiveData<Photo> {
// var photo: Photo? = null
// this is working and i am getting the photo object
// appExecutors.diskIO().execute {
photo = photoDao.getObjectPhotoById(photoId)
}
return photoDao.getPhotoById(photoId)
}
}
_PhotoViewModel
class PhotoViewModel @Inject constructor(private val photoRepository:
PhotoRepository) :
ViewModel() {
private var _photoId = MutableLiveData<Int>()
val photoId: LiveData<Int>
get() = _photoId
val photo: LiveData<Photo> = Transformations
.switchMap(_photoId) { id ->
photoRepository.loadPhotoById(id)
}
fun setId(photoId: Int) {
// if (_photoId.value == photoId){
// return
// }
_photoId.value = photoId
}
}
_PhotoFragment
class PhotoFragment : Fragment(), Injectable {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
var binding by autoCleared<FragmentPhotoBinding>()
lateinit var photoViewModel: PhotoViewModel
var photo = Photo()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate<FragmentPhotoBinding>(
inflater,
R.layout.fragment_photo,
container,
false
)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val params = PhotoFragmentArgs.fromBundle(arguments!!)
photoViewModel = ViewModelProviders.of(
this,
viewModelFactory).get(PhotoViewModel::class.java)
photoViewModel.setId(params.photoId)
// photoViewModel.photo.removeObservers(viewLifecycleOwner)
photoViewModel.photo.observe(viewLifecycleOwner, Observer {
if (it != null) {
binding.photo = it
}
})
}
}
_Doa中的查询class
@Query(" SELECT * FROM Photo WHERE id = :id")
abstract fun getPhotoById ( id: Int): LiveData<Photo>
_fragment_photo.xml
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.mustafa.pixabayapp.models.Photo"/>
<variable
name="photo"
type="Photo"/>
<import type="com.mustafa.pixabayapp.utils.StringUtils" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/photo_fragment_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:imageUrl="@{photo.webFormatURL}"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@color/colorTransparentDark"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/photo_fragment_tags"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{StringUtils.getTags(photo.tags)}"
tools:text="TEST - TEST - TEST"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/photo_fragment_user_name"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="@{StringUtils.byUser(photo.userName)}"
tools:text="By: Mustafa"/>
<TextView
android:id="@+id/photo_fragment_comments"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="4dp"
android:drawableStart="@drawable/ic_comment"
android:text="@{StringUtils.getCommentsAsString(photo.commentsCount)}"
tools:text="2222"/>
<TextView
android:id="@+id/photo_fragment_favorites"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_toStartOf="@id/photo_fragment_comments"
android:drawableStart="@drawable/ic_favorite"
android:text="@{StringUtils.getFavoritesAsString(photo.favoritesCount)}"
tools:text="2222"/>
<TextView
android:id="@+id/photo_fragment_likes"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_toStartOf="@id/photo_fragment_favorites"
android:drawableStart="@drawable/ic_like"
android:text="@{StringUtils.getLikesAsString(photo.likesCount)}"
tools:text="2222"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
</layout>
_错误信息:
java.lang.IllegalArgumentException:
Parameter specified as non-null is null:
method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter
userName at com.mustafa.pixabayapp.utils.StringUtils.byUser(Unknown
Source:2)at com.mustafa.pixabayapp.databinding.FragmentPhotoBindingImpl.
executeBindings(FragmentPhotoBindingImpl.java:138)
是的,您对 "it takes time" 的假设是正确的。布局想要在其绑定后立即绘制一些东西,此时 photo
尚未加载。
您可以处理 StringUtils.byUser()
中的空值或在布局中添加空值检查,如下所示:
我正在尝试从数据库中获取数据,然后将其以片段形式绑定到 XML。 所以我有存储库将数据从数据库获取到 ViewModel,UI 片段正在观察结果,然后将数据绑定到 XML。 但问题是应用程序正在崩溃,说数据为空,即使我正在取消观察者中的空数据。
我已经尝试在后台线程上执行查询,它似乎在返回数据(照片)时正常工作。
我认为问题在于查询需要时间,片段中的 Observer 没有等到查询完成。 所以查询没问题,我完全按照 Google 示例进行操作,但无法找出问题所在。 提前致谢。
_PhotoRepository
class PhotoRepository @Inject constructor(
private val photoDao: PhotoDoa
) {
fun loadPhotoById(photoId: Int): LiveData<Photo> {
// var photo: Photo? = null
// this is working and i am getting the photo object
// appExecutors.diskIO().execute {
photo = photoDao.getObjectPhotoById(photoId)
}
return photoDao.getPhotoById(photoId)
}
}
_PhotoViewModel
class PhotoViewModel @Inject constructor(private val photoRepository:
PhotoRepository) :
ViewModel() {
private var _photoId = MutableLiveData<Int>()
val photoId: LiveData<Int>
get() = _photoId
val photo: LiveData<Photo> = Transformations
.switchMap(_photoId) { id ->
photoRepository.loadPhotoById(id)
}
fun setId(photoId: Int) {
// if (_photoId.value == photoId){
// return
// }
_photoId.value = photoId
}
}
_PhotoFragment
class PhotoFragment : Fragment(), Injectable {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
var binding by autoCleared<FragmentPhotoBinding>()
lateinit var photoViewModel: PhotoViewModel
var photo = Photo()
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = DataBindingUtil.inflate<FragmentPhotoBinding>(
inflater,
R.layout.fragment_photo,
container,
false
)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
val params = PhotoFragmentArgs.fromBundle(arguments!!)
photoViewModel = ViewModelProviders.of(
this,
viewModelFactory).get(PhotoViewModel::class.java)
photoViewModel.setId(params.photoId)
// photoViewModel.photo.removeObservers(viewLifecycleOwner)
photoViewModel.photo.observe(viewLifecycleOwner, Observer {
if (it != null) {
binding.photo = it
}
})
}
}
_Doa中的查询class
@Query(" SELECT * FROM Photo WHERE id = :id")
abstract fun getPhotoById ( id: Int): LiveData<Photo>
_fragment_photo.xml
<layout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="com.mustafa.pixabayapp.models.Photo"/>
<variable
name="photo"
type="Photo"/>
<import type="com.mustafa.pixabayapp.utils.StringUtils" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="@+id/photo_fragment_image_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:imageUrl="@{photo.webFormatURL}"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:background="@color/colorTransparentDark"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/photo_fragment_tags"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{StringUtils.getTags(photo.tags)}"
tools:text="TEST - TEST - TEST"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/photo_fragment_user_name"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:text="@{StringUtils.byUser(photo.userName)}"
tools:text="By: Mustafa"/>
<TextView
android:id="@+id/photo_fragment_comments"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_marginEnd="4dp"
android:drawableStart="@drawable/ic_comment"
android:text="@{StringUtils.getCommentsAsString(photo.commentsCount)}"
tools:text="2222"/>
<TextView
android:id="@+id/photo_fragment_favorites"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_toStartOf="@id/photo_fragment_comments"
android:drawableStart="@drawable/ic_favorite"
android:text="@{StringUtils.getFavoritesAsString(photo.favoritesCount)}"
tools:text="2222"/>
<TextView
android:id="@+id/photo_fragment_likes"
style="@style/PixabayImageTextUser"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
android:layout_toStartOf="@id/photo_fragment_favorites"
android:drawableStart="@drawable/ic_like"
android:text="@{StringUtils.getLikesAsString(photo.likesCount)}"
tools:text="2222"/>
</RelativeLayout>
</LinearLayout>
</RelativeLayout>
</layout>
_错误信息:
java.lang.IllegalArgumentException:
Parameter specified as non-null is null:
method kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull, parameter
userName at com.mustafa.pixabayapp.utils.StringUtils.byUser(Unknown
Source:2)at com.mustafa.pixabayapp.databinding.FragmentPhotoBindingImpl.
executeBindings(FragmentPhotoBindingImpl.java:138)
是的,您对 "it takes time" 的假设是正确的。布局想要在其绑定后立即绘制一些东西,此时 photo
尚未加载。
您可以处理 StringUtils.byUser()
中的空值或在布局中添加空值检查,如下所示: