首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在不跳过框架的情况下更新UI?

如何在不跳过框架的情况下更新UI?
EN

Stack Overflow用户
提问于 2021-04-16 16:30:46
回答 1查看 384关注 0票数 1

所以我正在Kotlin开发android应用程序,不管我做了什么改变,我还是会得到这样的信息:

代码语言:javascript
复制
I/Choreographer: Skipped 59 frames!  The application may be doing too much work on its main thread.

我怎么才能摆脱它。我是说我只展示了九张照片..。下面是我的代码

模型:

代码语言:javascript
复制
data class Food (
    val id: String,
    val name: String,
    val price: String,
    @Json(name = "img_url") val imgSrcUrl: String,
    val type: String,
    val description: String,
    val average_rating: String,
    val number_of_raters: String,
    val special_price: String
)
data class FoodCategory(
    val id: String,
    val title: String,
    val foods: List<Food>
)

ViewModel:

代码语言:javascript
复制
enum class NetworkStatus {LOADING, DONE, FAILED}

enum class FontFamily (@FontRes val fontRes: Int) {
    POPPINS_BOLD(R.font.poppins_bold),
    POPPINS(R.font.poppins)
}

class FoodOverviewViewModel(private val foodRepository: FoodRepository): ViewModel() {

    private lateinit var foodProducts: List<Food>

    //This is the data that is gonna be exposed to the viewmodel
    //It will be submitted to a ListAdapter
    private val _foodCategory = MutableLiveData<List<FoodCategory>>()
    val foodCategory: LiveData<List<FoodCategory>>
        get() = _foodCategory
    
    //Used to display a progress bar for network status
    private val _status = MutableLiveData<NetworkStatus>()
    val status: LiveData<NetworkStatus>
        get() = _status

    init {
        getOverviewProducts()
    }

    private fun getOverviewProducts() {
        viewModelScope.launch(Dispatchers.Default) {
            _status.postValue(NetworkStatus.LOADING)
            try {
                getUpdatedFood()
                Log.i("getOverviewProducts","I am running on tread: $coroutineContext")
                _status.postValue(NetworkStatus.DONE)

            }catch (e: Exception) {
                _status.postValue(NetworkStatus.FAILED)
            }
        }
    }

    private suspend fun getUpdatedFood() {
        //withContext(Dispatchers.Default) {
            val limiter = 6 //Number of items I want to get from the server
            val foodCategory = arrayListOf<FoodCategory>()
            Log.i("getUpdatedFood","I am running on tread: $coroutineContext")

            val getRecommended = foodRepository.getRecommendedFood(limiter.toString())
            foodCategory += FoodCategory(id = 0.toString(), title = "Recommended for you", foods = getRecommended)
            
            val getSpecials = foodRepository.getSpecials(limiter.toString())
            foodCategory += FoodCategory(id = 1.toString(), title = "Specials", foods = getSpecials)

            _foodCategory.postValue(foodCategory)
        //}
    }
}

仓库:

代码语言:javascript
复制
class FoodRepository {

    suspend fun getRecommendedFood(limiter: String) = withContext(Dispatchers.IO) {
        Log.i("Resp-getRecommended","I am running on tread: $coroutineContext")
        return@withContext ProductApi.retrofitService.getRecommended(limiter)
    }
    suspend fun getSpecials(limiter: String) = withContext(Dispatchers.IO) {
        Log.i("Resp-getSpecials","I am running on tread: $coroutineContext")
        return@withContext ProductApi.retrofitService.getSpecials(limiter)
    }
}

BindingAdapters:

代码语言:javascript
复制
//Load image using Glide (in Food item recycleview)
@BindingAdapter("imageUrl")
fun bindImage(imgView: ImageView , imgUrl: String?) {
    imgUrl?.let {
        val imgUri = imgUrl.toUri().buildUpon().scheme("http").build()
        Glide.with(imgView.context)
            .load(imgUri)
            .apply(
                RequestOptions()
                .placeholder(R.drawable.loading_animation)
                .error(R.drawable.ic_broken_image))
            .into(imgView)
    }
}

//set raters count (in Food item recycleview)
@BindingAdapter("ratersCount")
fun bindText(txtView: TextView, number_of_raters: String?) {
    number_of_raters?.let {
        val ratersCount = "(${number_of_raters})"
        txtView.text = ratersCount
    }
}

//update the progressbar visibilty (in outer-parent recycleview) 
@BindingAdapter("updateStatus")
fun ProgressBar.updateStatus(status: NetworkStatus?) {
    visibility = when (status) {
        NetworkStatus.LOADING -> View.VISIBLE
        NetworkStatus.DONE -> View.GONE
        else -> View.GONE
    }
}

