Saturday 26 September 2020

How can I check to see if JSON data is null without an infinite loop?

I have a viewmodel and data classes that fetch the NASA api for photos of Mars. The user should be displayed images from a random date queried. I always need an image url (imgSrc in Photo class) returned. If no url (imgSrc) is found, refresh data until one is found and display it. This logic would need to return an imgSrc following launch of the application as well as after swiperefreshlayout if the user chooses to swipe to refresh. I have been stuck on this for a week with no resolve. What is the best way to handle this? Even if I have to refactor my code I would like to be pointed in the right direction.

Here is the actual project on github.

JSON that I want to fetch

JSON returning no imgSrc

viewmodel

import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.dev20.themarsroll.models.MarsPhotos
import com.dev20.themarsroll.models.Photo
import com.dev20.themarsroll.repository.MarsPhotoRepository
import com.dev20.themarsroll.util.Resource
import kotlinx.coroutines.launch
import retrofit2.Response

class MarsPhotoViewModel(

    private val marsPhotoRepository: MarsPhotoRepository
    ): ViewModel() {

    val marsPhotos: MutableLiveData<Resource<MarsPhotos>> = MutableLiveData()

    init {
        getRandomPhotos()
    }

     fun getCuriosityPhotos(solQuery: Int, roverQuery: Int, camera: String) = viewModelScope.launch {
        marsPhotos.postValue(Resource.Loading())
        val response = marsPhotoRepository.getCuriosityPhotos(solQuery, roverQuery, camera)
        marsPhotos.postValue(handlePhotosResponse(response))
    }

    private fun handlePhotosResponse(response: Response<MarsPhotos> ) : Resource<MarsPhotos> {
        if(response.isSuccessful) {
                response.body()?.let { resultResponse ->
                    return Resource.Success(resultResponse)
            }
        }
        return Resource.Error(response.message())
    }

    fun getRandomPhotos() {
        getCuriosityPhotos((1..2878).random(), 5, "NAVCAM")
    }

    fun savePhoto(photo: Photo) = viewModelScope.launch {
        marsPhotoRepository.upsert(photo)
    }

    fun getSavedPhotos() = marsPhotoRepository.getSavedPhotos()

    fun deletePhoto(photo: Photo) = viewModelScope.launch {
        marsPhotoRepository.deletePhoto(photo)
    }
}

CuriosityFragment


import android.os.Bundle
import android.util.Log
import androidx.fragment.app.Fragment
import android.view.View
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import com.dev20.themarsroll.R
import com.dev20.themarsroll.adapters.MarsPhotoAdapter
import com.dev20.themarsroll.util.Resource
import com.dev20.ui.MarsActivity
import com.dev20.ui.MarsPhotoViewModel
import kotlinx.android.synthetic.main.fragment_curiosity.*


class CuriosityFragment : Fragment(R.layout.fragment_curiosity) {
    lateinit var viewModel: MarsPhotoViewModel
    lateinit var marsPhotoAdapter: MarsPhotoAdapter
    
    val TAG = "CuriosityFragment"

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        viewModel = (activity as MarsActivity).viewModel
        setupRecyclerView()

        swipeLayout.setOnRefreshListener {
            viewModel.getRandomPhotos()
            swipeLayout.isRefreshing = false
        }

        marsPhotoAdapter.setOnItemClickListener {
            val bundle = Bundle().apply {
                putSerializable("photo", it)
            }
            findNavController().navigate(
                R.id.action_curiosityFragment_to_cameraFragment,
                bundle
            )
        }

        viewModel.marsPhotos.observe(viewLifecycleOwner, { response ->
            when(response) {
                is Resource.Success -> {
                    hideProgressBar()
                    response.data?.let { curiosityResponse ->
                    marsPhotoAdapter.differ.submitList(curiosityResponse.photos)
                    }
                }
                is Resource.Error -> {
                    hideProgressBar()
                    response.message?.let { message ->
                        Log.e(TAG, "An Error occurred: $message")
                    }
                }
                is Resource.Loading -> {
                    showProgressBar()
                }
            }
        })
    }

    private fun hideProgressBar() {
        curiosityPaginationProgressBar.visibility = View.INVISIBLE
    }

    private fun showProgressBar() {
        curiosityPaginationProgressBar.visibility = View.VISIBLE
    }

    private fun setupRecyclerView() {
        marsPhotoAdapter = MarsPhotoAdapter()
        rvCuriosityPhotos.apply {
        adapter = marsPhotoAdapter
            layoutManager = LinearLayoutManager(activity)
        }
    }
}

MarsPhoto data class

data class MarsPhotos(
    val photos: MutableList<Photo>,
    val camera: MutableList<Camera>
)

Photo data class


import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.TypeConverters
import com.google.gson.annotations.SerializedName
import java.io.Serializable

@Entity(
    tableName = "photos"
)

@TypeConverters
data class Photo(
    @PrimaryKey(autoGenerate = true)
    var id: Int? = null,
    @SerializedName("earth_date")
    val earthDate: String,
    @SerializedName("img_src")
    val imgSrc: String,
    val sol: Int,
    @SerializedName("rover_id")
    val rover: Int,
) : Serializable


from How can I check to see if JSON data is null without an infinite loop?

No comments:

Post a Comment