Как создать представление списка/представление сетки/представление переработчика с помощью API дооснащения в jetpack compose

#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 на более сложную архитектуру.

Для того чтобы изменение состояния объекта привело к перекомпозиции, вы можете использовать:

  1. mutableStateObject — Это специально созданный контейнер для compose, который обновит представление, если значение изменилось
  2. вы также можете использовать 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, если вы знаете, как работает модернизация, вам не составит труда вставить ее.