Android Kotlin ViewModel is not Loading/Showing content at first launch of the fragment/activity

42 Views Asked by At

I have a Android Kotlin MVVM project, ViewModel is not being loaded at first lauch of the Fragment. But if i refresh it load data and show in the UI

HomeFragment.kt UI

class HomeFragment : Fragment() {
    private val publicationViewModel: ListViewModel by viewModels()
    private lateinit var magazineList: RecyclerView
    private lateinit var paperList: RecyclerView
    private var magazineListAdapter = PaperAdapter(arrayListOf())
    private var paperListAdapter = PaperAdapter(arrayListOf())
    private lateinit var paperSkeletonScreen: LinearLayout
    private lateinit var magazineSkeletonScreen: LinearLayout
    private var pullToRefresh: SwipeRefreshLayout? = null
    var page: Int = 1

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?,
    ): View {
        val view: View = LayoutInflater.from(container!!.context)
            .inflate(R.layout.fragment_main_home, container, false)
        findAll()
        paperList = view.findViewById(R.id.today_newspaper_list)
        paperList.layoutManager =
            LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false).apply {
                paperList.layoutManager
            }
        paperList.apply {
            adapter = paperListAdapter
        }
        paperSkeletonScreen = view.findViewById(R.id.newspaper_loader)

        magazineList = view.findViewById(R.id.magazine_list)
        magazineList.layoutManager =
            LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false).apply {
                magazineList.layoutManager
            }
        magazineList.apply {
            adapter = magazineListAdapter
        }
        magazineSkeletonScreen = view.findViewById(R.id.magazine_loader)

        pullToRefresh = view.findViewById(R.id.refresh_page) as SwipeRefreshLayout
        pullToRefresh?.setOnRefreshListener {
            TrackerService.trackUserEvent(requireActivity(), "refresh_home")
            refreshPage()
        }
        observeViewModelPublications()
        return view
    }

    private fun observeViewModelPublications() {
        try {
            activity?.let { it ->
                publicationViewModel.apply {
                    todayPapers.observe(it) { pubs ->
                        pubs?.let {
                            paperListAdapter.getPapers(it)
                            paperSkeletonScreen.visibility = View.GONE
                        }
                    }
                }

                publicationViewModel.apply {
                    magazine.observe(it) { pubs ->
                        pubs?.let { magazine ->
                            magazineListAdapter.getPapers(magazine)
                            magazineSkeletonScreen.visibility = View.GONE
                        }
                    }
                }

                publicationViewModel.viewModelLoadError.observe(it) { error ->
                    if (!error.isNullOrEmpty()) {
                        ToastHelper.showToast(requireActivity(), error, 1)
                    }
                }
            }
        } catch (_: Exception) {
            ToastHelper.showToast(
                requireActivity(), requireActivity().getString(R.string.something_wrong), 1
            )
        }
    }


    private fun refreshPage() {
        try {
            pullToRefresh?.isRefreshing = false
            arrayOf(
                paperSkeletonScreen, magazineSkeletonScreen
            ).forEach { it.visibility = View.VISIBLE }
            findAll()
            Handler(Looper.getMainLooper()).postDelayed({
                observeViewModelPublications()
            }, 5000)
        } catch (_: Exception) {
            ToastHelper.showToast(requireActivity(), getString(R.string.something_wrong), 1)
        }
    }

    private fun findAll() {
        publicationViewModel.findPublications("Token", "KE", 1)
    }


    companion object {
        fun newInstance(): MainHomeFragment {
            return MainHomeFragment()
        }
    }
}

Interact with ApiService to make api call and updates the UI ListViewModel.kt


class ListViewModel : ViewModel() {
    private val userData = ApiClient.ApiService() 
    private var job: Job? = null

    // Publications
    val magazine = MutableLiveData<PublicationModal>()
    val todayPapers = MutableLiveData<List<PaperModal>>() 
    // Error Handling
    val viewModelLoadError = MutableLiveData<String?>()
    val loading = MutableLiveData<Boolean>()
 

    fun findPublications(bearer: String?, country: String?, page: Int?) {
        fetchTodayPapers(country)
        fetchMagazine(country)
    }

    private fun fetchTodayPapers(country: String?) {
        viewModelScope.launch {
            when (val result =
                RequestService().viewModelFetch(loading) { userData.findTodayPapers(country) }) {
                is RequestService.Result.Success -> {
                    todayPapers.value = result.data?.data
                    viewModelLoadError.value = null
                }

                is RequestService.Result.Error -> onError(result.message)
            }
        }
    }

    private fun fetchMagazine(country: String?) {
        viewModelScope.launch {
            when (val result = RequestService().viewModelFetch(loading) {
                userData.getTodayMagazine(
                    "2",
                    country
                )
            }) {
                is RequestService.Result.Success -> {
                    magazine.value = result.data?.data
                    viewModelLoadError.value = null
                }

                is RequestService.Result.Error -> onError(result.message)
            }
        }
    }
 
    private fun onError(
        message: String,
    ) {
        viewModelLoadError.value = message
        loading.value = false
    }

    override fun onCleared() {
        super.onCleared()
        job?.cancel()
    }

}

Extension Service to make api calls scallfolds everything in it to remove duplicate code in addition the val response = fetchDataFunction() returns null at start but when you refresh it return data. RequestService.kt


class RequestService {
 
    suspend fun <T> viewModelFetch(
        loadingLiveData: MutableLiveData<Boolean>,
        fetchDataFunction: suspend () -> Response<T>,
    ): Result<T> {
        return try {
            loadingLiveData.postValue(true)
            val response = fetchDataFunction()
            if (response.isSuccessful) {
                loadingLiveData.postValue(false)
                return Result.Success(response.body())
            } else {
                val responseBody = response.errorBody()?.toPrettyJson()
                if (responseBody == null) {
                    loadingLiveData.postValue(true)
                    Result.Success(response.body())
                } else {
                    val errorMessage =
                        responseBody.optString("message")
                            ?: responseBody.optString("error")
                    loadingLiveData.postValue(false)
                    return Result.Error(errorMessage)
                }
            }
        } catch (e: SocketTimeoutException) {
            loadingLiveData.postValue(false)
            return Result.Error("Request is taking too long to complete, try again later")
        } catch (e: IOException) {
            loadingLiveData.postValue(false)
            return Result.Error("Network error, check your internet connection")
        } catch (e: Exception) {
            loadingLiveData.postValue(false)
            return Result.Error("Network error, check your internet connection")
        }
    }

    sealed class Result<out T> {
        data class Success<out T>(val data: T?) : Result<T>()
        data class Error(val message: String) : Result<Nothing>()
    }
}

ApiClient.kt calls my Api's and returns data

  @GET("today")
    suspend fun findTodayPapers(
        @Query("country") country: String?,
    ): Response<PaperData>
     

  @GET("latest")
    suspend fun getTodayMagazine(
        @Query("country") country: String?,
    ): Response<PaperData>



What is wrong in the above code, Any help

0

There are 0 best solutions below