Now the data is fetched,but I also want the progress bar to show.I am using hilt for depedency injection.Check out my files below.I highly appreciate your feedback.I arleady have the Result class which holds the states but I am not quite sure on how to connect it with viewModel.
Api interface.kt
interface CampInterface {
@GET("programs") //includes endpoint
fun getPrograms() : Call<List<Programs>>
@GET("departments") //includes endpoint
fun getDepartments() : Call<List<Departments>>
}
viewModel.kt
@HiltViewModel
class campDataViewModel @Inject constructor(private val campDataRepository: CampDataRepository) : ViewModel() {
val programList = MutableLiveData<List<Programs>>()
val departmentList = MutableLiveData<List<Departments>>()
val errorMessage = MutableLiveData<String>()
fun getProgramData() {
val response=campDataRepository.getAllPrograms()
response.enqueue(object : Callback<List<Programs>?> {
override fun onResponse(
call: Call<List<Programs>?>,
response: Response<List<Programs>?>
) {
programList.postValue(response.body())
}
override fun onFailure(call: Call<List<Programs>?>, t: Throwable) {
errorMessage.postValue(t.message)
}
})
}
fun getDepartmentData() {
val response=campDataRepository.getAllDepartments()
response.enqueue(object : Callback<List<Departments>?> {
override fun onResponse(
call: Call<List<Departments>?>,
response: Response<List<Departments>?>
) {
departmentList.postValue(response.body())
}
override fun onFailure(call: Call<List<Departments>?>, t: Throwable) {
errorMessage.postValue(t.message)
}
})
}
}
ProgramFragment.kt
@AndroidEntryPoint
class ProgramFragment : Fragment() {
lateinit var tv_data: TextView
lateinit var pg_recyclerview: RecyclerView
@Inject
lateinit var viewModelFactory: MyViewModelFactory
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_program, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
pg_recyclerview=view.findViewById(R.id.pg_recyclerview)
// this creates a vertical layout Manager
pg_recyclerview.layoutManager = LinearLayoutManager(requireContext())
//creates an adapter
val adapter= CampdataAdapter(listOf())
pg_recyclerview.adapter=adapter
val viewModel=ViewModelProviders.of(this,viewModelFactory).get(campDataViewModel::class.java)
viewModel.programList.observe(this, Observer {
when(it.status)
Log.d(TAG, "onCreate: $it")
adapter.Programs=it //it => all items in the list
adapter.notifyDataSetChanged()
})
viewModel.errorMessage.observe(this, Observer {
})
viewModel.getProgramData()
}
}
Repository.kt
class CampDataRepository (private val campInterface: CampInterface) {
fun getAllPrograms() =campInterface.getPrograms()
fun getAllDepartments() =campInterface.getDepartments()
}
Results.kt
//for state
class Result<out T>(val status: Status, val data: T?, message: String?) {
companion object {
fun <T> success(data: T?): Result<T> {
return Result(Status.SUCCESS, data, null)
}
fun <T> loading(message: String?): Result<T> {
return Result(Status.LOADING, null, message)
}
fun <T> error(message: String?): Result<T> {
return Result(Status.ERROR, null, message)
}
}
}
enum class Status {
SUCCESS,
LOADING,
ERROR
}
fragmet_program.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
tools:context=".ui.ProgramFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="@ id/pg_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="6dp"
>
</androidx.recyclerview.widget.RecyclerView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@ id/bottomNavigationView"
android:layout_width="match_parent"
android:layout_height="65dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/bottom_nav_menu"/>
<ProgressBar
android:id="@ id/progressBar"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toTopOf="@ id/bottomNavigationView"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="@ id/pg_recyclerview"
tools:visibility="visible"
android:visibility="gone"/>
</androidx.constraintlayout.widget.ConstraintLayout>
program adapter.kt
class CampdataAdapter ( var Programs:List<Programs>) :RecyclerView.Adapter<CampdataAdapter.Campdataholder>() {
//viewholder class
inner class Campdataholder(itemview : View) : RecyclerView.ViewHolder(itemview){
val tvprogramname =itemview.findViewById<TextView>(R.id.tv_programname)
var tvcode =itemview.findViewById<TextView>(R.id.tv_code)
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): Campdataholder{
//layout to inflate to the recycler view
val view = LayoutInflater.from(parent.context).inflate(R.layout.program_item,parent,false)
return Campdataholder(view)
}
override fun onBindViewHolder(holder: Campdataholder, position: Int) {
//set values or listeners for the views
var currentprogram=Programs[position]
holder.tvprogramname.text=currentprogram.Name
holder.tvcode.text=currentprogram.Code
}
override fun getItemCount(): Int {
return Programs.size
}
}
CodePudding user response:
One option is to add a new variable in ViewModel val loading = MutableLiveData<Boolean>()
and then observe it in view. For your example
ViewModel
val loading = MutableLiveData<Boolean>()
fun getProgramData() {
loading.postValue(true)
val response=campDataRepository.getAllPrograms()
response.enqueue(object : Callback<List<Programs>?> {
override fun onResponse(
call: Call<List<Programs>?>,
response: Response<List<Programs>?>
) {
programList.postValue(response.body())
loading.postValue(false)
}
override fun onFailure(call: Call<List<Programs>?>, t: Throwable) {
errorMessage.postValue(t.message)
loading.postValue(false)
}
})
}
Fragment
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
viewModel.loading.observe(this, Observer {
when(it) {
true -> progressBar.visibility = View.Visible
false -> progressBar.visibility = View.Gone
})
}
CodePudding user response:
Change your viewModel like this
val result = MutableLiveData<Result>()
val departmentList = MutableLiveData<List<Departments>>()
val errorMessage = MutableLiveData<String>()
fun getProgramData() {
result.postValue(Result(Status.LOADING, null, "your message"))
val response=campDataRepository.getAllPrograms()
response.enqueue(object : Callback<List<Programs>?> {
override fun onResponse(
call: Call<List<Programs>?>,
response: Response<List<Programs>?>
) {
result.postValue(Result(Status.SUCCESS, response.body(), null))
}
override fun onFailure(call: Call<List<Programs>?>, t: Throwable) {
result.postValue(Result(Status.ERROR, response.body(), null))
}
})
}
Then In Fragment
viewModel.result.observe(this, Observer {
when(result.status){
Status.SUCCESS -> {
progressBar.visibility = View.GONE
adapter.Programs=it.data //it => all items in the list
adapter.notifyDataSetChanged()
}
Status.ERROR -> {
progressBar.visibility = View.GONE
//show the error message
}
Status.LOADING -> {
progressBar.visibility = View.VISIBLE
}
}
})