Home > Back-end >  How to use setOnClickLisenter in Android viewModels?
How to use setOnClickLisenter in Android viewModels?

Time:10-14

RestActivity

package com.example.internet_ex

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.lifecycle.*
import kotlinx.coroutines.launch
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory
import retrofit2.http.GET
import retrofit2.http.Path
import java.lang.StringBuilder

data class Owner(val login: String)
data class Repo(val name: String, val owner: Owner, val url: String)
data class Contributor(val login: String, val contributions: Int)

interface RestApi {
    @GET("users/{user}/repos")
    suspend fun listRepos(@Path("user") user: String): List<Repo>

    @GET("/repos/{owner}/{repo}/contributors")
    suspend fun contributors(
        @Path("owner") owner: String,
        @Path("repo") repo: String
    ): List<Contributor>
}

class MyViewModel : ViewModel() {
    private val baseURL = "https://api.github.com/"
    private lateinit var api: RestApi
    val userName = MutableLiveData<String>()

    val response = MutableLiveData<String>()


    init {
        retrofitInit()
        refreshData()
    }

    fun refreshData() {
        viewModelScope.launch {
            try {
                val repos = api.listRepos(userName.toString())
                response.value = StringBuilder().apply {
                    repos.forEach {
                        append(it.name)
                        append(" - ")
                        append(it.owner.login)
                        append("\n")
                    }
                }.toString()
            } catch (e: Exception) {
                response.value = "Failed to connect to the server"
            }
        }
    }

    private fun retrofitInit() {
        val retrofit = Retrofit.Builder()
            .baseUrl(baseURL)
            .addConverterFactory(MoshiConverterFactory.create())

            .build()

        api = retrofit.create(RestApi::class.java)
    }
}


class RestActivity : AppCompatActivity() {
    private lateinit var myViewModel: MyViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_rest)

        myViewModel = ViewModelProvider(this).get(MyViewModel::class.java)
//        problem
        myViewModel.userName.observe(this) {
            findViewById<Button>(R.id.queryBtn).setOnClickListener {
                myViewModel.userName.value = findViewById<Button>(R.id.nameText).toString()
                myViewModel.refreshData()
            }
        }
        myViewModel.response.observe(this) {
            findViewById<TextView>(R.id.textResponse).text = it
            findViewById<Button>(R.id.queryBtn).setOnClickListener {
            }
        }
    }
}

activity_rest

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".RestActivity">

    <TextView
        android:id="@ id/textResponse"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginStart="8dp"
        android:layout_marginEnd="8dp"
        android:text="TextView"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@ id/queryBtn" />

    <Button
        android:id="@ id/queryBtn"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Query"
        app:layout_constraintStart_toEndOf="@ id/nameText"
        app:layout_constraintTop_toTopOf="parent" />

    <EditText
        android:id="@ id/nameText"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:ems="10"
        android:inputType="textPersonName"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
**activity_rest.xml**

I made a place where I commented that it was a problem because I wanted to change the userName in the ViewModel when I pressed queryBtn, but it didn't work. I want to change the LiveData (userName) in the ViewModel using the setOnClickLisenter command, but I can't figure it out. And I would appreciate it if you could let me know what to study additionally.

CodePudding user response:

Your OnClickListener needs to be set outside of the observer. At least from what I can tell you don't need to observe userName as the queryBtn is used to activate a response, and NOT the fact that userName was changed.

But you do want to observe the response as it is changed in the ViewModel, and needs to be displayed in textResponse.

The code below is NOT checked for correctness I just copied what you had and removed the unnecessary bits.

    findViewById<Button>(R.id.queryBtn).setOnClickListener {
          myViewModel.userName.value = findViewById<EditText>(R.id.nameText).getText().toString()
          myViewModel.refreshData()
    }
    myViewModel.response.observe(this) {
          findViewById<TextView>(R.id.textResponse).text = it
    }

CodePudding user response:

Move this outside observer block

findViewById<Button>(R.id.queryBtn).setOnClickListener { 
              myViewModel.userName.value = findViewById<EditText>(R.id.nameText).getText().toString()
}

Inside observer block, when user String is updated, call refresh data

myViewModel.userName.observe(this) {
      myViewModel.refreshData()
  }

Remove onClickListener from response observer block.

  • Related