//Hide or view an imageview based in the network Status. When network Error, an error image
//will show (in outer-parent recycleview)
@BindingAdapter("setNoInternet")
fun ImageView.setNoInternet(status: NetworkStatus?) {
    when(status) {
        NetworkStatus.LOADING -> {
            visibility = View.GONE
        }
        NetworkStatus.DONE -> {
            visibility = View.GONE
        }
        NetworkStatus.FAILED -> {
            visibility = View.VISIBLE
            setImageResource(R.drawable.ic_connection_error)
        }
    }
}

//Submit the list of FoodCatergory item to the outer-parent recycleview
@BindingAdapter("listData")
fun bindRecyclerView(recyclerView: RecyclerView, data: List<FoodCategory>?) {
    (recyclerView.adapter as FoodCategoryAdapter).submitList(data)
}

//Submit list the the Food item recyclew view (child recycleView)
@BindingAdapter("setProducts")
fun RecyclerView.setProducts(foods: List<Food>?) {
    if (foods != null) {
        val foodAdapter = FoodItemAdapter()
        foodAdapter.submitList(foods)

        adapter = foodAdapter
    }
}

我有一个食品回收视图和一个FoodCategory循环库。如果我在ViewModel: getUpdatedFood()中注释掉getUpdatedFood,则不会收到消息。但是,当我将列表提交给外部循环视图(持有视图池的)时,我就得到了这个答案。请帮帮忙。我被困在上面一段时间了,试着处理掉那条信息。

谢谢。。

下面的更新的是适配器及其视图持有者

FoodItem布局

代码语言:javascript
复制
<layout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto">
    <data>

        <import type="android.view.View"/>
        <variable
                name="foodItem"
                type="com.example.e_commerceapp.models.Food"/>
        <variable
                name="font"
                type="com.example.e_commerceapp.products.overview.FontFamily"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/child_item_main_layout"
            android:background="@drawable/search_background"
            android:layout_marginTop="10dp"
            android:layout_marginStart="10dp"
            android:layout_marginBottom="10dp"
            android:layout_width="150dp"
            android:layout_height="250dp">

        <ImageView
                android:layout_width="120dp"
                android:layout_marginStart="10dp"
                android:layout_marginEnd="10dp"
                android:id="@+id/burger_image"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_height="160dp"
                />
<!--        app:imageUrl="@{foodItem.imgSrcUrl}"-->

        <TextView
                android:layout_width="match_parent"
                android:layout_height="34dp"
                android:layout_marginStart="5dp"
                android:id="@+id/burger_title"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginEnd="5dp"
                android:singleLine="true"
                android:textColor="#B4000000"
                app:layout_constraintTop_toBottomOf="@id/burger_image"
                android:text="@{foodItem.name}"
                android:textSize="12sp"
                android:fontFamily="@font/poppins"/>
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="35dp"
                app:layout_constraintTop_toBottomOf="@id/burger_title"
                android:layout_marginEnd="5dp"
                android:gravity="center"
                android:id="@+id/burger_price"
                android:layout_marginStart="5dp"
                app:layout_constraintStart_toEndOf="@id/special_price"
                android:textColor="#D0000000"/>

<!--                app:price="@{foodItem.price}"-->
<!--                app:specialPrice="@{foodItem.special_price}"-->
<!--                app:fontRes="@{foodItem.special ? font.POPPINS : font.POPPINS_BOLD}"-->


        <TextView
                android:layout_width="wrap_content"
                android:layout_height="35dp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@id/burger_title"
                android:layout_marginEnd="5dp"
                android:gravity="center_vertical"
                android:layout_marginStart="5dp"
                android:id="@+id/special_price"
                android:textColor="#D0000000"
                android:visibility="gone"
                android:textStyle="normal"
                android:fontFamily="@font/poppins_bold"/>
