效果:
实体类:
package com.aruba.flowapplyapplication.model
data class Article(val id: Int, val text: String)
Api:
package com.aruba.flowapplyapplication.net
import com.aruba.flowapplyapplication.model.Article
import retrofit2.http.GET
import retrofit2.http.Query
/**
* Created by aruba on 2021/9/21.
*/
interface Api {
@GET("article")
suspend fun searchArticles(
@Query("key") key: String
): List<Article>
}
Retrofit的工具类:
package com.aruba.flowapplyapplication.net
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
/**
* Created by aruba on 2021/9/21.
*/
object RetrofitClient {
private val instance: Retrofit by lazy {
Retrofit.Builder()
.baseUrl("http://192.168.0.118:8080/kotlinstudyserver/")
.client(OkHttpClient.Builder().build())
.addConverterFactory(GsonConverterFactory.create())
.build()
}
fun getApi(): Api {
return instance.create(Api::class.java)
}
}
利用LiveData进行后续的双向绑定
package com.aruba.flowapplyapplication.viewmodel
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.aruba.flowapplyapplication.model.Article
import com.aruba.flowapplyapplication.net.RetrofitClient
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.launch
/**
* Created by aruba on 2021/9/21.
*/
class ArticleViewModel : ViewModel() {
var searchText: MutableLiveData<String> = MutableLiveData()
var articleList = MutableLiveData<List<Article>>()
fun getArticle() {
if (searchText.value == null) return
viewModelScope.launch {
flow {
emit(RetrofitClient.getApi().searchArticles(searchText.value!!))
}.flowOn(Dispatchers.IO).catch { e ->
e.printStackTrace()
}.collect {
articleList.value = it
}
}
}
}
fragment的布局也比较简单,一个EditText和RecyclerView
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".ArticleFragment">
<androidx.appcompat.widget.AppCompatEditText
android:id="@+id/appCompatEditText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:text="@={articleViewModel.searchText}"
android:textSize="24sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/recyclerview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="10dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/appCompatEditText">
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
<data>
<variable
name="articleViewModel"
type="com.aruba.flowapplyapplication.viewmodel.ArticleViewModel" />
</data>
</layout>
package com.aruba.flowapplyapplication
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import com.aruba.flowapplyapplication.adapter.ArticleAdapter
import com.aruba.flowapplyapplication.databinding.FragmentArticleBinding
import com.aruba.flowapplyapplication.viewmodel.ArticleViewModel
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.launch
class ArticleFragment : Fragment() {
private val articleViewModel by lazy { ArticleViewModel() }
private val articleAdapter by lazy { ArticleAdapter() }
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val fragmentArticleBinding = DataBindingUtil.inflate<FragmentArticleBinding>(
inflater,
R.layout.fragment_article,
container,
false
)
//绑定viewmodel
fragmentArticleBinding.articleViewModel = articleViewModel
//配置recyclerview
fragmentArticleBinding.recyclerview.adapter = articleAdapter
fragmentArticleBinding.recyclerview.layoutManager = LinearLayoutManager(requireContext())
//设置LiveData
fragmentArticleBinding.lifecycleOwner = viewLifecycleOwner
//对edittext文本进行监听
articleViewModel.searchText.observe(viewLifecycleOwner) {
articleViewModel.getArticle()
}
//对服务器返回list的变化进行监听
articleViewModel.articleList.observe(viewLifecycleOwner) {
articleAdapter.setData(it)
}
return fragmentArticleBinding.root
}
}