Recyclerview 在滚动完成之前不能顺利滚动
Recyclerview not scrolling smoothly before scrolling finish
我在滚动时遇到问题我的意思是滚动速度很快但它看起来像是在滚动完成之前滞后
在这里我定义 RecyclerView :
RecyclerView recyclerView=fragment.getRecyclerView();
LinearLayoutManager layoutManager = new LinearLayoutManager(fragment.getActivity(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new DividerItemDecoration(fragment.getActivity(), LinearLayoutManager.VERTICAL));
ArrayList<InstaPostModel> rowListItems=getInstaPostListSample();
InstaPostAdapter rcAdapter = new InstaPostAdapter(rowListItems);
recyclerView.setAdapter(rcAdapter);
这里是 BindViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
context = holder.itemView.getContext();
Glide.with(context).load(R.mipmap.mee_small).into(holder.userPhoto);
Glide.with(context).load(R.drawable.post_image).into(holder.photo_content);
Glide.with(context).load(R.mipmap.love_gray_icon).into(holder.bt_like);
Glide.with(context).load(R.mipmap.comment_icon).into(holder.bt_comment);
Glide.with(context).load(R.mipmap.share_icon).into(holder.bt_share);
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
这里RecyclerView.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/qatar_now_posts_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
tools:context=".uis.fragments.home.QatarNowFragment"
/>
编辑
我也在同一个片段中有底部导航栏,它在滚动时显示
编辑 2 这是显示延迟的视频 link
我尝试了所有解决方案,但没有人帮助我。
我已经添加了我所有的代码
请帮忙?
如果recyclerview 中的项目大小相同,您可以尝试:
recyclerview.setHasFixedSize(真);
我认为滚动问题可能是因为您在绑定时重新加载图像。您可以在加载照片时使用缓存,当然还有分页。
您可以优化您的代码,
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
context = holder.itemView.getContext();
setImage(holder.userPhoto, p.getUserPhotoUrl());
setImage(holder.photo_content, p.getPostPhotoUrl());
setImage(holder.bt_like, R.mipmap.love_gray_icon);
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
private void setImage(ImageView iv, String url)
{
Glide.with(context)
.load(Urls.BASE_URI +url).thumbnail(0.5f)
.apply(new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true).dontAnimate()
)
.into(iv);
}
private void setImage(ImageView iv, int resource)
{
Glide.with(context)
.load(resource).thumbnail(0.5f)
.apply(new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true).dontAnimate()
)
.into(iv);
}
它肯定会减少负载,而 rendering.Make 请确保仅在适配器中遍历时才使用变量,因为每次 list.get(position) 调用都会占用更多内存。
我没有发现您的代码有任何问题。还有以下几点需要考虑。
(1) 您从 API 获得的 图像 的尺寸 太大 可能会发生什么。检查 API 的大小并使其最多减少 200 kb。 (100-150 kb 也足够了)。
(2) 您不应禁用缓存,因为它将通过将图像存储在缓存中并下次通过缓存而不是通过缓存加载来改善用户体验 URL。
(3) 您 现在不需要使用 material-ripple
库来获得 Android 中可用的简单涟漪效果。将此属性添加到您的 ImageView
android:background="?attr/selectableItemBackground"
(4) 检查一次加载了多少项目。你不应该一次加载很多项目。参见 Architecture component paging library
(5) 同时检查资源的大小,例如 love_gray_icon
。我认为它应该最大 70*70。如果你有更大的,你应该调整它的大小。 Resize multiple images at once. Also compress images before use, that will decrease image size up-to 80%. After resize, compress images.
(6) Glide 是一个维护良好的库,所以 onViewRecycled
是多余的。
终于对您的代码进行了一点修改。
private void loadImage(ImageView iv, String url) {
Glide.with(iv.getContext()).load(url).thumbnail(0.5f).into(iv);
}
private void loadImage(ImageView iv, int resId) {
Glide.with(iv.getContext()).load(resId).thumbnail(0.5f).into(iv);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
loadImage(holder.userPhoto, Urls.BASE_URI + p.getUserPhotoUrl());
loadImage(holder.photo_content, Urls.BASE_URI + p.getPostPhotoUrl());
loadImage(holder.bt_like, R.mipmap.love_gray_icon);
loadImage(holder.bt_comment, R.mipmap.comment_icon);
loadImage(holder.bt_share, R.mipmap.share_icon);
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
我有几个改进建议给你。
- 您在列表项中加载的图像过多。尽可能减少图像加载。例如,您可能会考虑为“赞”和“分享”按钮设置默认图像,这在您的应用程序中通常不会更改。在列表项布局中将它们设置为
android:src
。
- 检查 Instagram 图片是否太大。您可能会得到 API 来加载平均大小的图像。
- 使用选择器而不是创建嵌套视图可以在单击列表项中的喜欢或共享按钮时产生连锁反应。尽量保持列表项布局尽可能简单,并尽量避免嵌套视图层次结构。
- 从您的适配器中删除我认为不必要的
onViewRecycled
功能。
- 使用在构造函数中传递给它的
Context
初始化适配器。您不必每次都在 onBindViewHodler
中获取它。
- 您不必每次都在
onBindViewHolder
函数中初始化 RequestOption
。只需初始化一次并在每个 Glide 图像加载器中使用它。
- 如前所述,删除按钮、评论和共享图像加载器并提供图像作为布局中的源。
- 使用
DiskCacheStrategy.ALL
缓存您的图像,这样它就不会在您每次打开应用程序或加载 RecyclerView
时加载。
因此,最终的适配器应该如下所示。
public class InstaPostAdapter
extends RecyclerView.Adapter<InstaPostAdapter.ViewHolder> {
private List<InstaPostModel> items = new ArrayList<>();
Context context;
// Initialize the context once, use it everywhere
public InstaPostAdapter(List<InstaPostModel> items, Context context) {
this.items = items;
this.context = context;
}
@Override
public InstaPostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.insta_post_list_item, parent, false);
// set the view's size, margins, paddings and layout parameters
return new ViewHolder(v);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
RequestOptions requestOptions = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(context)
.load(Urls.BASE_URI + items.get(position).getUserPhotoUrl()).thumbnail(0.5f)
.apply(requestOptions)
.into(holder.userPhoto);
Glide.with(context)
.load(Urls.BASE_URI + items.get(position).getPostPhotoUrl()).thumbnail(0.5f)
.apply(requestOptions)
.into(holder.photo_content);
// Removed the like, comment, share images which should be set from layout.
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return items.size();
}
@Override
public long getItemId(int position) {
return position;
}
public void add(InstaPostModel post, int i) {
items.add(post);
notifyItemInserted(i);
}
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public ImageView userPhoto;
public TextView userNameTextView;
public ImageView bt_more;
public ImageView photo_content;
public ImageView bt_like;
public ImageView bt_comment;
public ImageView bt_share;
public TextView postContent;
public RelativeTimeTextView post_date;
public ViewHolder(View v) {
super(v);
userPhoto = v.findViewById(R.id.insta_user_photo);
userNameTextView = v.findViewById(R.id.insta_user_name);
bt_more = v.findViewById(R.id.insta_bt_more);
photo_content = v.findViewById(R.id.insta_photo_content);
bt_like = v.findViewById(R.id.insta_bt_like);
bt_comment = v.findViewById(R.id.insta_bt_comment);
bt_share = v.findViewById(R.id.insta_bt_share);
postContent = v.findViewById(R.id.insta_post_content);
post_date = v.findViewById(R.id.insta_post_date);
setClickListener();
}
private void setClickListener() {
bt_more.setOnClickListener(view -> {
PopupMenu popupMenu = new PopupMenu(context, view);
popupMenu.setOnMenuItemClickListener(item -> {
Snackbar.make(view, item.getTitle() + " Clicked", Snackbar.LENGTH_SHORT).show();
return true;
});
popupMenu.inflate(R.menu.menu_feed_popup);
popupMenu.show();
});
bt_like.setOnClickListener(view -> Snackbar.make(view, "Like Clicked", Snackbar.LENGTH_SHORT).show());
bt_comment.setOnClickListener(view -> Snackbar.make(view, "Comment Clicked", Snackbar.LENGTH_SHORT).show());
bt_share.setOnClickListener(view -> Snackbar.make(view, "Share Clicked", Snackbar.LENGTH_SHORT).show());
}
}
}
我想我已经为 Flickr 图像搜索完成了一个类似的项目。您可能会找到 project here in Github。
希望对您有所帮助!
可能是图片太大了
您可以像这样使用滑行调整它的大小
Glide.with(context)
.load(imgUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.error(placeholder)
.placeholder(placeholder)
.dontTransform()
.override(200,200)
.into(imageView);
有人提到您应该使用 pagingadapter。我正在使用它,但滚动不流畅。在我的例子中,我将 recyclerview 放在了一个可滚动的视图中。尽管使用了 pagingadapter,但它正在加载整个 rv。为简单起见:不要将 rv 放在可滚动视图中。如果你需要一些 header 将它放在不同类型的房车里。
我在滚动时遇到问题我的意思是滚动速度很快但它看起来像是在滚动完成之前滞后 在这里我定义 RecyclerView :
RecyclerView recyclerView=fragment.getRecyclerView();
LinearLayoutManager layoutManager = new LinearLayoutManager(fragment.getActivity(), LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new DividerItemDecoration(fragment.getActivity(), LinearLayoutManager.VERTICAL));
ArrayList<InstaPostModel> rowListItems=getInstaPostListSample();
InstaPostAdapter rcAdapter = new InstaPostAdapter(rowListItems);
recyclerView.setAdapter(rcAdapter);
这里是 BindViewHolder
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
context = holder.itemView.getContext();
Glide.with(context).load(R.mipmap.mee_small).into(holder.userPhoto);
Glide.with(context).load(R.drawable.post_image).into(holder.photo_content);
Glide.with(context).load(R.mipmap.love_gray_icon).into(holder.bt_like);
Glide.with(context).load(R.mipmap.comment_icon).into(holder.bt_comment);
Glide.with(context).load(R.mipmap.share_icon).into(holder.bt_share);
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
这里RecyclerView.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/qatar_now_posts_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scrollbars="none"
tools:context=".uis.fragments.home.QatarNowFragment"
/>
编辑 我也在同一个片段中有底部导航栏,它在滚动时显示
编辑 2 这是显示延迟的视频 link
我尝试了所有解决方案,但没有人帮助我。
我已经添加了我所有的代码
请帮忙?
如果recyclerview 中的项目大小相同,您可以尝试: recyclerview.setHasFixedSize(真);
我认为滚动问题可能是因为您在绑定时重新加载图像。您可以在加载照片时使用缓存,当然还有分页。
您可以优化您的代码,
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
context = holder.itemView.getContext();
setImage(holder.userPhoto, p.getUserPhotoUrl());
setImage(holder.photo_content, p.getPostPhotoUrl());
setImage(holder.bt_like, R.mipmap.love_gray_icon);
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
private void setImage(ImageView iv, String url)
{
Glide.with(context)
.load(Urls.BASE_URI +url).thumbnail(0.5f)
.apply(new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true).dontAnimate()
)
.into(iv);
}
private void setImage(ImageView iv, int resource)
{
Glide.with(context)
.load(resource).thumbnail(0.5f)
.apply(new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.NONE)
.skipMemoryCache(true).dontAnimate()
)
.into(iv);
}
它肯定会减少负载,而 rendering.Make 请确保仅在适配器中遍历时才使用变量,因为每次 list.get(position) 调用都会占用更多内存。
我没有发现您的代码有任何问题。还有以下几点需要考虑。
(1) 您从 API 获得的 图像 的尺寸 太大 可能会发生什么。检查 API 的大小并使其最多减少 200 kb。 (100-150 kb 也足够了)。
(2) 您不应禁用缓存,因为它将通过将图像存储在缓存中并下次通过缓存而不是通过缓存加载来改善用户体验 URL。
(3) 您 现在不需要使用 material-ripple
库来获得 Android 中可用的简单涟漪效果。将此属性添加到您的 ImageView
android:background="?attr/selectableItemBackground"
(4) 检查一次加载了多少项目。你不应该一次加载很多项目。参见 Architecture component paging library
(5) 同时检查资源的大小,例如 love_gray_icon
。我认为它应该最大 70*70。如果你有更大的,你应该调整它的大小。 Resize multiple images at once. Also compress images before use, that will decrease image size up-to 80%. After resize, compress images.
(6) Glide 是一个维护良好的库,所以 onViewRecycled
是多余的。
终于对您的代码进行了一点修改。
private void loadImage(ImageView iv, String url) {
Glide.with(iv.getContext()).load(url).thumbnail(0.5f).into(iv);
}
private void loadImage(ImageView iv, int resId) {
Glide.with(iv.getContext()).load(resId).thumbnail(0.5f).into(iv);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
loadImage(holder.userPhoto, Urls.BASE_URI + p.getUserPhotoUrl());
loadImage(holder.photo_content, Urls.BASE_URI + p.getPostPhotoUrl());
loadImage(holder.bt_like, R.mipmap.love_gray_icon);
loadImage(holder.bt_comment, R.mipmap.comment_icon);
loadImage(holder.bt_share, R.mipmap.share_icon);
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
我有几个改进建议给你。
- 您在列表项中加载的图像过多。尽可能减少图像加载。例如,您可能会考虑为“赞”和“分享”按钮设置默认图像,这在您的应用程序中通常不会更改。在列表项布局中将它们设置为
android:src
。 - 检查 Instagram 图片是否太大。您可能会得到 API 来加载平均大小的图像。
- 使用选择器而不是创建嵌套视图可以在单击列表项中的喜欢或共享按钮时产生连锁反应。尽量保持列表项布局尽可能简单,并尽量避免嵌套视图层次结构。
- 从您的适配器中删除我认为不必要的
onViewRecycled
功能。 - 使用在构造函数中传递给它的
Context
初始化适配器。您不必每次都在onBindViewHodler
中获取它。 - 您不必每次都在
onBindViewHolder
函数中初始化RequestOption
。只需初始化一次并在每个 Glide 图像加载器中使用它。 - 如前所述,删除按钮、评论和共享图像加载器并提供图像作为布局中的源。
- 使用
DiskCacheStrategy.ALL
缓存您的图像,这样它就不会在您每次打开应用程序或加载RecyclerView
时加载。
因此,最终的适配器应该如下所示。
public class InstaPostAdapter
extends RecyclerView.Adapter<InstaPostAdapter.ViewHolder> {
private List<InstaPostModel> items = new ArrayList<>();
Context context;
// Initialize the context once, use it everywhere
public InstaPostAdapter(List<InstaPostModel> items, Context context) {
this.items = items;
this.context = context;
}
@Override
public InstaPostAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// create a new view
View v = LayoutInflater.from(parent.getContext())
.inflate(R.layout.insta_post_list_item, parent, false);
// set the view's size, margins, paddings and layout parameters
return new ViewHolder(v);
}
// Replace the contents of a view (invoked by the layout manager)
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
final InstaPostModel p = items.get(position);
RequestOptions requestOptions = new RequestOptions()
.diskCacheStrategy(DiskCacheStrategy.ALL);
Glide.with(context)
.load(Urls.BASE_URI + items.get(position).getUserPhotoUrl()).thumbnail(0.5f)
.apply(requestOptions)
.into(holder.userPhoto);
Glide.with(context)
.load(Urls.BASE_URI + items.get(position).getPostPhotoUrl()).thumbnail(0.5f)
.apply(requestOptions)
.into(holder.photo_content);
// Removed the like, comment, share images which should be set from layout.
holder.userNameTextView.setText(p.getPosterUserName());
holder.postContent.setText(p.getText());
holder.post_date.setReferenceTime(p.getDate().getTime());
}
// Return the size of your dataset (invoked by the layout manager)
@Override
public int getItemCount() {
return items.size();
}
@Override
public long getItemId(int position) {
return position;
}
public void add(InstaPostModel post, int i) {
items.add(post);
notifyItemInserted(i);
}
public class ViewHolder extends RecyclerView.ViewHolder {
// each data item is just a string in this case
public ImageView userPhoto;
public TextView userNameTextView;
public ImageView bt_more;
public ImageView photo_content;
public ImageView bt_like;
public ImageView bt_comment;
public ImageView bt_share;
public TextView postContent;
public RelativeTimeTextView post_date;
public ViewHolder(View v) {
super(v);
userPhoto = v.findViewById(R.id.insta_user_photo);
userNameTextView = v.findViewById(R.id.insta_user_name);
bt_more = v.findViewById(R.id.insta_bt_more);
photo_content = v.findViewById(R.id.insta_photo_content);
bt_like = v.findViewById(R.id.insta_bt_like);
bt_comment = v.findViewById(R.id.insta_bt_comment);
bt_share = v.findViewById(R.id.insta_bt_share);
postContent = v.findViewById(R.id.insta_post_content);
post_date = v.findViewById(R.id.insta_post_date);
setClickListener();
}
private void setClickListener() {
bt_more.setOnClickListener(view -> {
PopupMenu popupMenu = new PopupMenu(context, view);
popupMenu.setOnMenuItemClickListener(item -> {
Snackbar.make(view, item.getTitle() + " Clicked", Snackbar.LENGTH_SHORT).show();
return true;
});
popupMenu.inflate(R.menu.menu_feed_popup);
popupMenu.show();
});
bt_like.setOnClickListener(view -> Snackbar.make(view, "Like Clicked", Snackbar.LENGTH_SHORT).show());
bt_comment.setOnClickListener(view -> Snackbar.make(view, "Comment Clicked", Snackbar.LENGTH_SHORT).show());
bt_share.setOnClickListener(view -> Snackbar.make(view, "Share Clicked", Snackbar.LENGTH_SHORT).show());
}
}
}
我想我已经为 Flickr 图像搜索完成了一个类似的项目。您可能会找到 project here in Github。
希望对您有所帮助!
可能是图片太大了
您可以像这样使用滑行调整它的大小
Glide.with(context)
.load(imgUrl)
.diskCacheStrategy(DiskCacheStrategy.ALL)
.error(placeholder)
.placeholder(placeholder)
.dontTransform()
.override(200,200)
.into(imageView);
有人提到您应该使用 pagingadapter。我正在使用它,但滚动不流畅。在我的例子中,我将 recyclerview 放在了一个可滚动的视图中。尽管使用了 pagingadapter,但它正在加载整个 rv。为简单起见:不要将 rv 放在可滚动视图中。如果你需要一些 header 将它放在不同类型的房车里。