<!--        app:setSpecialPrice="@{foodItem.special_price}"-->


        <ImageView
                android:layout_width="15dp"
                android:layout_height="15dp"
                app:layout_constraintTop_toBottomOf="@id/burger_price"
                android:src="@drawable/ic_baseline_star_24"
                android:visibility="@{foodItem.hasRating ? View.GONE : View.VISIBLE}"
                android:id="@+id/rating_star"
                app:layout_constraintStart_toStartOf="parent"
                android:layout_marginStart="5dp"
                android:layout_marginBottom="10dp"
                app:layout_constraintBottom_toBottomOf="parent"/>
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="15dp"
                android:layout_marginStart="5dp"
                android:gravity="center"
                android:textSize="12sp"
                android:visibility="@{foodItem.hasRating ? View.GONE : View.VISIBLE}"
                android:id="@+id/rating_count"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintTop_toBottomOf="@id/burger_price"
                android:text="@{foodItem.average_rating}"
                android:layout_marginBottom="10dp"
                app:layout_constraintStart_toEndOf="@id/rating_star"/>
        <TextView
                android:layout_width="wrap_content"
                android:layout_height="15dp"
                android:id="@+id/number_of_raters"
                android:textSize="12sp"
                android:visibility="@{foodItem.hasRating ? View.GONE : View.VISIBLE}"
                android:layout_marginStart="2dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toEndOf="@id/rating_count"
                app:ratersCount="@{foodItem.number_of_raters}"
                android:layout_marginBottom="10dp"
                app:layout_constraintTop_toBottomOf="@id/burger_price"/>

        <ImageView android:layout_width="20dp"
                   android:layout_height="20dp"
                   android:layout_marginEnd="10dp"
                   android:layout_marginTop="10dp"
                   app:layout_constraintEnd_toEndOf="parent"
                   app:layout_constraintTop_toTopOf="parent"/>


    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

FoodItem适配器

代码语言:javascript
复制
class FoodItemAdapter: ListAdapter<Food ,
        FoodItemAdapter.ItemFoodViewHolder>(DiffCallback) {

    override fun onCreateViewHolder(parent: ViewGroup , viewType: Int): ItemFoodViewHolder {
        return ItemFoodViewHolder(
            FoodItemBinding.inflate(LayoutInflater.from(parent.context),
            parent, false))
    }

    override fun onBindViewHolder(holder: ItemFoodViewHolder , position: Int) {
        val currentFood = getItem(position)
        holder.bind(currentFood)
    }

    class ItemFoodViewHolder(private var binding: FoodItemBinding): RecyclerView.ViewHolder(binding.root) {
        fun bind(food: Food) {
            binding.foodItem = food
            binding.executePendingBindings()
        }
    }

    object DiffCallback: DiffUtil.ItemCallback<Food>() {
        override fun areItemsTheSame(oldItem: Food , newItem: Food): Boolean {
            return oldItem === newItem
        }

        override fun areContentsTheSame(oldItem: Food , newItem: Food): Boolean {
            return oldItem.id == newItem.id
        }
    }
}

FoodCategory布局

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools">
    <data>
        <variable
                name="foodCategory"
                type="com.example.e_commerceapp.models.FoodCategory"/>
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
            android:background="#fff"
            android:layout_marginTop="5dp"
            android:layout_marginBottom="5dp"
            android:layout_width="match_parent"
            android:layout_height="wrap_content">

        <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="16dp"
                android:id="@+id/category_title"
                android:layout_marginTop="16dp"
                android:text="@{foodCategory.title}"
                android:textColor="#2B2A2A"
                android:fontFamily="@font/poppins_bold"
                android:textSize="16sp"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"/>

        <androidx.recyclerview.widget.RecyclerView
                android:id="@+id/nestedRecyclerView"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginTop="4dp"
                app:setProducts="@{foodCategory.foods}"
                android:orientation="horizontal"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/category_title"
                tools:itemCount="4"
                tools:listitem="@layout/food_item"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>

FoodCategory适配器

代码语言:javascript
复制
class FoodCategoryAdapter: ListAdapter<FoodCategory,
        FoodCategoryAdapter.CategoryFoodViewHolder>(Companion) {

    private val viewPool = RecyclerView.RecycledViewPool()

    override fun onCreateViewHolder(parent: ViewGroup , viewType: Int): CategoryFoodViewHolder {
        return CategoryFoodViewHolder(FoodCategoryBinding.inflate(LayoutInflater.from(parent.context),
            parent, false))
    }

    override fun onBindViewHolder(holder: CategoryFoodViewHolder , position: Int) {
        val currentFoodCategory = getItem(position)
        holder.bind(currentFoodCategory)
    }


    inner class CategoryFoodViewHolder(private var binding: FoodCategoryBinding): RecyclerView.ViewHolder(binding.root) {
        fun bind(currentFoodCategory: FoodCategory?) {
            binding.foodCategory = currentFoodCategory
            binding.nestedRecyclerView.setRecycledViewPool(viewPool)
            binding.executePendingBindings()
        }
    }

    companion object: DiffUtil.ItemCallback<FoodCategory>() {
        override fun areItemsTheSame(oldItem: FoodCategory , newItem: FoodCategory): Boolean {
            return oldItem === newItem
        }

        override fun areContentsTheSame(oldItem: FoodCategory, newItem: FoodCategory): Boolean {
            return oldItem.id == newItem.id
        }
    }
}

父recycleView

代码语言:javascript
复制
<?xml version="1.0" encoding="utf-8"?>

