#android #listview #retrofit #android-jetpack-compose
Вопрос:
Я создал код Kotlin для синтаксического анализа API с доработкой в представлении списка/в виде сетки/в представлении переработчика, я хотел знать, как я могу сделать то же самое с помощью jetpack compose? Я использовал retrofit для анализа ответов 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 amp;amp; 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 для представления списка, представления сетки, представления переработчика. Спасибо.
Комментарии:
1. ознакомьтесь с информацией о ленивых списках в разделе Составление
2. Я видел некоторые демонстрации ленивых списков в Compose, но не смог обновить их в соответствии со своими потребностями.
3. Покажите, какой код компоновки вы пробовали, а что работает не так, как вы ожидаете. ознакомьтесь также с моделями представления compose, там вы можете выполнять обработку данных
4. Сэр, пожалуйста, проверьте, что я обновил функцию LazyRowItemsDemo, которую я хочу обновить в виде списка/в виде сетки/в виде переработчика с помощью arraylist, я не уверен, как я могу обновить ее с помощью вызова API и динамически синхронизировать с адаптерами.
Ответ №1:
Это более общий пример, без модернизации. Вы можете реализовать извлечение данных внутри моего getTestData
метода.
Для начала, чтобы понять основные принципы работы с Compose, я предлагаю вам изучить учебные пособия по составлению.
Compose использует модели представлений для выполнения сложных манипуляций с данными. Я буду использовать базовую версию, но вы также можете проверить Hilt на более сложную архитектуру.
Для того чтобы изменение состояния объекта привело к перекомпозиции, вы можете использовать:
mutableStateObject
— Это специально созданный контейнер для compose, который обновит представление, если значение изменилось- вы также можете использовать
LiveData
иFlow
, они оба могут быть приведены к mutableStateObject.
Обратите внимание, что mutableStateObject
это не предупредит вас об изменениях в полях объекта контейнера, если вы передадите там сложный класс. Он уведомит вас только о том, когда само значение изменится, поэтому рекомендуется использовать его только для простых типов.
Вы также можете использовать mutableStateListOf
для хранения коллекций. В моем примере вы увидите и то, и другое: с mutableStateListOf
ним удобно добавлять/удалять объекты в коллекцию, в то время mutableStateObject
как с List
лежащими внутри проще полностью заменить новыми объектами.
Внутри составных функций вам нужно обернуть объекты изменяемого состояния remember
, чтобы предотвратить их повторную инициализацию в каждой композиции, а внутри вашей модели представления вам не нужно этого делать, потому что она в любом случае не будет повторно инициализирована.
SwipeRefresh
не является частью compose, это библиотека, созданная также сопровождающими compose. Чтобы установить его, следуйте этим инструкциям.
Я использую здесь две колонки только для того , чтобы показать разницу между 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")
}
}
}
}
}
Результат:
Комментарии:
1. спасибо за ваш комментарий, сэр, но я хочу более обобщенное решение с использованием вызова API!
2. @Ramanjeet, почему бы тебе не скопировать свой собственный код вызова API вместо моего
getTestData
?3. вот что я хотел знать, как я могу интегрировать свой код kotlin с помощью модифицированных API в jetpack compose… Должен ли я использовать тот же код без каких-либо изменений??
4. @Ramanjeet в принципе да. Я показал вам всю часть пользовательского интерфейса Jetpack Compose, если вы знаете, как работает модернизация, вам не составит труда вставить ее.