You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Studio中如何防止获取子文件夹内的视频文件?

问题:视频播放器展示指定文件夹时包含子文件夹内的文件

开发视频播放器应用时,遇到以下问题:访问存储中的文件夹时,会同时获取到其子文件夹内的文件。例如创建了“Folder 1”文件夹及其子文件夹“Folder 2”,打开“Folder 1”时,“Folder 2”内的视频文件也会被展示出来,请问该如何修复?

VideoFilesActivity

public class VideoFilesActivity extends AppCompatActivity implements SearchView.OnQueryTextListener {


    public static final String MY_PREF = "my pref";
    RecyclerView recyclerView;
    private ArrayList<MediaFiles> videoFilesArrayList = new ArrayList<>();
    static VideoFilesAdapter videoFilesAdapter;
    String folder_name;
    String sortOrder;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_video_files);
        folder_name = getIntent().getStringExtra("folderName");
        getSupportActionBar().setTitle(folder_name);
    recyclerView = findViewById(R.id.videos_rv);

        SharedPreferences.Editor editor = getSharedPreferences(MY_PREF, MODE_PRIVATE).edit();
        editor.putString("playlistFOlderName", folder_name);
        editor.apply();


    showVideoFiles();

    }

    private void showVideoFiles() {
        videoFilesArrayList = fetchMedia(folder_name);
    videoFilesAdapter = new VideoFilesAdapter(videoFilesArrayList, this);
    recyclerView.setAdapter(videoFilesAdapter);
    recyclerView.setLayoutManager(new LinearLayoutManager(this,
            RecyclerView.VERTICAL,false));
    videoFilesAdapter.notifyDataSetChanged();
    }

    private ArrayList<MediaFiles> fetchMedia(String folderName) {
        SharedPreferences preferences = getSharedPreferences(MY_PREF, MODE_PRIVATE);
        String sort_value = preferences.getString("sort", "abcd");


        ArrayList<MediaFiles> videoFiles = new ArrayList<>();
        Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        if(sort_value.equals("sortName")) {
            sortOrder = MediaStore.MediaColumns.DISPLAY_NAME+" ASC";
        }else if (sort_value.equals("sortSize")){
            sortOrder = MediaStore.MediaColumns.SIZE+" DESC";
        } else if (sort_value.equals("sorDate")) {
            sortOrder = MediaStore.MediaColumns.DATE_ADDED + " DESC";
        }else {
            sortOrder = MediaStore.Video.Media.DURATION+ " DESC";
        }

        String selection = MediaStore.Video.Media.DATA+" like?";
        String[] selectionArg = new String[]{"%"+folderName+"%"};
        Cursor cursor = getContentResolver().query(uri, null,
                selection, selectionArg, null);
        if (cursor!=null && cursor.moveToNext()) {
            do {
                @SuppressLint("Range") String id = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media._ID));
                @SuppressLint("Range") String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
                @SuppressLint("Range") String displayName = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));
                @SuppressLint("Range") String size = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.SIZE));
                @SuppressLint("Range") String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DURATION));
                @SuppressLint("Range") String path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
                @SuppressLint("Range") String dateAdded = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATE_ADDED));
                MediaFiles mediaFiles = new MediaFiles(id, title, displayName, size, duration, path,
                        dateAdded);
                videoFiles.add(mediaFiles);
            }while (cursor.moveToNext());

        }
        return videoFiles;
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
       getMenuInflater().inflate(R.menu.video_menu, menu);
        MenuItem menuItem = menu.findItem(R.id.search_video);
        SearchView searchView = (SearchView) menuItem.getActionView();
        searchView.setOnQueryTextListener(this);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(@NonNull MenuItem item) {
        SharedPreferences preferences = getSharedPreferences(MY_PREF, MODE_PRIVATE);
        SharedPreferences.Editor editor = preferences.edit();

        int id = item.getItemId();
        switch (id) {
            case R.id.refresh_videos:
                finish();
                startActivity(getIntent());
                break;
            case R.id.sort_by:
                AlertDialog.Builder alertdialog = new AlertDialog.Builder(this);
                alertdialog.setTitle("Sort By");
                alertdialog.setPositiveButton("OK", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        editor.apply();
                        finish();
                        startActivity(getIntent());
                        dialog.dismiss();
                    }
                });
                String[] items = {"Name (A to Z)", "Size (Big to Small)", "Date (New to Old)",
                "Length (Log to Short)"};
                alertdialog.setSingleChoiceItems(items, -1, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        switch ( which){
                            case 0:
                                editor.putString("sort", "sortName");
                            break;
                            case 1:
                                editor.putString("sort", "sortSize");
                                break;
                            case 2:
                                editor.putString("sort", "sortDate");
                                break;
                            case 3:
                                editor.putString("sort", "sortLenght");
                                break;
                        }
                    }
                });
                alertdialog.create().show();
                break;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        return false;
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        String inputs = newText.toLowerCase();
        ArrayList<MediaFiles> mediaFiles = new ArrayList<>();
        for (MediaFiles media : videoFilesArrayList){
            if (media.getTitle().toLowerCase().contains(inputs)){
                mediaFiles.add(media);
            }
        }
        return true;
    }
}

VideoFilesAdapter

