如何寫一個檔案總管(FilesManager)

如何寫一個檔案總管(FilesManager)

我們常常需要知道手機內到底有哪些檔案,
因此我們就來寫個檔案總管吧!

首先我們在xml放置一個ListView,

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.example.givemepass.filemanagerdemo.MainActivity">

    <ListView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/list_view" />
</RelativeLayout>

先透過如何透過Android Studio產生向量圖產出兩張圖, 分別是檔案跟資料夾的icon

接著宣告一個陣列來存放這兩張圖片

private int[] fileImg = {
            R.drawable.directory,
            R.drawable.file};

當我們搜尋的時候,會將該層的目錄列表在ListView,
我們宣告一個ArrayList, 用來裝某一層目錄底下每筆資料的圖片以及名稱,
然後在用兩個ArrayList來裝每筆資料的名稱及路徑。

private void initData() {
    filesList = new ArrayList<>();
    names = new ArrayList<>();
    paths = new ArrayList<>();
    getFileDirectory(ROOT);
}

getFileDirectory方法一開始先判斷是否進入根目錄,如果不是進入根目錄,
裡面使用paths這個陣列來儲存當前目錄,
如果不是在根目錄,
則會在index 0跟index 1分別加入上一層(..)跟根目錄(/),

private void getFileDirectory(String path){
    filesList.clear();
    if(!path.equals(ROOT)){
        //回根目錄
        filesMap = new HashMap<>();
        names.add(ROOT);
        paths.add(FIRST_ITEM, ROOT);
        filesMap.put(IMG_ITEM, fileImg[0]);
        filesMap.put(NAME_ITEM, ROOT);
        filesList.add(filesMap);
        //回上一層
        filesMap = new HashMap<>();
        names.add(PRE_LEVEL);
        paths.add(SECOND_ITEM, new File(path).getParent());
        filesMap.put(IMG_ITEM, fileImg[0]);
        filesMap.put(NAME_ITEM, PRE_LEVEL);
        filesList.add(filesMap);
    }

    //...
}

接著搜尋該層下面所有的檔案跟資料夾
透過File的方法listFiles()把下面的檔案跟資料夾列出來
根據File來判斷是否為資料夾, 如果是則設定image為資料夾的圖示,
反之, 為檔案圖示。

private void getFileDirectory(String path){
    //...
    files = new File(path).listFiles();
    for(int i = 0; i < files.length; i++){
        filesMap = new HashMap<>();
        names.add(files[i].getName());
        paths.add(files[i].getPath());
        if(files[i].isDirectory()){
            filesMap.put(IMG_ITEM, fileImg[0]);
        }
        else {
            filesMap.put(IMG_ITEM, fileImg[1]);
        }
        filesMap.put(NAME_ITEM, files[i].getName());
        filesList.add(filesMap);
    }
}

還記得在如何使用SimpleAdapter如何使用GridView裡面, 我們也是利用相同的方式來建立SimpleAdapter,
然後在丟入ListView, 就可以完成一個帶有圖示的ListView。

simpleAdapter = new SimpleAdapter(this,
    filesList, R.layout.simple_adapter, 
    new String[]{IMG_ITEM, NAME_ITEM},
    new int[]{R.id.image, R.id.text});
listView = (ListView) findViewById(R.id.list_view);
listView.setAdapter(simpleAdapter);       

這樣一執行程式,就會看到目錄所形成的ListView了。

可是我們還必須實做當使用者點下某個資料夾的時候,
就會跳往下一層的功能。

listView.setOnItemClickListener(new AdapterView.OnItemClickListener(){
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        String target = paths.get(position);
        if(target.equals(ROOT)){
            nowPath = paths.get(position);
            getFileDirectory(ROOT);
            simpleAdapter.notifyDataSetChanged();
        } else if(target.equals(PRE_LEVEL)){
            nowPath = paths.get(position);
            getFileDirectory(new File(nowPath).getParent());
            simpleAdapter.notifyDataSetChanged();
        } else {
            File file = new File(target);
            if (file.canRead()) {
                if (file.isDirectory()) {
                    nowPath = paths.get(position);
                    getFileDirectory(paths.get(position));
                    simpleAdapter.notifyDataSetChanged();
                } else{
                    Toast.makeText(MainActivity.this, R.string.is_not_directory, Toast.LENGTH_SHORT).show();
                }
            } else{
                Toast.makeText(MainActivity.this, R.string.can_not_read, Toast.LENGTH_SHORT).show();
            }
        }
    }
});

如果有透過getFileDirectory存取資料前,
都必須將nowPath存起來,
因為這樣才能將目前處於哪一層記錄起來。

可以一層一層往下點, 也可以直接回到上一層或根目錄,
這樣一來一個簡單的檔案總管就完成了。

github