
这里用到了网络。。用的php构建的假数据
核心代码如下
- // ---------------------------引入接口参数类(以用户实际路径为准)---------------------------------
- namespace App\Services\test;
-
- use App\Common\Services\BaseService;
- use App\Http\Controllers\ExpressController;
- use App\Services\express\ExpressService;
- use App\Services\utils\IpServices;
-
- class TestService extends BaseService
- {
- public function index($key): \Illuminate\Http\JsonResponse
- {
-
- $data = array();
- $dataSub = array();
- $dataSub['text'] = $key . "乱七八糟噢噢噢噢的数据";
- $dataSub['id'] = 1;
- $data[] = $dataSub;
-
- $dataSub['text'] = $key . "你说不用自作自受自己创造伤悲,写歌的人就应该有伤悲";
- $dataSub['id'] = 2;
- $data[] = $dataSub;
-
- $dataSub['text'] = $key . "去吗,配吗 这褴褛的披风";
- $dataSub['id'] = 3;
- $data[] = $dataSub;
-
-
- return $this->apiSuccess("1", $data);
-
- }
-
- }
最后返回json结果如下
- {
- "code": 20000,
- "message": "1",
- "data": [{
- "text": "123乱七八糟噢噢噢噢的数据",
- "id": 0
- }, {
- "text": "123你说不用自作自受自己创造伤悲,写歌的人就应该有伤悲",
- "id": 1
- }, {
- "text": "123去吗,配吗 这褴褛的披风",
- "id": 1
- }]
- }
好 正题开始咯

- package com.example.android_flow_practice.net
-
- import com.example.android_flow_practice.model.Article
- import com.example.android_flow_practice.model.NetResponse
- import retrofit2.http.GET
- import retrofit2.http.Query
-
-
- interface ArticleApi {
-
- @GET("api/v1/open/test")
- suspend fun searchArticles(
- @Query("key") key: String
- ): NetResponse
>
- }
- package com.example.android_flow_practice.net
-
- import okhttp3.OkHttpClient
- import retrofit2.Retrofit
- import retrofit2.converter.gson.GsonConverterFactory
- import retrofit2.create
-
- object RetrofitClient {
- val url = "https://xxx.xxx.com/";
- private val instance: Retrofit by lazy {
- Retrofit.Builder().client(OkHttpClient.Builder().build()).baseUrl(url)
- .addConverterFactory(GsonConverterFactory.create()).build()
- }
-
-
- val articleApi: ArticleApi by lazy {
- instance.create(ArticleApi::class.java)
- }
- }
依然是马赛克的url。。多余的靠自己
准备adapter
- package com.example.android_flow_practice.adapter
-
- import android.content.Context
- import android.view.LayoutInflater
- import android.view.ViewGroup
- import androidx.recyclerview.widget.RecyclerView
- import com.example.android_flow_practice.databinding.ItemArticleBinding
- import com.example.android_flow_practice.databinding.ItemUserBinding
- import com.example.android_flow_practice.db.User
- import com.example.android_flow_practice.model.Article
-
- class ArticleAdapter(private val context: Context) : RecyclerView.Adapter
() { -
- private val data = ArrayList
() - fun setData(data: List<Article>) {
- this.data.clear()
- this.data.addAll(data);
- notifyDataSetChanged()
- }
-
- override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BindingViewHolder {
- val binding = ItemArticleBinding.inflate(LayoutInflater.from(context), parent, false)
- return BindingViewHolder(binding = binding)
- }
-
- override fun getItemCount(): Int {
- return data.size
- }
-
- override fun onBindViewHolder(holder: BindingViewHolder, position: Int) {
- val item = data[position]
- val binding = holder.binding as ItemArticleBinding
- binding.text.text = "${item.id}, ${item.text}"
-
- }
- }
对应的viewHolder
- package com.example.android_flow_practice.adapter
-
- import androidx.recyclerview.widget.RecyclerView
- import androidx.viewbinding.ViewBinding
-
- class BindingViewHolder(val binding: ViewBinding) : RecyclerView.ViewHolder(binding.root) {}
布局
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:orientation="vertical">
-
- <androidx.appcompat.widget.AppCompatTextView
- android:id="@+id/text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:gravity="center"
- android:paddingVertical="4dp"
- android:textSize="26sp" />
-
- </LinearLayout>
然后adapter是在Fragment当中的
Fragment布局
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout 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"
- android:orientation="vertical"
- tools:context=".fragment.UserFragment">
-
- <androidx.appcompat.widget.AppCompatEditText
- android:id="@+id/ed_search"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:hint="Input keyword for search"
- android:padding="8.dp"
-
- />
-
- <androidx.recyclerview.widget.RecyclerView
- android:id="@+id/rv"
- app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
-
- </LinearLayout>

