如何在 jetpack compose 中使用改造 API 创建列表视图/网格视图/回收器视图
Posted
技术标签:
【中文标题】如何在 jetpack compose 中使用改造 API 创建列表视图/网格视图/回收器视图【英文标题】:How to create list view/grid view/recycler view with retrofit API in jetpack compose 【发布时间】:2021-11-02 05:41:44 【问题描述】:我已经创建了 Kotlin 代码,用于在列表视图/网格视图/回收器视图中通过改造来解析 API,我想知道如何使用 jetpack compose 来做同样的事情?我使用改造来使用不同的 ViewGroup 解析 GET API 响应。视图绑定用于与此屏幕上的视图进行交互。
代码
import android.annotation.SuppressLint
import android.app.AlertDialog
import android.app.ProgressDialog
import android.content.ActivityNotFoundException
import android.content.DialogInterface
import android.content.Intent
import android.content.res.Configuration
import android.os.Bundle
import android.util.Log
import android.view.*
import android.view.inputmethod.EditorInfo
import android.widget.*
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import okhttp3.ResponseBody
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import retrofit.Retrofit2
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import retrofit2.Retrofit
import retrofit2.converter.gson.GsonConverterFactory
import supports.*
import viewmodel.SIViewModel
import java.io.IOException
import java.net.SocketTimeoutException
import java.util.*
class TestIndex : AppCompatActivity()
var adapter: Adapter1? = null
var dialog: AlertDialog? = null
var builder: AlertDialog.Builder? = null
private val viewModel: SIViewModel? by viewModels()
var test_arr = ArrayList<TestModel>()
var binding: TestGridBinding? = null
@SuppressLint("CommitPrefEdits", "ClickableViewAccessibility", "SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
binding = DataBindingUtil.setContentView(this, R.layout.test_grid)
setSupportActionBar(binding?.view?.toolbarr)
supportActionBar!!.elevation = 0f
viewModel
adapter = Adapter1(this@TestIndex, R.layout.row, test_arr)
//binding ViewModel retrofit API with activity, here ID1 and ID2 coming from the previous screen.
viewModel!!.getList(this@TestIndex , ID1!!, ID2!!)
binding?.gvTest?.adapter = adapter
binding?.swipeRefreshLayout?.setOnRefreshListener
binding?.swipeRefreshLayout?.isRefreshing = true
if (ID1 != null && ID2 != null)
// getting same server response on swipe refresh widget
getdata(ID1!!, ID2!!)
else
builder = AlertDialog.Builder(MyApplication.instance)
builder!!.setCancelable(false)
builder!!.setTitle("Alert")
builder!!.setNegativeButton("Cancel") dialog: DialogInterface, which: Int ->
dialog.dismiss()
finish()
builder!!.setPositiveButton("OK") dialog: DialogInterface, which: Int -> dialog.dismiss()
dialog = builder!!.create()
dialog?.show()
subscribeObservers()
//this is checked on the dev portal but I don't know I could I use it //dynamically with adapters and ArrayList.
@Composable
fun LazyRowItemsDemo()
LazyRow
items((1..title_arr.size).toList())
Text(text = "Item $it")
private fun getdata(id1: String, id2: String)
val mProgressDialog = ProgressDialog(this@TestIndex)
mProgressDialog.isIndeterminate = true
mProgressDialog.setMessage(Keys.KEY_pre_msg)
if (!this.isFinishing)
mProgressDialog.show()
val retrofit = Retrofit.Builder()
.baseUrl(Keys.testURL)
.client(OkHttpClient().build())
.addConverterFactory(GsonConverterFactory.create())
.build()
val retrofitInterface = retrofit.create(
RetrofitInterface::class.java
)
val call = retrofitInterface.getTestdata(id1, id2)
call!!.enqueue(object : Callback<ResponseBody?>
override fun onResponse(call: Call<ResponseBody?>, response: Response<ResponseBody?>)
var remoteResponse: String? = null
if (response.code() == 200)
try
assert(response.body() != null)
remoteResponse = response.body()!!.string()
catch (e: Exception)
e.printStackTrace()
else
try
if (response.errorBody() != null)
remoteResponse = response.errorBody()!!.string()
catch (e: IOException)
e.printStackTrace()
if (remoteResponse != null)
//getting response fields and parsing list view or grid view/recycler view in different screens
adapter =
Adapter1(this@TestIndex, R.layout.row, test_arr)
binding!!.gvTest.adapter = adapter
adapter!!.notifyDataSetChanged()
override fun onFailure(call: Call<ResponseBody?>, t: Throwable)
Log.d(Keys.KEY_TAG, "onFailure: " + t.localizedMessage)
)
if (mProgressDialog.isShowing) mProgressDialog.dismiss()
//subscribed the Observers here from view model
private fun subscribeObservers()
viewModel!!.lifting.observe(this, TestModel: List<TestModel>? ->
adapter!!.updateTests(TestModel)
binding!!.swipeRefreshLayout.isRefreshing = false
请让我知道如何使用 jetpack compose 为列表视图、网格视图、回收器视图做同样的事情。谢谢。
【问题讨论】:
查看lazy lists in Compose 我在 Compose 中看到了一些惰性列表的演示,但无法根据我的需要进行更新。 显示您尝试了哪些撰写代码,哪些未按预期工作。也可以查看 compose view models,您可以在那里进行数据处理 先生,请检查我是否更新了 LazyRowItemsDemo 函数,我想用 arraylist 更新列表视图/网格视图/回收器视图,我不确定如何从 API 调用更新它并与适配器同步动态的。 【参考方案1】:这是一个更一般的例子,没有改造。您可以在我的 getTestData
方法中实现数据提取。
首先,为了了解使用 Compose 的基本原理,我建议你学习compose tutorials。
Compose 使用视图模型来执行复杂的数据操作。我将使用基本版本,但您也可以查看Hilt 了解更复杂的架构。
为了改变对象的状态以导致重组,您可以使用:
mutableStateObject
- 这是一个专门为 compose 创建的容器,如果值发生变化,它将更新视图
您也可以使用LiveData
和Flow
,它们都可以转换为mutableStateObject。
请注意,如果您在其中传递复杂类,mutableStateObject
不会提醒您容器对象字段的更改。它只会在值本身发生变化时通知您,因此建议仅将其用于简单类型。
您也可以使用mutableStateListOf
来存储收藏。在我的示例中,您将看到两者:mutableStateListOf
可以方便地向集合添加/删除对象,而 mutableStateObject
和 List
位于内部更容易完全替换为新对象。
在 Composable 函数内部,您需要使用 remember
包装可变状态对象,以防止在每个组合上重新初始化它们,而在您的视图模型内部,您不需要这样做,因为它在任何情况下都不会被重新初始化。
SwipeRefresh
不是 compose 的一部分,它也是 compose 维护者创建的库。要安装它,请关注this instructions。
我在这里使用两列只是为了显示mutableStateOf
和mutableStateListOf
之间的区别,您可以删除Row
和LazyColumn
之一
class ScreenViewModel : ViewModel()
var list by mutableStateOf(emptyList<String>())
var mutableList = mutableStateListOf<String>()
var isRefreshing by mutableStateOf(false)
init
refresh()
fun refresh()
isRefreshing = true
viewModelScope.launch
list = getTestData()
mutableList.addAll(0, list)
isRefreshing = false
suspend fun getTestData(): List<String>
// emulate network call
delay(1000)
return List(100)
Random.nextInt(100).toString()
@Composable
fun TestView()
val viewModel: ScreenViewModel = viewModel()
SwipeRefresh(
state = rememberSwipeRefreshState(viewModel.isRefreshing),
onRefresh =
viewModel.refresh()
,
)
Row
LazyColumn(
modifier = Modifier.weight(1f) // this needed inly for two columns case
)
itemsIndexed(viewModel.list) i, item ->
Text("$i $item")
LazyColumn(
modifier = Modifier.weight(1f) // this needed inly for two columns case
)
itemsIndexed(viewModel.mutableList) i, item ->
Text("$i $item")
结果:
【讨论】:
感谢您的评论先生,但我想要一个使用 API 调用的更通用的解决方案! @Ramanjeet 为什么不复制自己的 API 调用代码而不是我的getTestData
?
这就是我想知道的如何将我的 kotlin 代码使用改造 API 集成到 jetpack compose 中...我应该使用相同的代码而不做任何修改吗??
@Ramanjeet 基本上是的。我向你展示了 Jetpack Compose 的所有 UI 部分,如果你知道改造的工作原理,插入它应该没问题。以上是关于如何在 jetpack compose 中使用改造 API 创建列表视图/网格视图/回收器视图的主要内容,如果未能解决你的问题,请参考以下文章
如何在 jetpack compose 中使用 MotionLayout、MotionScene、ConstraintSet?
Jetpack Compose ScrollableTabRow 如何调整最小宽度
如何在 Android Jetpack Compose 中使用字符串资源?
如何将 CameraView 与 Jetpack Compose 一起使用?
如何在 Android Jetpack Compose 中结合使用 LazyColumn stickyHeader 和 Paging?