首页 > 解决方案 > 如何掩盖android Studio中的加载时间延迟?

问题描述

我在 Android Studio 中制作了一个从网站导入数据的应用程序......当我打开应用程序时,要在其中导入数据的卡片视图是空的,并在一段时间后加载。我想知道是否有任何方法可以掩盖它,以便在加载它之前我的启动屏幕一直保持在那里。这是一个显示滞后的视频:

卡片视图加载时间延迟

编辑:这是电影适配器:

class MoviesAdapter(
    private var movies: MutableList<Movie>,
    private val onMovieClick: (movie: Movie) -> Unit,
) : RecyclerView.Adapter<MoviesAdapter.MovieViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MovieViewHolder {
        val view = LayoutInflater
            .from(parent.context)
            .inflate(R.layout.item_movie, parent, false)
        return MovieViewHolder(view)
    }

    override fun getItemCount(): Int = movies.size

    override fun onBindViewHolder(holder: MovieViewHolder, position: Int) {
        holder.bind(movies[position])
    }

    fun appendMovies(movies: List<Movie>) {
        this.movies.addAll(movies)
        notifyItemRangeInserted(
            this.movies.size,
            movies.size - 1
        )
    }

    inner class MovieViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        private val poster: ImageView = itemView.findViewById(R.id.item_movie_poster)

        fun bind(movie: Movie) {
            itemView.setOnClickListener { onMovieClick.invoke(movie) }
            Glide.with(itemView)
                .load("https://image.tmdb.org/t/p/w342${movie.posterPath}")
                .transform(CenterCrop())
                .into(poster)
        }
    }
}

我的 main_activity_xml:

<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView 
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_gradient"
android:fitsSystemWindows="true">

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">


    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="10dp"
        android:layout_marginTop="25dp"
        android:layout_marginEnd="16dp"
        android:text="@string/discover"
        android:textColor="@android:color/white"
        android:textSize="45sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/popular"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/most_popular_movies" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/popular_movies"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:clipToPadding="false"
        android:paddingStart="16dp"
        android:paddingEnd="16dp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/top_rated"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/highest_rated_movies" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/top_rated_movies"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:clipToPadding="false"
        android:paddingStart="16dp"
        android:paddingEnd="16dp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/upcoming"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/stay_updated" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/upcoming_movies"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="16dp"
        android:clipToPadding="false"
        android:paddingStart="16dp"
        android:paddingEnd="16dp" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/now_playing"
        android:textColor="@android:color/white"
        android:textSize="22sp"
        android:textStyle="bold" />

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginEnd="16dp"
        android:text="@string/now_in_Cinemas" />

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/now_playing_movies"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="10dp"
        android:clipToPadding="false"
        android:paddingStart="16dp"
        android:paddingEnd="16dp" />

</LinearLayout>

</androidx.core.widget.NestedScrollView>

API 密钥:

interface Api {

    @GET("movie/popular")
    fun getPopularMovies(
        @Query("api_key") apiKey: String = 
 "eff7d87eb14cdf1fb273414692d3e3a8",
        @Query("page") page: Int,
    ): Call<GetMoviesResponse>
}

API 加载器:

api.getPopularMovies(page = page)
            .enqueue(object : Callback<GetMoviesResponse> {
                override fun onResponse(
                    call: Call<GetMoviesResponse>,
                    response: Response<GetMoviesResponse>,
                ) {
                    if (response.isSuccessful) {
                        val responseBody = response.body()

                        if (responseBody != null) {
                            onSuccess.invoke(responseBody.movies)
                        } else {
                            onError.invoke()
                        }
                    } else {
                        onError.invoke()
                    }
                }

                override fun onFailure(call: Call<GetMoviesResponse>, t: 
    Throwable) {
                    onError.invoke()
                }
            })

还有什么我应该指定的吗?

标签: androidandroid-cardviewlag

解决方案


没有代码很难回答这个问题,但你总是可以使用一个 ViewSwitcher,它在卡片视图的数据准备好之前显示“正在加载”状态,但保留空间,所以 UI 不会跳转,然后有卡片加载数据后显示的视图。

可能是这样的:

sealed class CardData {
object Loading: CardData()
class Info(val items: List<CardInfo>): CardData()
}

fun loadData() {
    viewModel.cardData.observe { cardData ->
        when(cardData) {
          is Loading -> {
            binding.switcher.displayedChild = 0
           }
          is Info -> {
            binding.switcher.displayedChild = 1
            binding.listOfCards.items = cardData.items
          }
    }
}

对于您的具体情况:

// display the loading view before making the call
binding.switcher.displayedChild = 0
api.getPopularMovies(page = page)
            .enqueue(object : Callback<GetMoviesResponse> {
                override fun onResponse(
                    call: Call<GetMoviesResponse>,
                    response: Response<GetMoviesResponse>,
                ) {
                    if (response.isSuccessful) {
                        val responseBody = response.body()

                        if (responseBody != null) {
                            onSuccess.invoke(responseBody.movies)
                        } else {
                            onError.invoke()
                        }
                    } else {
                        onError.invoke()
                    }
                }

                override fun onFailure(call: Call<GetMoviesResponse>, t: 
    Throwable) {
                    onError.invoke()
                }
            })

// in your onSuccess()
private void onSuccess(List<Movies> movies) {
 binding.switcher.displayedChild = 1
 listAdapter.items = movies
 listAdapter.notifyDatasetChanged()
}

// in your onError()
private void onError() {
 binding.switcher.displayedChild = 2 // you can add a third child for errors
}

那么 XML 将类似于(缺少属性):

<ViewSwitcher
android:id="@+id/switcher">
<!-- child 0 - loading state -->
<ProgressBar
android:id="@+id/loader"
/>
<!-- child 1 - movies state -->
<RecyclerView 
android:id="@+id/movies"
/>
<!-- child 2 - error state -->
<TextView 
android:id="@id/error_text"
/>
</ViewSwitcher>

推荐阅读