Android Kotlin Retrofit 与Flow。两个Flow用LiveData来进行分解
Posted 安果移不动
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android Kotlin Retrofit 与Flow。两个Flow用LiveData来进行分解相关的知识,希望对你有一定的参考价值。
这里用到了网络。。用的php构建的假数据
核心代码如下
<?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<List<Article>>
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<BindingViewHolder>()
private val data = ArrayList<Article>()
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<String> = 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
以上是关于Android Kotlin Retrofit 与Flow。两个Flow用LiveData来进行分解的主要内容,如果未能解决你的问题,请参考以下文章
Android - ViewModel、LiveData、Room 和 Retrofit 以及协程放在 kotlin 中
如何使用 Retrofit Android Kotlin 发布 [重复]
无法使用 Kotlin Retrofit 将数据从 Android 插入到 Mysql [重复]
Android Kotlin Retrofit + SimpleXMLConverter ElementList 解析不正确