RecyclerView 花费太长时间从用户存储中填充大量视频
RecyclerView taking too long to populate a large number of Videos from User Storage
所以我使用Glide来加载视频缩略图,但是加载大量视频需要一段时间才能查看,best/fastest如何加载用户中的视频列表[=22] =] 与每个相应的视频缩略图,在 Recycler 视图中。
填充列表
public static ArrayList<String> getAllMedia(Context context) {
HashSet<String> videoItemHashSet = new HashSet<>();
String[] projection = { MediaStore.Video.VideoColumns.DATA ,MediaStore.Video.Media.DISPLAY_NAME};
Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
try {
cursor.moveToFirst();
do{
videoItemHashSet.add((cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))));
}while(cursor.moveToNext());
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
ArrayList<String> downloadedList = new ArrayList<>(videoItemHashSet);
return downloadedList;
}
滑行法
public static void displayImageOriginal(Context ctx, ImageView img, String url) {
try {
Glide.with(ctx).load(url)
.transition(DrawableTransitionOptions.withCrossFade())
.apply(RequestOptions.centerCropTransform().skipMemoryCache(false).diskCacheStrategy(DiskCacheStrategy.ALL))
.into(img);
} catch (Exception e) {
}
}
这里是适配器视图Binder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final YVideos obj = items.get(position);
if (holder instanceof OriginalViewHolder) {
OriginalViewHolder view = (OriginalViewHolder) holder;
view.video_title.setText(obj.title);
view.duration_size.setText(obj.getDurSize());
Tools.displayImageOriginal(ctx, view.video_thumbnail, obj.name);
} else {
SectionViewHolder view = (SectionViewHolder) holder;
view.title_section.setText(obj.title);
}
}
这一切看起来都像标准的 RecyclerView
用法,因此假设您的适配器被单独分配给 RecyclerView
,即没有定义任何限制性能的属性,例如 setItemViewCacheSize()
, setMaxRecycledViews()
之类的,你的问题不太可能是客户端问题。
您是否依赖 Glide
在运行时为您生成缩略图?如果是这样,您将真正通过大量处理让图书馆完成其步伐,因为它必须即时处理原始质量、原始分辨率的视频。难道不能事先生成缩略图吗?这些将加载得更快,并减轻您的应用程序的大量计算负担。如果缩略图将永远保持不变,那么为什么不计算一次并让每个用户受益,而不是让每个用户在您希望呈现时都计算相同的结果?
在我看来,您的问题很可能是因为您希望在用户已经在查看内容时获取图像并将其呈现给用户。这意味着您加载屏幕,调用 onBindViewHolder()
,并尝试从网络获取图像;但在这个阶段,用户已经在查看列表并准备浏览。在某种程度上,你有点晚了,你的 List
只会和你的网络 connection/image 服务器一样快。
您可以做的是在尝试绘制 RecyclerView
之前准备图像缓存。在到达该屏幕之前,您知道要渲染的图像范围;在您准备好绘图之前,可以将这些 load
转换为 Glide
并定义适当的 diskStrategy
。这样,您可以在用户查看时初始化 List
内容。预测图像缓存策略不会就此结束;您知道接下来准备加载哪几行图像;所以你也可以在后台获取那些。这种方法的缺点是它有可能浪费大量带宽来获取用户可能永远不会向下滚动到的图像;因此您可能需要尝试请求速率限制。
还有更巧妙的方法来解决这个问题。即使是资金最充裕、研究最充分的应用程序也依赖于简单的技巧来解决网络性能的瓶颈……您是否考虑过使用 placeholder animation 来让您的应用程序保持活跃?您会惊讶于这些效果如何!
所以我使用Glide来加载视频缩略图,但是加载大量视频需要一段时间才能查看,best/fastest如何加载用户中的视频列表[=22] =] 与每个相应的视频缩略图,在 Recycler 视图中。
填充列表
public static ArrayList<String> getAllMedia(Context context) {
HashSet<String> videoItemHashSet = new HashSet<>();
String[] projection = { MediaStore.Video.VideoColumns.DATA ,MediaStore.Video.Media.DISPLAY_NAME};
Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, projection, null, null, null);
try {
cursor.moveToFirst();
do{
videoItemHashSet.add((cursor.getString(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DATA))));
}while(cursor.moveToNext());
cursor.close();
} catch (Exception e) {
e.printStackTrace();
}
ArrayList<String> downloadedList = new ArrayList<>(videoItemHashSet);
return downloadedList;
}
滑行法
public static void displayImageOriginal(Context ctx, ImageView img, String url) {
try {
Glide.with(ctx).load(url)
.transition(DrawableTransitionOptions.withCrossFade())
.apply(RequestOptions.centerCropTransform().skipMemoryCache(false).diskCacheStrategy(DiskCacheStrategy.ALL))
.into(img);
} catch (Exception e) {
}
}
这里是适配器视图Binder
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) {
final YVideos obj = items.get(position);
if (holder instanceof OriginalViewHolder) {
OriginalViewHolder view = (OriginalViewHolder) holder;
view.video_title.setText(obj.title);
view.duration_size.setText(obj.getDurSize());
Tools.displayImageOriginal(ctx, view.video_thumbnail, obj.name);
} else {
SectionViewHolder view = (SectionViewHolder) holder;
view.title_section.setText(obj.title);
}
}
这一切看起来都像标准的 RecyclerView
用法,因此假设您的适配器被单独分配给 RecyclerView
,即没有定义任何限制性能的属性,例如 setItemViewCacheSize()
, setMaxRecycledViews()
之类的,你的问题不太可能是客户端问题。
您是否依赖 Glide
在运行时为您生成缩略图?如果是这样,您将真正通过大量处理让图书馆完成其步伐,因为它必须即时处理原始质量、原始分辨率的视频。难道不能事先生成缩略图吗?这些将加载得更快,并减轻您的应用程序的大量计算负担。如果缩略图将永远保持不变,那么为什么不计算一次并让每个用户受益,而不是让每个用户在您希望呈现时都计算相同的结果?
在我看来,您的问题很可能是因为您希望在用户已经在查看内容时获取图像并将其呈现给用户。这意味着您加载屏幕,调用 onBindViewHolder()
,并尝试从网络获取图像;但在这个阶段,用户已经在查看列表并准备浏览。在某种程度上,你有点晚了,你的 List
只会和你的网络 connection/image 服务器一样快。
您可以做的是在尝试绘制 RecyclerView
之前准备图像缓存。在到达该屏幕之前,您知道要渲染的图像范围;在您准备好绘图之前,可以将这些 load
转换为 Glide
并定义适当的 diskStrategy
。这样,您可以在用户查看时初始化 List
内容。预测图像缓存策略不会就此结束;您知道接下来准备加载哪几行图像;所以你也可以在后台获取那些。这种方法的缺点是它有可能浪费大量带宽来获取用户可能永远不会向下滚动到的图像;因此您可能需要尝试请求速率限制。
还有更巧妙的方法来解决这个问题。即使是资金最充裕、研究最充分的应用程序也依赖于简单的技巧来解决网络性能的瓶颈……您是否考虑过使用 placeholder animation 来让您的应用程序保持活跃?您会惊讶于这些效果如何!