使用 Glide 在 RecyclerView 中加载图像时 UI 滞后且不稳定

Ste*_*ail 7 android android-recyclerview android-glide google-cloud-firestore

我有一个 RecyclerView,它使用 Glide 从 URL 加载图像。现在,使用分页从 Firebase 检索 URL,如下所示。问题是,当 MainActivity(包含以下代码和 recyclerview)首次初始化时,UI 中存在很大的延迟(滚动非常缓慢且断断续续,选项菜单需要 3 秒才能打开等),并且图像需要一段时间才能显示出来。加载时。当我向下滚动并到达第一页数据的 RecyclerView 末尾后,OnScrollListener 被触发,我开始从新查询加载新数据。我已经尽力根据我发表的另一篇文章中的用户建议来优化 Glide 的功能,并且我也将其设置adapter.setHasFixedSize为 true,但运气不佳。知道这里发生了什么吗?尽管查询是异步的,但我是否以某种方式挂起 UI 线程?

编辑 :Glide 是否会由于必须将多个图像加载到回收器视图的 imageViews 中而导致主线程上的滞后?如果是这样,我能做什么来应对呢?

以下是我处理从 Firebase 获取的数据的分页并通知适配器的方法:

class MainActivity : AppCompatActivity() {

private val TAG: String = MainActivity::class.java.simpleName // Tag used for debugging
private var queryLimit : Long = 50 // how many documents should the query request from firebase
private lateinit var iconsRCV : RecyclerView // card icons recycler view
private lateinit var lastVisible:DocumentSnapshot

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    val rootRef: FirebaseFirestore = FirebaseFirestore.getInstance()
    val urlsRef : CollectionReference = rootRef.collection("CardIconUrls")
    val query : Query = urlsRef.orderBy("resID",Query.Direction.ASCENDING).limit(queryLimit) // create a query for the first queryLimit documents in the urlsRef collection

    // Setting Toolbar default settings
    val toolbar : Toolbar = findViewById(R.id.mainToolbar)
    setSupportActionBar(toolbar) // set the custom toolbar as the support action bar
    supportActionBar?.setDisplayShowTitleEnabled(false) // remove the default action bar title

    // RecyclerView initializations
    iconsRCV = findViewById(R.id.cardIconsRCV)
    iconsRCV.layoutManager = GridLayoutManager(this,5) // set the layout manager for the rcv
    val iconUrls : ArrayList<String> = ArrayList() // initialize the data with an empty array list
    val adapter = CardIconAdapter(this,iconUrls) // initialize the adapter for the recyclerview
    iconsRCV.adapter = adapter // set the adapter
    iconsRCV.setHasFixedSize(true)

    iconsRCV.addOnScrollListener(object:OnScrollListener(){
        override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
            super.onScrollStateChanged(recyclerView, newState)

            if(!iconsRCV.canScrollVertically(1) && (newState == RecyclerView.SCROLL_STATE_IDLE) && ((iconsRCV.layoutManager as GridLayoutManager).findLastVisibleItemPosition() == (iconsRCV.layoutManager as GridLayoutManager).itemCount-1)) {
                Log.d(TAG,"End of rcv-Starting query")
                val nextQuery = urlsRef.orderBy("resID",Query.Direction.ASCENDING).startAfter(lastVisible).limit(queryLimit).get().addOnCompleteListener { task ->
                    if(task.isSuccessful) {
                        Log.d(TAG,"Next query called")
                        for(document:DocumentSnapshot in task.result!!) {
                            iconUrls.add(document.get("url").toString())
                        }
                        lastVisible = task.result!!.documents[task.result!!.size()-1]
                        adapter.notifyDataSetChanged()
                    }
                }
            }
        }
    })

    query.get().addOnCompleteListener {task: Task<QuerySnapshot> ->
        if(task.isSuccessful) {
            Log.d(TAG,"Success")
            for(document:DocumentSnapshot in task.result!!) {
                Log.d(TAG,"Task size = " + task.result!!.size())
                iconUrls.add(document.get("url").toString()) // add the url to the list
            }
            lastVisible = task.result!!.documents[task.result!!.size()-1]
            adapter.notifyDataSetChanged() // notify the adapter about the new data
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 recyclerview 适配器:

public class CardIconAdapter extends RecyclerView.Adapter<CardIconAdapter.ViewHolder> {

    private List<String> urlsList;
    private Context context;

    class ViewHolder extends RecyclerView.ViewHolder {
        ImageView iconImg;
        ViewHolder(@NonNull View view) {
            super(view);
            iconImg = view.findViewById(R.id.cardIcon);
        }
    }

    public CardIconAdapter(Context cntxt, List<String> data) {
        context = cntxt;
        urlsList = data;
    }

    @NonNull
    @Override
    public CardIconAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view =  LayoutInflater.from(parent.getContext()).inflate(R.layout.card_icons_rcv_item,parent,false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull CardIconAdapter.ViewHolder holder, int position) {
        RequestOptions requestOptions = RequestOptions.diskCacheStrategyOf(DiskCacheStrategy.ALL);
        GlideApp.with(context).load(urlsList.get(position)).thumbnail(0.25f).centerCrop().dontTransform().apply(requestOptions).into(holder.iconImg);
    }

    @Override
    public int getItemCount() {
        return urlsList.size();
    }
}
Run Code Online (Sandbox Code Playgroud)

向上滚动

Ste*_*ail 8

经过多次尝试和错误,我终于解决了这个问题。我的第一个错误是没有发布 recyclerview 项目的 xml 布局文件,因为这是性能问题的根源。第二个错误是我使用的是LinearLayout,并将其自己的layout_width和layout_height属性设置为75dp,而不是嵌套在LinearLayout内部的ImageView,并且使用wrap_content作为ImageView各自的属性。因此,为了解决性能问题,我执行了以下操作:

  1. 我将其更改LinearLayout为 a ConstraintLayout(我读到它总体上更加优化)
  2. 我将 ConstraintLayout 的layout_width&layout_height属性设置为wrap_content和 最后
  3. 我将实际 ImageView 的布局宽度和布局高度属性设置为 75dp,这是我想要图像的实际尺寸

这是更改后 recyclerview 的每个项目的最终布局文件:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:orientation="horizontal"
    android:padding="5dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/cardIcon"
        android:layout_width="75dp"
        android:layout_height="75dp"
        android:contentDescription="cardIcon"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:srcCompat="@tools:sample/avatars" />
</androidx.constraintlayout.widget.ConstraintLayout>
Run Code Online (Sandbox Code Playgroud)