RecyclerView延迟滚动

时间:2015-10-22 18:45:43

标签: android android-recyclerview picasso

我在RecyclerView中加载400x200图像,但在2k设备上滚动是滞后的。我正在使用Picasso从资源加载图像。

正如您在演示图像中看到的那样,在2k屏幕上图像模糊,但如果我加载更高分辨率的图像,情况会变得更糟。 如何解决这个问题,我甚至没有加载大图像,它的400x200?

Demo

这是我的代码 的 card_view.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:card_view="http://schemas.android.com/apk/res-auto"
    android:id="@+id/card_view"
    card_view:cardPreventCornerOverlap="false"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    card_view:cardCornerRadius="2dp">

    <LinearLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:id="@+id/rel">

        <ImageView
            android:id="@+id/cardimage"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:scaleType="fitXY"
            android:src="@drawable/p7"/>

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="title"
            android:paddingLeft="16dp"
            android:paddingRight="16dp"
            android:paddingTop="16dp"
            android:paddingBottom="24dp"
            android:textStyle="bold"
            android:textSize="24sp"
            android:id="@+id/cardtitle"
            android:layout_gravity="center_vertical"/>

    </LinearLayout>

</android.support.v7.widget.CardView>

Myadapter代码

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

private Context mContext;
List<Flower> list = new ArrayList<>();

public CardAdapter(Context mContext, List<Flower> list) {
    this.mContext = mContext;
    this.list = list;

}

@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)   {

    View itemView = LayoutInflater.from(parent.getContext())
            .inflate(R.layout.card_view, parent, false);
    return new ViewHolder(itemView);
}

@Override
public void onBindViewHolder(ViewHolder holder, int position)  {

    holder.Flower=getItem(position);
    holder.cardtitle.setText(list.get(position).name);

    Picasso.with(mContext)
            .load(list.get(position).id)
            .placeholder(R.drawable.ic_launcher)
            .into(holder.cardimage);
}

@Override
public void onAttachedToRecyclerView(RecyclerView recyclerView) {
    super.onAttachedToRecyclerView(recyclerView);
}

@Override
public int getItemCount() {
    return list.size();
}

public Flower getItem(int i) {
    return list.get(i);
}

public class ViewHolder extends RecyclerView.ViewHolder {

    ImageView cardimage;
    TextView cardtitle;
    Flower Flower;

    public ViewHolder(View itemView) {
        super(itemView);

        cardimage = (ImageView) itemView.findViewById(R.id.cardimage);
        cardtitle = (TextView) itemView.findViewById(R.id.cardtitle);
    }
}
}

更新:我正在从资源加载图片,我没有下载任何内容

这是我的数组

 private void initializeData() {
    flowers = new ArrayList<>();
    flowers.add(new Flower("Flower 1", R.drawable.p8));
    flowers.add(new Flower("Flower 2", R.drawable.p10));
    flowers.add(new Flower("Flower 3", R.drawable.p11));
    flowers.add(new Flower("Flower 4", R.drawable.p8));
    flowers.add(new Flower("Flower 5", R.drawable.photo2));
    flowers.add(new Flower("Flower 6", R.drawable.photo6));
    flowers.add(new Flower("Flower 7", R.drawable.p12));
    flowers.add(new Flower("Flower 8", R.drawable.p9));
    flowers.add(new Flower("Flower 9", R.drawable.p8));
    flowers.add(new Flower("Flower 10", R.drawable.p8));
    flowers.add(new Flower("Flower 11", R.drawable.p8));
    flowers.add(new Flower("Flower 12", R.drawable.p10));
}

更新2:伙计我通过设置adapter.setHasStableIds(true)修复了大部分滞后,但是当图像尚未加载时,app仍然在第一个滚动上滞后,如何修复?

更新3:我刚试过从网上加载图像,一切看起来都很顺利,从资源加载图像可能存在一些问题。

好的,谢谢你们,我要从网上加载我的图片。

14 个答案:

答案 0 :(得分:19)

如果您使用两个或更多回收站视图,例如(RecyclerView和NestedView) 试试这个

recyclerView.setNestedScrollingEnabled(false);

来源:Recyclerview inside Nested Scrollview scroll but does not fast scroll like normal Recyclerview or Nested Scrollview

答案 1 :(得分:10)

RecyclerView.setHasFixedSize()是否设置为true?我无法重现这种滞后...你能把整个项目发布在git上吗?看看这个,也许它可以帮到你:http://antonioleiva.com/recyclerview/

答案 2 :(得分:7)

我相信,有时您只尝试在可绘制图形中显示某些静态图片来显示您的回收站视图时会生气。而且发生了极端落后

为什么?当您使用某些库从url加载图片时,您可能不会出现此问题(毕加索,格莱德...),但是相同图像,相同大小的图像会发生什么直接在您的可绘制对象中(完全不需要下载)。过了一会儿,我发现, android 做了一些技巧,调整了可绘制图像的大小,使我们在不同分辨率的设备上获得了合适的图像 >。因此,我的建议使用drawable-nodpi 存储您的图像,以使android不会干扰我们的图像。

