Java 无法在gridview android中显示视频缩略图

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

我正在开发一个类似Shareit的共享应用程序,Xender。我想在一个简单的gridview中显示视频的所有缩略图,但是加载缩略图需要很多时间,特别是如果我有1000-2000多个视频的话。 因此,我制作了一个程序,在新线程上加载每个缩略图(如果尚未加载),然后通知基本适配器

代码是:-

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);
}