API 请求仅调用一次且未在 recyclerview 中显示结果

API Request called only once and not showing result in recyclerview

我是 MVVM 的新手,我很乐意得到一些帮助。它是非常基本的项目,只是为了了解 MVVM 中的工作方式。

因此,一旦应用程序启动,它就会用 API 中的所有员工填充 recyclerView。 我有一个浮动操作按钮,当我按下它时,会打开一个带有编辑文本的警告对话框,当我输入一个数字时,我想根据他的 ID 从 API 中获取特定员工并更新 recyclerview所以它只会显示 1 名员工。

问题是:

我正在使用这个虚拟机 API - https://dummy.restapiexample.com/

这是员工模型:

data class Employee (
    @SerializedName("employee_name")
    val employeeName:String,

    @SerializedName("employee_salary")
    val employeeSalary: String,

    @SerializedName("employee_age")
    val employeeAge: Int,

    @SerializedName("id")
    val employeeID: Int

    )

data class EmployeesListResult(

    @SerializedName("data")
    val getEmployeesListResult : List<Employee>,

)

data class SingleEmployeeListResult(

    @SerializedName("data")
    val getSingleEmployeesListResult : Employee

    )

这是API请求对象:

object APIRequest {

    val baseUrl : String = "https://dummy.restapiexample.com/api/v1/"

    var retrofit: Retrofit = Retrofit.Builder()
        .baseUrl(baseUrl)
        .addConverterFactory(GsonConverterFactory.create())
        .build()

    val retrofitCallGetList : APICallRequest = retrofit.create(APICallRequest::class.java)


}

interface APICallRequest{

    @GET("employees")
    fun callEmployeeList() : Call<EmployeesListResult>

    @GET("employee/{id}")
    fun callSpecificEmployee(@Path(value = "id", encoded = false) key: Int, ): Call<SingleEmployeeListResult>

}

这是主存储库class:

class MainRepository {

    val mutableListLiveData = MutableLiveData<List<Employee>>()
    val mutableSingleLiveData = MutableLiveData<Employee>()

    fun getEmployeeListFromAPI(): MutableLiveData<List<Employee>> {

        val apiRequest: APICallRequest = APIRequest.retrofitCallGetList


        apiRequest.callEmployeeList().enqueue(object : Callback<EmployeesListResult?> {
            override fun onResponse(
                call: Call<EmployeesListResult?>,
                response: Response<EmployeesListResult?>
            ) {

                if (response.isSuccessful) {
                    mutableListLiveData.value = response.body()?.getEmployeesListResult
                    Log.e("onResponse", "Success!")
                    Log.e("Response:", "${response.body()}")
                }

            }

            override fun onFailure(call: Call<EmployeesListResult?>, t: Throwable) {
                Log.e("onFailure", "Failed getting list: ${t.message}")
            }
        })

        return mutableListLiveData

    }




    fun getSpecificEmployee(employeeID: Int): MutableLiveData<Employee> {

        val apiRequest: APICallRequest = APIRequest.retrofitCallGetList

        apiRequest.callSpecificEmployee(employeeID).enqueue(object : Callback<SingleEmployeeListResult?> {
            override fun onResponse(
                call: Call<SingleEmployeeListResult?>,
                response: Response<SingleEmployeeListResult?>
            ) {
                    if (response.isSuccessful) {
                        mutableSingleLiveData.value = response.body()?.getSingleEmployeesListResult
                        Log.e("Single onResponse", "Success!")
                        Log.e("Response:", "${response.body()}")
                    }
            }

            override fun onFailure(call: Call<SingleEmployeeListResult?>, t: Throwable) {
                Log.e("Single onResponse FAIL", "FAIL! ${t.message}")
            }
        })

        return mutableSingleLiveData
    }

这是 MainViewModel:

class MainViewModel : ViewModel() {

    private var employeeMutableData : MutableLiveData<List<Employee>>? = null
    private var specificEmployeeMutableData : MutableLiveData<Employee>? = null

    fun getEmployeeListFromRepo() : LiveData<List<Employee>>{

        if (employeeMutableData == null){
            employeeMutableData = MainRepository().getEmployeeListFromAPI()
        }

        return employeeMutableData as LiveData<List<Employee>>
    }



    fun getSpecificEmployee(employeeID : Int) : LiveData<Employee> {
        if (specificEmployeeMutableData == null){
            specificEmployeeMutableData = MainRepository().getSpecificEmployee(employeeID)
        }
        return specificEmployeeMutableData as LiveData<Employee>
    }


}

MainActivityclass:

class MainActivity : AppCompatActivity() {

