欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Android 文件管理器的列表界面

程序员文章站 2022-06-10 10:43:40
...

前言:

之前做了一个文件管理器的app,那么列表中只有名字....实在太简陋了,所以我打算做一个比较好看一点的列表。

效果图:

Android 文件管理器的列表界面


可能对于专业的你来说,还是比较简陋。这次列表中,除了文件名,我还添加了图标,文件大小,文件权限还有修改日期。

首先这是一个RecyclerView..然后先上代码,这个RecyclerView的部分代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <ImageView
        android:id="@+id/myFileImage"
        android:layout_width="50dp"
        android:layout_height="50dp"
        android:layout_margin="5dp"
        app:srcCompat="@mipmap/ic_launcher" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/myFileName"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="5dp"
            android:singleLine="true"
            android:ellipsize="start"
            android:textSize="25sp"
            android:layout_gravity="center"
            android:text="TextView" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="horizontal">

            <TextView
                android:id="@+id/fileSize"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="大小" />

            <TextView
                android:id="@+id/filePower"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="权限" />

            <TextView
                android:id="@+id/fileDate"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_weight="1"
                android:text="创建日期" />
        </LinearLayout>
    </LinearLayout>


</LinearLayout>

这个是列表每个项目的样子,来张截图

Android 文件管理器的列表界面


然后是这个包装类

package com.example.administrator.day2_15;

/**
 * Created by Administrator on 2018/2/25 0025.
 */

public class MyFile {
    private int imageId;
    private String fileName;
    private String fileSize;
    private String filePower;
    private String fileDate;

    public MyFile(String fileName, int imageId, String fileSize, String filePower, String fileDate) {
        super();
        this.fileName = fileName;
        this.imageId = imageId;
        this.fileSize = fileSize;
        this.filePower = filePower;
        this.fileDate = fileDate;
    }

    public String getFileName() {
        return fileName;
    }

    public int getImageId() {
        return imageId;
    }

    public String getFileSize() {
        return fileSize;
    }

    public String getFilePower() {
        return filePower;
    }

    public String getFileDate() {
        return fileDate;
    }
}

然后就到自定义的Adapter

package com.example.administrator.day2_15;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import java.util.List;

/**
 * Created by Administrator on 2018/2/25 0025.
 */

public class MyFileAdapter extends RecyclerView.Adapter<MyFileAdapter.ViewHolder> {
    private List<MyFile> myFileList;
    private Context mContext;

    public MyFileAdapter(List<MyFile> list) {
        super();
        myFileList = list;
    }

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (mContext == null) {
            mContext = parent.getContext();
        }
        View view = LayoutInflater.from(mContext).inflate(R.layout.myfile_item, parent, false);
        ViewHolder holder = new ViewHolder(view);
        return holder;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        MyFile myFile = myFileList.get(position);
        holder.myFileName.setText(myFile.getFileName());
        holder.myFileImage.setImageResource(myFile.getImageId());
        holder.myFileSize.setText(myFile.getFileSize());
        holder.myFilePower.setText(myFile.getFilePower());
        holder.myFileDate.setText(myFile.getFileDate());
    }

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

    static class ViewHolder extends RecyclerView.ViewHolder{
        TextView myFileName;
        ImageView myFileImage;
        TextView myFileSize;
        TextView myFilePower;
        TextView myFileDate;

        public ViewHolder(View itemView) {
            super(itemView);
            myFileName = itemView.findViewById(R.id.myFileName);
            myFileImage = itemView.findViewById(R.id.myFileImage);
            myFileSize = itemView.findViewById(R.id.fileSize);
            myFilePower = itemView.findViewById(R.id.filePower);
            myFileDate = itemView.findViewById(R.id.fileDate);
        }
    }
}

如果你了解RecyclerView的话,这些不用说你都明白,甚至会觉得有点啰嗦了。

好了,关键的地方到了,就是传入RecyclerView的数据,文件的大小,创建时间,图标怎么判断呢

