Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding variable is null.. How to let the observer in UI wait till the queried Livedata is excuted from database?

I am trying to get data from database and then bind it in fragment to the XML. So I have repository getting the data from the DB to the ViewModel and the UI fragment is observing the results and then binding the data to the XML. But the problem is that the app is crushing saying that data is null Even though I am voiding the null data in the observer.

I've tried the to execute the query on the background thread it seems to be working properly the returning the data (Photo).

I think the problem is that the query is taking time and the Observer in the fragment is not waiting till the query is done. So the query is okay and I am following exactly Google samples but could not figure out the problem. Thanks in advance.

_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
        }

    })
  }
}

_ The Query in the 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>

_The Error message:

 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)
like image 532
Mustafa Shahoud Avatar asked Sep 27 '19 21:09

Mustafa Shahoud


1 Answers

Yes, your assumption with "it takes time" is correct. The layout wants to draw something as soon its bind and at this time photo is not loaded yet. You could handle the null value in StringUtils.byUser() or adding a null check in the layout like here: Data binding: set property if it isn't null

like image 70
3dmg Avatar answered Nov 15 '22 00:11

3dmg