布局完事以后代码
- package com.example.android_flow_practice.fragment
-
- import android.os.Bundle
- import android.text.Editable
- import android.text.TextWatcher
- import android.util.Log
- import androidx.fragment.app.Fragment
- import android.view.LayoutInflater
- import android.view.View
- import android.view.ViewGroup
- import android.widget.TextView
- import androidx.fragment.app.viewModels
- import androidx.lifecycle.lifecycleScope
- import com.example.android_flow_practice.R
- import com.example.android_flow_practice.adapter.ArticleAdapter
- import com.example.android_flow_practice.databinding.FragmentArticleBinding
- import com.example.android_flow_practice.databinding.FragmentDownloadBinding
- import com.example.android_flow_practice.viewmodel.ArticleViewModel
- import com.example.android_flow_practice.viewmodel.UserViewModel
- import kotlinx.coroutines.channels.awaitClose
- import kotlinx.coroutines.flow.Flow
- import kotlinx.coroutines.flow.callbackFlow
- import kotlinx.coroutines.flow.collect
-
-
- class ArticleFragment : Fragment() {
- private val TAG = "ArticleFragment"
- private val viewModel: ArticleViewModel by viewModels()
-
- private val mBinding: FragmentArticleBinding by lazy {
- FragmentArticleBinding.inflate(layoutInflater)
- }
-
- override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
- ): View? {
- // Inflate the layout for this fragment
- return mBinding.root
- }
-
-
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
- lifecycleScope.launchWhenCreated {
- mBinding.edSearch.textWatcherFlow().collect {
- Log.e(TAG, "onActivityCreated: ${it}")
- viewModel.searchArticles(it)
- }
- }
- context?.let {
- val adapter = ArticleAdapter(it)
- mBinding.rv.adapter = adapter
- viewModel.articles.observe(viewLifecycleOwner, { artices ->
- adapter.setData(artices)
- })
- }
-
-
- }
-
- //获取关键字
-
- fun TextView.textWatcherFlow(): Flow
= callbackFlow { - val textWatcher = object : TextWatcher {
- override fun beforeTextChanged(
- s: CharSequence?, start: Int, count: Int, after: Int
- ) {
- }
-
- override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
- }
-
- override fun afterTextChanged(s: Editable?) {
- trySend(s.toString()).isSuccess
-
- }
- }
- addTextChangedListener(textWatcher)
- awaitClose { removeTextChangedListener(textWatcher) }
- }
- }
核心代码存放与viewModel当中
- package com.example.android_flow_practice.viewmodel
-
- import android.app.Application
- import androidx.lifecycle.AndroidViewModel
- import androidx.lifecycle.MutableLiveData
- import androidx.lifecycle.viewModelScope
- import com.example.android_flow_practice.model.Article
- import com.example.android_flow_practice.net.RetrofitClient
- import kotlinx.coroutines.Dispatchers
- import kotlinx.coroutines.flow.*
- import kotlinx.coroutines.launch
- import okhttp3.Dispatcher
- class ArticleViewModel(app: Application) : AndroidViewModel(app) {
- val articles = MutableLiveData<List<Article>>()
- fun searchArticles(key: String) {
- viewModelScope.launch {
- flow {
- val list = RetrofitClient.articleApi.searchArticles(key)
- emit(list)
- }.flowOn(Dispatchers.IO).catch { e -> e.printStackTrace() }.collect {
- it.data.let {
- articles.setValue(it)
- }
- }
- }
- }
- }
这里简单拆析下这里

使用flow 监听
afterTextChanged 将文本变动后的数据返回过来。
又监听其关闭方法
awaitClose 对textWather进行解除监听也就是释放
这是其一
其二 将viewModel的搜索列表数据弄到了articles

然后再次对其进行监听 这样结构数据就不是collect{ collect{} }了
那我们试下这种错误的写法看看会怎么样
collect{ collect{} }
viewModel中复制修改
-
- fun searchArticles2(key: String) = flow {
- val list = RetrofitClient.articleApi.searchArticles(key)
- emit(list)
- }.flowOn(Dispatchers.IO).catch { e -> e.printStackTrace() }
fragment也有所改变
- override fun onActivityCreated(savedInstanceState: Bundle?) {
- super.onActivityCreated(savedInstanceState)
- lifecycleScope.launchWhenCreated {
- mBinding.edSearch.textWatcherFlow().collect {
- Log.e(TAG, "onActivityCreated: ${it}")
- viewModel.searchArticles2(it).collect{ dataList->
- context?.let {
- val adapter = ArticleAdapter(it)
- mBinding.rv.adapter = adapter
- adapter.setData(dataList.data)
- }
- }
- }
- }
这样做依然没有问题

但是并不推荐。
因为collect{ collect{} } 并不是流的设计思想。。
collect{ }
collect{} 这种事
你可以明显的感觉到 使用上述不推荐的写法
collect{ collect{} } 这种写法。速度完全跟不上
- collect{ }
-
- collect{}