答案 3 :(得分:2)

您需要异步获取图像。就像现在一样,它实际上下载了图像。

在创建图像视图时将其保留为空白,但在下载图像时会有某种倾听者设置图像。

答案 4 :(得分:2)

如果您在垂直模式下使用Recyclerview,并且您的活动包含您拥有ScrollView的其他项目,那么您必须使用NestedScrollView而不是ScrollView

如google文档中所述NestedScrollView就像ScrollView一样,但它支持在新旧版本的Android上充当嵌套滚动父级和子级。默认情况下启用嵌套滚动。

答案 5 :(得分:2)

这是因为需要花费一些时间来加载图像。 首先,将您的图像加载代码更改为以下代码...

Picasso.get().load(list.get(position).id).fit().centerCrop()
                .placeholder(R.drawable.ic_launcher)
                .into(holder.cardimage);

然后,之前在recyclerview上将适配器设置为MainActivity中CardAdapter的实例,然后添加此行。

        yourAdapter_name.setHasStableIds(true);

另一个提示...如果有人使用大型可绘制对象(xxxhdpi,xxhdpi),请先将其转换为mdpi或ldpi。这也将大大提高性能并减小apk大小。您可以使用此网站NativeScript Image Builder

答案 6 :(得分:1)

当recyclerView中的一个textView接收到空值时,我遇到了laggy recyclerView问题。我解决了这个问题,我的recyclerView停止了滞后。

答案 7 :(得分:1)

这可能是因为毕加索花时间加载图像。使用以下快照并相应调整。

Picasso.with (context)
                    .load (url).fit().centerCrop()
                    .error (R.drawable.UserImage)         
                    .into (imageView);

使用fit()centerCrop()来避免紧张。

答案 8 :(得分:0)

可能已经晚了,但是也许有人会觉得它有用。遇到同样的问题,问题就在网上:

<ul>
    <li>item1</li>
    <li>item2</li>
    <div>submenu</div>
</ul>

所以我这样添加了fit()。centerCrop():

<ul>
    <li>item1</li>
    <li>item2
        <div>submenu</div>
    </li>
</ul>

那解决了我的问题

答案 9 :(得分:0)

我来晚了,但是可以使用带有Glide的缩略图来解决。

     Glide.with(context)
                .load(URL)
                .dontAnimate()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .thumbnail(0.5f)
                .centerCrop()
                .into(imageView);

答案 10 :(得分:0)

就我而言,位图的创建延迟了滚动。因此,我将位图创建放在后台线程中,并设置为UI线程中的图像。这样,不会阻止用户界面创建位图

new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Bitmap myBitmap = BitmapFactory.decodeFile(filepath);
                        activity.runOnUiThread(new Runnable() {
                            public void run() {
                                vItem.imgProfile.setImageBitmap(myBitmap);
           
                            }
                        });
                    }
                }).start();

答案 11 :(得分:0)

根据我对recyclerview的经验,我发现可能的原因可能是图像尺寸。 除了将属性(setNestedScrollingEnabled(false); )添加到recyclerview和(setHasStableIds)到适配器之外,还有助于使recyclerview顺利工作。 因此,最重要的是,如果您的recyclerview有要从网络加载的图片,请确保覆盖其大小或使用缩略图属性(滑行)。 这个骗局挽救了我的性命,我希望它也可以挽救他人的性命。 编码愉快:)

答案 12 :(得分:0)

有点晚了,但我发现利用 Kotlin 协程作为降低 onBindViewHolder() 调用成本的有效方法,通过将图像加载卸载到后台线程。我使用 Glide 加载 384x384 的图像,滚动流畅,最多可加载数千张图像。

// Here, defaultScope = CoroutineScope(Dispatchers.Default + SupervisiorJob())
// Key idea is to launch the Glide call on a background thread.

defaultScope.launch(exceptionHandler) {
    Glide.with(view)
        .load(uri)
        .also {
            // When Glide is done preparing the resource, 
            // use Main thread to load into ImageView.
            withContext(Dispatchers.Main) {
                it.into(view)
            }
        }
}

对于 Picasso 来说,这将是类似的事情(虽然我没有亲自尝试过),其中 into() 必须从 Main 线程和后台线程上的准备中调用。

答案 13 :(得分:-2)

我认为原因是Picasso会缓存您的图片,但由于您有一个与应用程序捆绑在一起的drawable列表,因此理论上您不需要缓存图像。缓存仅在您从互联网下载图像时非常有用,并且您不希望每次在Recyclerview上向上或向下滑动时应用程序都会重新下载图像。

我会通过更改memorypolicy来调整毕加索的工作方式,所以请尝试这样做:

 Picasso.with(getContext()).load(data.get(pos).getFeed_thumb_image()).memoryPolicy(MemoryPolicy.NO_CACHE).into(image);