【问题标题】:How to use setOnClickLisenter in Android viewModels?如何在 Android viewModel 中使用 setOnClickListener?
【发布时间】:2021-12-02 10:57:44
【问题描述】:

休息活动

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**

我做了一个地方,我评论说这是一个问题,因为我想在按下queryBtn 时更改ViewModel 中的userName,但它没有用。我想使用setOnClickLisenter 命令更改ViewModel 中的LiveData (userName),但我想不通。如果您能告诉我要另外学习什么,我将不胜感激。

【问题讨论】:

    标签: java android kotlin mvvm viewmodel


    【解决方案1】:

    您的OnClickListener 需要设置在observer 之外。 至少据我所知,您不需要observe userName,因为queryBtn 用于激活response,并且不是userName 已更改的事实.

    但你确实想observeresponse,因为它在ViewModel 中被更改,并且需要在textResponse 中显示。

    下面的代码检查正确性我只是复制了你所拥有的并删除了不必要的位。

        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
        }
    

    【讨论】:

    • 感谢您的回答。但是,如果你按下 queryBtn,程序就会结束。
    • 我再次复制了您的代码,您还有另一个错误 nameText is not a Button it an EditText。如果您想要来自EditText 的文本,请致电getText().toString(),我已经更新了我的答案。
    • 我按照你的修改改了,但是这次按钮不起作用。
    【解决方案2】:

    移动这个外部观察者块

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

    观察者块内部,当用户字符串更新时,调用刷新数据

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

    response 观察者块中移除 onClickListener

    【讨论】:

      猜你喜欢
      • 2017-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多