    private val mainViewModel : MainViewModel by viewModels()

    private lateinit var recyclerView: RecyclerView

    private lateinit var mainAdapter: MainRecyclerViewAdapter

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

        initRecycler()

        val actionButton = findViewById<FloatingActionButton>(R.id.actionButton)


        actionButton.setOnClickListener(View.OnClickListener {
            searchEmployeeByIdDialog()
        })

        mainViewModel.getEmployeeListFromRepo().observe(this,object : Observer<List<Employee>> {
            override fun onChanged(theListOfEmployees: List<Employee>) {

             mainAdapter = MainRecyclerViewAdapter(theListOfEmployees)
             recyclerView.adapter = mainAdapter


            }
        })


    } // End of OnCreate

    private fun initRecycler() {
        recyclerView = findViewById<RecyclerView>(R.id.mainRecyclerView)
        recyclerView.setHasFixedSize(true)
        recyclerView.layoutManager = GridLayoutManager(this@MainActivity,2)

    }

    private fun searchEmployeeByIdDialog(){

        val editTextForDialog = EditText(this)
        editTextForDialog.maxLines = 1
        editTextForDialog.setPadding(10)
        editTextForDialog.inputType = InputType.TYPE_CLASS_NUMBER

        val alertDialog = AlertDialog.Builder(this)
        alertDialog.setTitle("Employee Search")
        alertDialog.setMessage("What employee ID do you want to look for ?")
        alertDialog.setView(editTextForDialog)
            .setPositiveButton("Search", DialogInterface.OnClickListener { dialogInterface: DialogInterface?, i: Int ->
              if (editTextForDialog.text.isNotEmpty()){

                  mainViewModel.getSpecificEmployee(editTextForDialog.text.toString().toInt()).observe(this,object : Observer<Employee?> {

                      override fun onChanged(t: Employee?) {
                          if (t != null) {
                              
                              val list = listOf(t)

                              mainAdapter.updateEmployeeList(list)

                          }

                      }
                  })



              }else{

                  Toast.makeText(this,"Please enter employee ID",Toast.LENGTH_SHORT).show()

              }

            })

            .setNegativeButton("Cancel", DialogInterface.OnClickListener { dialogInterface, i ->
                dialogInterface.dismiss()
            })
            .show()

    }

}

最后,MainRecyclerViewAdapter class:

class MainRecyclerViewAdapter(var employeeList: List<Employee>) : RecyclerView.Adapter<MainRecyclerViewAdapter.EmployeesHolder>() {


    inner class EmployeesHolder(var itemView : View) : RecyclerView.ViewHolder(itemView){

        fun bindData(employee : Employee){

            val nameTextView = itemView.findViewById<TextView>(R.id.nameTextView)
            val ageTextView = itemView.findViewById<TextView>(R.id.ageTextView)
            val salaryTextView = itemView.findViewById<TextView>(R.id.salaryTextView)

            nameTextView.text = employee.employeeName
            ageTextView.text = employee.employeeAge.toString()
            salaryTextView.text = employee.employeeSalary


        }

    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): EmployeesHolder {
        return EmployeesHolder(LayoutInflater.from(parent.context).inflate(R.layout.recyclerview_row,parent,false))
    }

    override fun onBindViewHolder(holder: EmployeesHolder, position: Int) {
        holder.bindData(employeeList[position])
    }

    override fun getItemCount(): Int {
        return employeeList.size
    }

    fun updateEmployeeList(newList: List<Employee>) {
        this.employeeList = newList
        notifyDataSetChanged()
    }


}

非常感谢!

在您的 MainViewModel 实现中,关于您如何实现 getSpecificEmployee(...) 方法的一些事情对我来说很突出。

目前的实现方式,第一次搜索特定员工时,specificEmployeeMutableData实时数据将为空,因此将调用相关的存储库方法。

但是对于您尝试获取特定员工的后续时间,specificEmployeeMutableData 将不再为空,这意味着它不会触发存储库中的 API 调用。

这就是为什么在您的日志中,似乎什么都没有发生...因为什么都没有发生。

一个快速补丁可以是删除空检查,并在每次需要获取特定员工时调用存储库。

fun getSpecificEmployee(employeeID : Int) : LiveData<Employee> {
    return MainRepository().getSpecificEmployee(employeeID) as LiveData<Employee>
}