<layout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        tools:context=".products.overview.FoodOverviewFragment">
    <data>
        <variable
                name="foodOverview"
                type="com.example.e_commerceapp.products.overview.FoodOverviewViewModel"/>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
            android:background="@color/grey"
            android:layout_width="match_parent"
            android:layout_height="match_parent">

        <RelativeLayout
                android:layout_width="match_parent"
                android:id="@+id/relative_layout"
                android:layout_height="105dp"
                android:elevation="8dp"
                android:layout_marginBottom="5dp"
                android:background="#fff"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent"
                app:layout_constraintEnd_toEndOf="parent">

            <ImageView
                    android:layout_width="200dp"
                    android:layout_marginTop="10dp"
                    android:layout_height="35dp"
                    android:id="@+id/logo_and_name"
                    android:src="@drawable/compony_logo_and_name"
                    android:layout_alignParentStart="true"/>
            <ImageView
                    android:layout_width="wrap_content"
                    android:layout_height="35dp"
                    android:layout_marginTop="10dp"
                    android:id="@+id/notifications"
                    android:src="@drawable/ic_baseline_notifications_24"
                    android:layout_alignParentEnd="true"
                    android:paddingEnd="20dp"
                    android:paddingStart="20dp"/>
            <TextView
                    android:layout_width="match_parent"
                    android:id="@+id/search"
                    android:layout_marginTop="10dp"
                    android:layout_marginStart="20dp"
                    android:layout_marginEnd="20dp"
                    android:background="@drawable/search_background"
                    android:layout_below="@id/logo_and_name"
                    android:gravity="center_vertical"
                    android:layout_height="match_parent"
                    android:layout_marginBottom="10dp"
                    android:paddingEnd="10dp"
                    android:paddingStart="10dp"
                    android:text="@string/search_text"
                    tools:ignore="RtlSymmetry"
                    app:drawableEndCompat="@drawable/ic_baseline_search_24"/>
        </RelativeLayout>

        <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:updateStatus="@{foodOverview.status}"
                app:layout_constraintTop_toBottomOf="@id/relative_layout"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:id="@+id/progressbar"/>
        <ImageView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                app:layout_constraintTop_toBottomOf="@id/relative_layout"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                android:id="@+id/noInternetImage"/>

        <androidx.recyclerview.widget.RecyclerView
                android:layout_width="0dp"
                android:id="@+id/foodCategory"
                android:clipToPadding="false"
                tools:itemCount="4"
                tools:listitem="@layout/food_category"
                app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
                android:layout_height="0dp"
                app:listData="@{foodOverview.foodCategory}"
                app:layout_constraintTop_toBottomOf="@id/relative_layout"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintBottom_toBottomOf="parent"/>

    </androidx.constraintlayout.widget.ConstraintLayout>

</layout>
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-04-19 19:03:29

跳过的帧可能与您发布的代码无关:对我来说,这听起来像是RecyclerViews / Adapters的错误配置。但是,您需要发布这段代码,因为它更清晰。

然而,即使您发布的内容可能不是罪魁祸首,您仍然可以优化您拥有的协同代码:

代码语言:javascript
复制
class FoodOverviewViewModel(private val foodRepository: FoodRepository): ViewModel() {

    private lateinit var foodProducts: List<Food>

    private val _foodCategory = MutableLiveData<List<FoodCategory>>()
    val foodCategory: LiveData<List<FoodCategory>>
        get() = _foodCategory
    
    private val _status = MutableLiveData<NetworkStatus>()
    val status: LiveData<NetworkStatus>
        get() = _status

    init {
        getOverviewProducts()
    }

    private fun getOverviewProducts() {
        viewModelScope.launch { // <------- Don't apply a custom scope here
            _status.value = NetworkStatus.LOADING // <--- Don't call "postValue" here
            try {
                val food = getUpdatedFood() // <------ This is already using a background dispatcher
                _foodCategory.value = food // <------- Emit this value here
                _status.value = NetworkStatus.DONE
            } catch (e: Exception) {
                _status.value = NetworkStatus.FAILED
            }
        }
    }

    private suspend fun getUpdatedFood(): List<FoodCategory> { // <---- Return a value here
        val limiter = 6 //Number of items I want to get from the server
        val foodCategory = arrayListOf<FoodCategory>()
        Log.i("getUpdatedFood","I am running on tread: $coroutineContext")

        val getRecommended = foodRepository.getRecommendedFood(limiter.toString())
            foodCategory += FoodCategory(id = 0.toString(), title = "Recommended for you", foods = getRecommended)
            
        val getSpecials = foodRepository.getSpecials(limiter.toString())
        foodCategory += FoodCategory(id = 1.toString(), title = "Specials", foods = getSpecials)
        return foodCategories
    }
}

这里的要点是:

中主线程上的_foodCategory值。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67128974

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档