Java 无法在gridview android中显示视频缩略图
我正在开发一个类似Shareit的共享应用程序,Xender。我想在一个简单的gridview中显示视频的所有缩略图,但是加载缩略图需要很多时间,特别是如果我有1000-2000多个视频的话。 因此,我制作了一个程序,在新线程上加载每个缩略图(如果尚未加载),然后通知基本适配器 代码是:-Java 无法在gridview android中显示视频缩略图,java,android,mediastore,Java,Android,Mediastore,我正在开发一个类似Shareit的共享应用程序,Xender。我想在一个简单的gridview中显示视频的所有缩略图,但是加载缩略图需要很多时间,特别是如果我有1000-2000多个视频的话。 因此,我制作了一个程序,在新线程上加载每个缩略图(如果尚未加载),然后通知基本适配器 代码是:- package com.*.filetransfer.Server.File.Selection.SubFragments; import android.content.ContentUris; impo
package com.*.filetransfer.Server.File.Selection.SubFragments;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import com.*.filetransfer.R;
import com.*.filetransfer.Strings;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static com.*.filetransfer.Server.File.Selection.FileSelection.selected_item_counter_down;
import static com.*.filetransfer.Server.File.Selection.FileSelection.selected_item_counter_up;
import static com.*.filetransfer.Server.File.Selection.FileSelection.videoList;
public class VideoGalleryFragment extends Fragment {
GridView gridView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.gridview, container, false);
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
videoList = new ArrayList<Video>();
gridView = view.findViewById(R.id.gridview);
String[] projection = new String[] {
MediaStore.Video.Media._ID,
MediaStore.Video.Media.DISPLAY_NAME,
MediaStore.Video.Media.DURATION,
MediaStore.Video.Media.SIZE
};
String selection = MediaStore.Video.Media.DURATION +
" >= ?";
String[] selectionArgs = new String[] {
String.valueOf(TimeUnit.MILLISECONDS.convert(5, TimeUnit.MILLISECONDS))};
String sortOrder = MediaStore.Video.Media.DATE_ADDED + " DESC";
try (Cursor cursor = getContext().getApplicationContext().getContentResolver().query(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
projection,
selection,
selectionArgs,
sortOrder
)) {
// Cache column indices.
int idColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media._ID);
int nameColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DISPLAY_NAME);
int durationColumn =
cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATION);
int sizeColumn = cursor.getColumnIndexOrThrow(MediaStore.Video.Media.SIZE);
while (cursor.moveToNext()) {
// Get values of columns for a given video.
long id = cursor.getLong(idColumn);
String name = cursor.getString(nameColumn);
int duration = cursor.getInt(durationColumn);
long size = cursor.getLong(sizeColumn);
Uri contentUri = ContentUris.withAppendedId(
MediaStore.Video.Media.EXTERNAL_CONTENT_URI, id);
// Stores column values and the contentUri in a local object
// that represents the media file.
videoList.add(new Video(contentUri, name, duration, size, null, false, false));
}
gridView.setAdapter(new GalleryGridViewAdapter(requireContext(), videoList){
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if (imageView == null){
imageView = new ImageView(requireContext());
imageView.setLayoutParams(new GridView.LayoutParams(300,300));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
imageView.setPadding(20,20,20,20);
}
if (( (Video) getItem(position)).isChecked()){
imageView.setBackgroundColor(getResources().getColor(R.color.aqua));
}
else{
imageView.setBackgroundColor(Color.TRANSPARENT);
}
if (((Video)getItem(position)).getThumbnail() == null && (!((Video)getItem(position)).isImageLoading())){
((Video)getItem(position)).setImageLoading(true);
new Thread(new Runnable() {
@Override
public void run() {
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor1 = requireContext().getContentResolver().query(((Video)getItem(position)).getUri(), filePathColumn, null, null, null);
cursor1.moveToFirst();
int columnIndex = cursor1.getColumnIndex(filePathColumn[0]);
String picturePath = cursor1.getString(columnIndex);
cursor1.close();
Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(picturePath, MediaStore.Video.Thumbnails.MINI_KIND);
((Video)getItem(position)).setThumbnail(bitmap);
((Video)getItem(position)).setImageLoading(true);
try {
requireActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
notifyDataSetChanged();
}
});
}
catch (IllegalStateException ignored){
}
}
}).start();
}
if (((Video)getItem(position)).getThumbnail() != null)
imageView.setImageBitmap(((Video)getItem(position)).getThumbnail());
return imageView;
}
});
}
gridView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (!videoList.get(position).isChecked()) {
videoList.get(position).setChecked(true);
selected_item_counter_up();
Log.e(Strings.TAG, String.valueOf(videoList.get(position).getSize()));
try {
((ImageView) view).setBackgroundColor(getResources().getColor(R.color.aqua));
} catch (Exception e) {
}
}
else{
videoList.get(position).setChecked(false);
selected_item_counter_down();
try {
((ImageView) view).setBackgroundColor(Color.TRANSPARENT);
} catch (Exception e) {
}
}
}
});
}
}
class GalleryGridViewAdapter extends BaseAdapter {
private List<Video> videos;
private Context context;
public GalleryGridViewAdapter(Context context, List<Video> videoList) {
this.context = context;
this.videos = videoList;
}
@Override
public int getCount() {
return videos.size();
}
@Override
public Object getItem(int position) {
return videos.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
return null;
}
}
我面临的问题是,如果用户滚动得太快,大部分缩略图都会混淆,有些会多次加载。有人能发现缺陷并纠正它吗
如果您可以建议一种在设备上加载和显示媒体缩略图的替代方法,如果可能,请按日期分开,因为我不知道如何操作
编辑
我切换到recyclerview,它的滚动非常平稳,但出于某种原因,它正在滚动到顶部。以下是更新的代码:-
package com.*.filetransfer.Server.File.Selection.SubFragments;
import android.graphics.Color;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.sugarsnooper.filetransfer.R;
import com.*.filetransfer.Server.File.Selection.Media;
import com.*.filetransfer.Server.Send_Activity;
import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import static com.*.filetransfer.Server.File.Selection.FileSelection.imageList;
public class Photos extends Fragment {
RecyclerView gridView;
GridAdapter ga = new GridAdapter();
private int max_padding = 20;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.gridview, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
imageList = new ArrayList<>();
for (Map.Entry<String, Long> entry : Send_Activity.readableRoots.getImages().entrySet())
{
File file = new File(entry.getKey());
imageList.add(new Media(Uri.fromFile(file), file.getName(), file.length(), entry.getValue()));
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
gridView = view.findViewById(R.id.gridview);
gridView.setLayoutManager(new GridLayoutManager(requireContext(), 3));
gridView.setAdapter(ga);
gridView.addItemDecoration(new SpacesItemDecoration(30));
}
});
}
}).start();
}
class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
// Add top margin only for the first item to avoid double space between items
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
}
class GridAdapter extends RecyclerView.Adapter<GridAdapter.MyViewHolder> {
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View layout = LayoutInflater.from(requireActivity()).inflate(R.layout.grid_item, parent, false);
return new MyViewHolder(layout);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int i) {
if (((Media) getItem(i)).isChecked()) {
holder.ivparent.setPadding(max_padding, max_padding, max_padding, max_padding);
holder.ivparent.setBackgroundColor(Color.parseColor("#777777"));
}
else{
holder.ivparent.setPadding(0, 0, 0, 0);
holder.ivparent.setBackgroundColor(Color.parseColor("#00777777"));
}
Glide.with(requireActivity()).fromUri().dontAnimate().load(((Media) getItem(i)).getUri()).into(holder.imageView);
}
@Override
public int getItemCount() {
return imageList.size();
}
@Override
public void onViewRecycled(@NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
holder.recycle();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
LinearLayout ivparent;
ImageView imageView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
ivparent = itemView.findViewById(R.id.iv_parent);
}
public void recycle() {
Glide.clear(imageView);
}
}
public Object getItem(int i) {
return imageList.get(i);
}
}
}
package com.*.filetransfer.Server.File.Selection.SubFragments;
导入android.graphics.Color;
导入android.graphics.Rect;
导入android.net.Uri;
导入android.os.Bundle;
导入android.os.Handler;
导入android.os.Looper;
导入android.view.LayoutInflater;
导入android.view.view;
导入android.view.ViewGroup;
导入android.widget.ImageView;
导入android.widget.LinearLayout;
导入androidx.annotation.NonNull;
导入androidx.annotation.Nullable;
导入androidx.fragment.app.fragment;
导入androidx.recyclerview.widget.GridLayoutManager;
导入androidx.recyclerview.widget.recyclerview;
导入com.bumptech.glide.glide;
导入com.sugarsnooper.filetransfer.R;
导入com.*.filetransfer.Server.File.Selection.Media;
导入com.*.filetransfer.Server.Send_活动;
导入java.io.File;
导入java.util.ArrayList;
导入java.util.Map;
导入静态com.*.filetransfer.Server.File.Selection.FileSelection.imageList;
公共类照片扩展片段{
RecyclerView gridView;
GridAdapter ga=新的GridAdapter();
私有int max_padding=20;
@可空
@凌驾
创建视图时的公共视图(@NonNull LayoutInflater inflater、@Nullable ViewGroup container、@Nullable Bundle savedInstanceState){
返回充气机。充气(R.layout.gridview,容器,假);
}
@凌驾
已创建公用void onview(@NonNull视图,@Nullable Bundle savedInstanceState){
super.onViewCreated(视图,savedInstanceState);
新线程(newrunnable()){
@凌驾
公开募捐{
imageList=新的ArrayList();
for(Map.Entry:Send_Activity.readableroot.getImages().entrySet())
{
File File=新文件(entry.getKey());
添加(新媒体(Uri.fromFile(file)、file.getName()、file.length()、entry.getValue());
}
新的处理程序(Looper.getMainLooper()).post(新的Runnable()){
@凌驾
公开募捐{
gridView=view.findviewbyd(R.id.gridView);
setLayoutManager(新的GridLayoutManager(requireContext(),3));
setAdapter(ga);
gridView.addItemDecoration(新的SpacesItemDecoration(30));
}
});
}
}).start();
}
类SpaceSiteDecoration扩展了RecyclerView.ItemDecoration{
私有int空间;
公共空间站点删除(内部空间){
这个空间=空间;
}
@凌驾
public void getItemOffset(Rect-outRect、View-View、,
RecyclerView父级,RecyclerView.State(状态){
outRect.left=空间;
outRect.right=空间;
outRect.bottom=空间;
//仅为第一个项目添加上边距,以避免项目之间出现双空格
if(parent.getChildLayoutPosition(视图)==0){
outRect.top=空间;
}否则{
outRect.top=0;
}
}
}
类GridAdapter扩展了RecyclerView.Adapter{
@非空
@凌驾
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup父级,int-viewType){
视图布局=LayoutFlater.from(requireActivity())。充气(R.layout.grid_项,父项,false);
返回新的MyViewHolder(布局);
}
@凌驾
public void onBindViewHolder(@NonNull MyViewHolder,int i){
如果(((媒体)getItem(i)).isChecked()){
holder.ivparent.setPadding(max_padding,max_padding,max_padding,max_padding);
holder.ivparent.setBackgroundColor(Color.parseColor(“#777777”);
}
否则{
holder.ivparent.setPadding(0,0,0,0);
holder.ivparent.setBackgroundColor(Color.parseColor(“#00777777”);
}
Glide.with(requireActivity()).fromUri().dontAnimate().load((媒体)getItem(i)).getUri())加载到(holder.imageView)中;
}
@凌驾
public int getItemCount(){
返回imageList.size();
}
@凌驾
ViewRecycled上的公共无效(@NonNull MyViewHolder){
super.onViewRecycled(支架);
holder.recycle();
}
公共类MyViewHolder扩展了RecyclerView.ViewHolder{
直系亲属;
图像视图图像视图;
公共MyViewHolder(@NonNull View itemView){
超级(项目视图);
imageView=(imageView)itemView.findViewById(R.id.imageView);
ivparent=itemView.findviewbyd(R.id.iv_parent);
}
公共空间回收(){
滑动。清除(图像视图);
}
}
公共对象getItem(int i){
返回imageList.get(i);
}
}
}
package com.*.filetransfer.Server.File.Selection.SubFragments;
import android.graphics.Bitmap;
import android.net.Uri;
public class Video {
private final Uri uri;
private final String name;
private final int duration;
private final long size;
private Bitmap thumbnail;
private boolean isImageLoading;
private boolean isChecked;
public Video(Uri uri, String name, int duration, long size, Bitmap bitmap, boolean isImageLoading, boolean isChecked) {
this.uri = uri;
this.name = name;
this.duration = duration;
this.size = size;
this.thumbnail = bitmap;
this.isImageLoading = isImageLoading;
this.isChecked = isChecked;
}
public boolean isChecked() {
return isChecked;
}
public boolean isImageLoading() {
return isImageLoading;
}
public Uri getUri() {
return uri;
}
public String getName() {
return name;
}
public int getDuration() {
return duration;
}
public long getSize() {
return size;
}
public Bitmap getThumbnail() {
return thumbnail;
}
public void setThumbnail(Bitmap thumbnail) {
this.thumbnail = thumbnail;
}
public void setImageLoading(boolean imageLoading) {
isImageLoading = imageLoading;
}
public void setChecked(boolean checked) {
isChecked = checked;
}
}
package com.*.filetransfer.Server.File.Selection.SubFragments;
import android.graphics.Color;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.GridLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.bumptech.glide.Glide;
import com.sugarsnooper.filetransfer.R;
import com.*.filetransfer.Server.File.Selection.Media;
import com.*.filetransfer.Server.Send_Activity;
import java.io.File;
import java.util.ArrayList;
import java.util.Map;
import static com.*.filetransfer.Server.File.Selection.FileSelection.imageList;
public class Photos extends Fragment {
RecyclerView gridView;
GridAdapter ga = new GridAdapter();
private int max_padding = 20;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return inflater.inflate(R.layout.gridview, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
new Thread(new Runnable() {
@Override
public void run() {
imageList = new ArrayList<>();
for (Map.Entry<String, Long> entry : Send_Activity.readableRoots.getImages().entrySet())
{
File file = new File(entry.getKey());
imageList.add(new Media(Uri.fromFile(file), file.getName(), file.length(), entry.getValue()));
}
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
gridView = view.findViewById(R.id.gridview);
gridView.setLayoutManager(new GridLayoutManager(requireContext(), 3));
gridView.setAdapter(ga);
gridView.addItemDecoration(new SpacesItemDecoration(30));
}
});
}
}).start();
}
class SpacesItemDecoration extends RecyclerView.ItemDecoration {
private int space;
public SpacesItemDecoration(int space) {
this.space = space;
}
@Override
public void getItemOffsets(Rect outRect, View view,
RecyclerView parent, RecyclerView.State state) {
outRect.left = space;
outRect.right = space;
outRect.bottom = space;
// Add top margin only for the first item to avoid double space between items
if (parent.getChildLayoutPosition(view) == 0) {
outRect.top = space;
} else {
outRect.top = 0;
}
}
}
class GridAdapter extends RecyclerView.Adapter<GridAdapter.MyViewHolder> {
@NonNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View layout = LayoutInflater.from(requireActivity()).inflate(R.layout.grid_item, parent, false);
return new MyViewHolder(layout);
}
@Override
public void onBindViewHolder(@NonNull MyViewHolder holder, int i) {
if (((Media) getItem(i)).isChecked()) {
holder.ivparent.setPadding(max_padding, max_padding, max_padding, max_padding);
holder.ivparent.setBackgroundColor(Color.parseColor("#777777"));
}
else{
holder.ivparent.setPadding(0, 0, 0, 0);
holder.ivparent.setBackgroundColor(Color.parseColor("#00777777"));
}
Glide.with(requireActivity()).fromUri().dontAnimate().load(((Media) getItem(i)).getUri()).into(holder.imageView);
}
@Override
public int getItemCount() {
return imageList.size();
}
@Override
public void onViewRecycled(@NonNull MyViewHolder holder) {
super.onViewRecycled(holder);
holder.recycle();
}
public class MyViewHolder extends RecyclerView.ViewHolder {
LinearLayout ivparent;
ImageView imageView;
public MyViewHolder(@NonNull View itemView) {
super(itemView);
imageView = (ImageView) itemView.findViewById(R.id.imageView);
ivparent = itemView.findViewById(R.id.iv_parent);
}
public void recycle() {
Glide.clear(imageView);
}
}
public Object getItem(int i) {
return imageList.get(i);
}
}
}
@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
// Code for loading thumbnail using video file path
Glide.with(context)
.load(Uri.fromFile(new File(videoFilePath)))
.thumbnail(0.5f)
.into(imageView);
}