private void initMyFile(File sourceFile) {
        myFileList.clear();
        List<File> files = new ArrayList<>();
        Collections.addAll(files, sourceFile.listFiles());
        for (File file : files) {
            String fileName = file.getName();
            //默认是未知文件
            int imageId = R.drawable.interrogation;

            //下面开始判断
            if (file.isDirectory()) {
                imageId = R.drawable.floder2;
            } else {
                //如果是文件,就从文件名的后缀名来判断是什么文件,从而添加对应图标
                //获取后缀名前的分隔符"."在fName中的位置。
                int dotIndex = fileName.lastIndexOf(".");
                if(dotIndex >= 0){
                    /* 获取文件的后缀名*/
                    String end= fileName.substring(dotIndex,fileName.length()).toLowerCase();
                    if(!Objects.equals(end, "")){
                        if (Objects.equals(end, ".mp3")||Objects.equals(end, ".ape")
                                ||Objects.equals(end, ".flac")||Objects.equals(end, ".m4a")
                                ||Objects.equals(end, ".ape")||Objects.equals(end, ".wav")
                                ||Objects.equals(end, ".aac")){
                            //如果是音乐文件
                            imageId = R.drawable.music;
                        }else if (Objects.equals(end, ".mp4")||Objects.equals(end, ".mkv")
                                ||Objects.equals(end, ".avi")||Objects.equals(end, ".rmvb")
                                ||Objects.equals(end, ".rm")||Objects.equals(end, ".mov")
                                ||Objects.equals(end, ".mpeg")){
                            //如果是影视文件
                            imageId = R.drawable.play;
                        }
                    }
                }
            }

            String fileSize = "";
            long size = 0;
            //下面开始判断文件大小
            if (file.isDirectory()) {
                //如果是文件夹就要求出占用大小 = 总大小 - 可用大小
                try {
                    size = getTotalSizeOfFilesInDir(file);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                size = file.length();
            }
            //判断大小是该用什么单位,K\M\G
            if (size / 1024 / 1024 / 1024 > 0) {
                fileSize = size / 1024 / 1024 / 1024 + " G";
            } else if (size / 1024 / 1024 > 0) {
                fileSize = size / 1024 / 1024 + " M";
            } else {
                fileSize = size / 1024 + " K";
            }

            String filePower = "";
            StringBuilder builder = new StringBuilder();
            builder.append("-");
            if (file.canRead()) builder.append("r");
            if (file.canWrite()) builder.append("w");
            if (file.canExecute()) builder.append("x");
            filePower = builder.toString();

            String fileDate = "";
            fileDate = getModifiedTime_2(file);

            MyFile myFile = new MyFile(fileName, imageId, fileSize, filePower, fileDate);
            myFileList.add(myFile);
        }
        adapter.notifyDataSetChanged();
    }

该方法只是测试样子,所以图标那块仅仅区分了音乐文件和影视文件,还有其他文件格式没有添加进去。不过大同小异,也是照葫芦画瓢而已。

那么至于怎么获取文件夹的大小,上代码

private class SubDirectoriesAndSize {

        final public long size;
        final public List<File> subDirectories;

        public SubDirectoriesAndSize(final long totalSize,
                                     final List<File> theSubDirs) {
            size = totalSize;
            subDirectories = Collections.unmodifiableList(theSubDirs);
        }
    }

    private SubDirectoriesAndSize getTotalAndSubDirs(final File file) {
        long total = 0;
        final List<File> subDirectories = new ArrayList<File>();
        if (file.isDirectory()) {
            final File[] children = file.listFiles();
            if (children != null)
                for (final File child : children) {
                    if (child.isFile())
                        total += child.length();
                    else
                        subDirectories.add(child);
                }
        }
        return new SubDirectoriesAndSize(total, subDirectories);
    }

    private long getTotalSizeOfFilesInDir(final File file)
            throws InterruptedException, ExecutionException, TimeoutException {
        final ExecutorService service = Executors.newFixedThreadPool(100);
        try {
            long total = 0;
            final List<File> directories = new ArrayList<File>();
            directories.add(file);
            while (!directories.isEmpty()) {
                final List<Future<SubDirectoriesAndSize>> partialResults = new ArrayList<Future<SubDirectoriesAndSize>>();
                for (final File directory : directories) {
                    partialResults.add(service
                            .submit(new Callable<SubDirectoriesAndSize>() {
                                public SubDirectoriesAndSize call() {
                                    return getTotalAndSubDirs(directory);
                                }
                            }));
                }
                directories.clear();
                for (final Future<SubDirectoriesAndSize> partialResultFuture : partialResults) {
                    final SubDirectoriesAndSize subDirectoriesAndSize = partialResultFuture
                            .get(100, TimeUnit.SECONDS);
                    directories.addAll(subDirectoriesAndSize.subDirectories);
                    total += subDirectoriesAndSize.size;
                }
            }
            return total;
        } finally {
            service.shutdown();
        }
    }

这个方法使用Executors.newFixedThreadPool和callable 多线程实现,是来自网址

点击打开链接  ,这个博客里面还介绍了很多种获取文件夹大小的方法,我开头试过单线程递归,发现很耗时间和内存。

返回字节后再通过一点判断来决定显示单位。

最后就是怎么获取文件的修改时间呢?

public static String getModifiedTime_2(File f){
        Calendar cal = Calendar.getInstance();
        long time = f.lastModified();
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        cal.setTimeInMillis(time);
        return formatter.format(cal.getTime());
    }

这个方法是来自百度知道 回答者 vdny 。。。点击打开链接

最后再贴上mainActivity的部分代码

    private List<MyFile> myFileList = new ArrayList<>();
    private MyFileAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        adapter = new MyFileAdapter(myFileList);
        initMyFile(Environment.getExternalStorageDirectory());
        RecyclerView recyclerView = findViewById(R.id.rv);
        LinearLayoutManager manager = new LinearLayoutManager(this);
        recyclerView.setLayoutManager(manager);
        recyclerView.setAdapter(adapter);

    }

好了,那么写到这里终于把文件管理器的Bug和坑填完了。但是我也失去了去年那种小小进步就能兴奋不已的感觉了。

希望这篇文章能够帮助到你。如有问题,请尽管提出,看到我会尽量回答你。拜