public class VideoFilesAdapter extends RecyclerView.Adapter<VideoFilesAdapter.ViewHolder> {
    private ArrayList<MediaFiles> videoList;
    private Context context;

    public VideoFilesAdapter(ArrayList<MediaFiles> videoList, Context context) {
        this.videoList = videoList;
        this.context = context;
    }

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

        View view = LayoutInflater.from(context).inflate(R.layout.video_item, parent, false);
        return new ViewHolder(view);
    }

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

        holder.videoName.setText(videoList.get(position).getDisplayName());
        String size = videoList.get(position).getSize();
        holder.videoSize.setText(android.text.format.Formatter.formatFileSize(context,
                Long.parseLong(size)));

        double milliseconds = Double.parseDouble(videoList.get(position).getDuration());
        holder.videoDuration.setText(timeConversion((long) milliseconds));

        Glide.with(context).load(new File(videoList.get(position).getPath())).into(holder.thumbnail);

        holder.menu_more.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Toast.makeText(context, "Menu More", Toast.LENGTH_SHORT).show();
            }
        });

        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(context, VideoPlayerActivity.class);
                context.startActivity(intent);
            }
        });

    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {
        ImageView thumbnail, menu_more;
        TextView videoName, videoSize, videoDuration;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);

            thumbnail = itemView.findViewById(R.id.thumbnail);
            menu_more = itemView.findViewById(R.id.vide_menu_more);
            videoName = itemView.findViewById(R.id.video_name);
            videoSize = itemView.findViewById(R.id.video_size);
            videoDuration = itemView.findViewById(R.id.video_duration);

        }
    }


    public String timeConversion(long value){
        String videoTime;
        int duration = (int) (value);
        int hrs = (duration / 36000);
        int min = (duration/ 60000 ) % 60000;
        int sec = duration % 60000 / 1000;
        if (hrs > 0 ) {
            videoTime = String.format("%02d:%02d:%02d", hrs, min, sec);
        }else {
            videoTime = String.format("%02d:%02d", min, sec);
        }
        return videoTime;
    }
}

修复方案

问题根源在于fetchMedia方法中使用了模糊匹配MediaStore.Video.Media.DATA like ?,参数为%folderName%,导致所有路径包含该文件夹名称的文件(包括子文件夹内的)都被查询出来。需要修改查询条件,精确匹配文件所在的父目录为目标文件夹。

修改后的fetchMedia方法如下:

private ArrayList<MediaFiles> fetchMedia(String folderName) {
    SharedPreferences preferences = getSharedPreferences(MY_PREF, MODE_PRIVATE);
    String sort_value = preferences.getString("sort", "abcd");

    ArrayList<MediaFiles> videoFiles = new ArrayList<>();
    Uri uri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
    if(sort_value.equals("sortName")) {
        sortOrder = MediaStore.MediaColumns.DISPLAY_NAME+" ASC";
    }else if (sort_value.equals("sortSize")){
        sortOrder = MediaStore.MediaColumns.SIZE+" DESC";
    } else if (sort_value.equals("sorDate")) {
        sortOrder = MediaStore.MediaColumns.DATE_ADDED + " DESC";
    }else {
        sortOrder = MediaStore.Video.Media.DURATION+ " DESC";
    }

    // 获取目标文件夹的绝对路径,避免名称重复导致的匹配错误
    File targetFolder = new File(folderName);
    String folderPath = targetFolder.getAbsolutePath();
    // 构建精确匹配条件:只取目标文件夹下的直接子文件,排除子文件夹内的文件
    String selection = MediaStore.Video.Media.DATA + " LIKE ? AND " +
            MediaStore.Video.Media.DATA + " NOT LIKE ?";
    String[] selectionArg = new String[]{
            folderPath + "/%",
            folderPath + "/%/%"
    };
    Cursor cursor = getContentResolver().query(uri, null,
            selection, selectionArg, sortOrder);
    if (cursor!=null) {
        while (cursor.moveToNext()) {
            @SuppressLint("Range") String id = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media._ID));
            @SuppressLint("Range") String title = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.TITLE));
            @SuppressLint("Range") String displayName = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DISPLAY_NAME));
            @SuppressLint("Range") String size = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.SIZE));
            @SuppressLint("Range") String duration = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DURATION));
            @SuppressLint("Range") String path = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATA));
            @SuppressLint("Range") String dateAdded = cursor.getString(cursor.getColumnIndex(MediaStore.Video.Media.DATE_ADDED));
            MediaFiles mediaFiles = new MediaFiles(id, title, displayName, size, duration, path,
                    dateAdded);
            videoFiles.add(mediaFiles);
        }
        cursor.close();
    }
    return videoFiles;
}

关键修改说明

  1. 绝对路径匹配:先获取目标文件夹的绝对路径,避免同名文件夹导致的误匹配
  2. 双重条件过滤:
    • 第一个条件确保文件路径以目标文件夹路径/开头,即文件在目标文件夹范围内
    • 第二个条件排除路径中包含目标文件夹路径//的情况,确保只取目标文件夹的直接子文件,不包含子文件夹内的内容
  3. 资源优化:添加cursor.close()避免内存泄漏,同时将do-while循环改为更严谨的while循环

内容的提问来源于stack exchange,提问作者Zahid Ashraf

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 09:55:25