GiveMePasS's Android惡補筆記

如何使用 TabLayout + ViewPager

情境

如果要使用 TabLayout 在 Android 早期是很痛苦的,漸漸的有很多優秀的第三方出來支援,包含 Indicater、ViewPager 等等…。

由於太常使用這些元件,因此 Google 這次在 android.support.design 這包 library 內,直接就提供 TabLayout 讓你快速建立好一個 Tab 元件。

如何使用CheckBox

情境

如果要使用一個勾選方塊,可以使用 CheckBox 這個元件,它會出現一個選取方塊讓使用者來進行勾選,一般來說它會是多選的模式,如果你想要用單選的方式來進行選取,那麼建議是使用 RadioButton 會比較恰當。

如何使用全版面的 DialogFragment

情境

如果你想要宣告一個 Fragment 並且以全版面呈現,應該怎麼做?
如何使用Toast.md

情境

Toast是一個小型提示訊息的視窗,會顯示在視窗下方的一個小小訊息,不會妨礙使用者進行其他的操作,是一個很常見的工具。

如何使用Button

情境

Button 是 Android 剛入門一定會碰到的元件, 根據使用者按下去, 開發者寫出對應的反應, 在外觀上就是一個單純的按鈕。

如何在Android 5.0以上使用Notification icon

這次的範例從如何使用Notification修改的,在 Android 5.0 以上,Google 建議你使用白色跟透明的icon,否則這樣的 icon 會在 Notification 上面被塗成白色。

如何使用 Badge Count (桌面圖示計數)

情境

在 Android 系統上面,我們需要在外面 Icon 上面提示使用者有幾則未讀的訊息,方便使用者在還沒進入到 App 之前就能夠決定是否要進到 App 內查看,這時候,就會使用到 Badge Count 這個功能,比較奇怪的是 Google 對於這個設計卻沒有支援,因此,只能夠過第三方函式庫來完成這樣的功能。

如何使用 Firebase - 使用 Notification

情境

在早期叫做 Android Cloud to Device Messaging (C2DM),
後來改成使用 Google Cloud Messaging (GCM),
現在因為 Firebase 而推出了 Firebase Cloud Messaging (FCM),
FCM 簡單操作而且方便, 只需要幾個簡單的設定,
就可以完成推播的功能。

如何使用 Firebase - 操作 Authentication - 管理 User

情境

如何使用 Firebase - 操作 Authentication - 註冊與登入帳戶
我們透過 Firebase 成功建立一個簡易版的 email 註冊系統
在這個系統我們其實可以增加更多管理的功能
例如: 修改 Email、修改密碼、Email 驗證以及刪除使用者 … 等等

如何使用 Firebase - 操作 Authentication - 註冊與登入帳戶

情境

Firebase 提供一套非常簡單操作的第三方帳號認證登入模式
從 Firebase 的控制台可以看到我們的登入方式有以下幾種方式

  • Email
  • Google
  • Facebook
  • Twitter
  • GitHub
  • Anonymous
如何使用SnapHelper

情境

Google 在 API 24 的時候出了一個 SnapHelper 的工具
這有甚麼用呢?
它類似 ViewPager 的操作方式
但是最大的不同點是它的輪詢模式會比較不一樣
一般 ViewPager 一頁就一個 View
SnapHelper 可以搭配 RecyclerView 來進行調配
可以滑到一半停止呈現

如何使用CoordinatorLayout搭配AppBarLayout

情境

如何使用RecylerView+CardView以及
如何使用Toolbar+DrawerLayout+Tab+SwipRefresh

示範了TabLayout跟RecyclerView的使用
這個範例來結合這兩個元件
加入CoordinatorLayout跟AppBarLayout完成一個往上推Tab會縮上去的效果

如何使用TextInputLayout

情境

Google 出了一個新的 Layout 叫做 TextInputLayout
可以讓你在操作 EditText 的時候使用者體驗更佳
它提供了許多方便的操作方法跟動畫

如何使用 PercentRelativeLayout

情境

多裝置一直都是 Android 開發者的痛
因此 Google 提供了一套新的 Layout library 讓開發者能夠輕鬆處理多裝置的問題
只需要透過比例的調整
就可以根據螢幕的大小來進行微調

如何使用 Firebase - 操作 Storage

情境

如何使用 Firebase - 用 Android Studio 建立帳戶篇 簡單介紹如何建立一個 Firebase 的專案
所以我們來玩一下 Firebase 的檔案空間系統
Firebase 提供良好的 Storage 讓你能夠輕鬆操作各項檔案
無論是上傳, 下載或者刪除檔案
都提供非常簡便的介面讓開發者使用
因此我們只需要幾行程式碼
就可以完成檔案存取的複雜功能

如何使用 Firebase - 用 Android Studio 建立帳戶篇

情境

如何使用 Firebase - 建立帳戶篇是屬於刻苦耐勞型的安裝環境步驟
其實在 Android Studio 內已經幫你內建好工具直接設定

如何使用 Firebase - 建立帳戶篇

起源

Google 支援一套後台系統叫做 Firebase
它提供了許多服務讓 App 或者 Web 開發者可以輕鬆開發出更有效率的程式
例如推撥、資料庫、儲存檔案、登入認證以及分析等 … 多種服務

如何不用 USB 線就可以安裝 apk 到手機上

情境

讀書會的朋友介紹一種不用連接 USB 線就可以直接透過 Android Studio 來安裝 APK 的方式

如何使用Runtime Permission-使用EasyPermissions

情境

如何使用 Runtime Permission 當中我們知道許多權限是需要使用者同意才可以使用的
可是在跟使用者取得權限的程式碼卻是十分的複雜
因此有第三方開發出很簡便的要權限的程式
這個第三方就是 EasyPermissions

電子書

嗨 大家好
我是 GiveMePasS
這個 Blog 本來是記錄工作或練習遇到的難題
在編排方式較為雜亂無章

如何使用ContentProvider-簡介

簡介

ContentProvider是一組讓你跟其他應用程式存取的資料庫
對於剛接觸的Android開發者來說
它會是一個比較難以上手的區域
Android提供一套通用的介面讓每個應用程式可以進行CRUD(新增、讀取、更新、刪除)的操作
ContentProvider用於管理音訊、影片、圖片、個人聯絡資訊等資料

如何使用Toast

情境

Toast是一個小型提示訊息的視窗
會顯示在視窗下方的一個小小訊息
不會妨礙使用者進行其他的操作
是一個很常見的工具

如何將專案內的git push到github上面

情境

如果要把project丟到github
之前的作法是會先在github建立一個repository,
但是問題來了, 如果先前我們已經有對project進行git init了以後
就無法對之前的git history進行保留。

如何解決CheckBox在RecyclerView錯亂的Bug

問題

某次在寫RecyclerView時, 內裝CheckBox的時候,
滾動RecyclerView會造成CheckBox勾選亂跳。

如何使用LinearLayout

情境

布局(Layout)是一開始寫Android就會碰到的第一個課題,
在Android要排版排的好, 必須對Layout有基礎的認識,
LinearLayout提供垂直跟水平兩種模式的排版,
讓你有效的應用這兩種模式情境,
將你所需要的元件進行排版。

如何使用TimePickerDialog

情境

如果你想要讓使用者直接點選時間,
Android 提供了現成的元件讓使用者可以直接選取時間的工具,
這樣使用者就可以正確的選取時間了。

如何使用DatePickerDialog

情境

如果你想要讓你的某個元件加入目前的日期,
可是如果使用 EditText 讓使用者填入時間,那真的是非常的麻煩,
而且使用者的格式也會出錯,
只要利用 DatePickerDialog 就可以避免以上的麻煩。

如何使用Spinner(下拉式選單)

情境

如果你想要從一個集合內選出一個值, Spinner是一個很好用的工具,
它會提供一個下拉式選單, 顯示清單內所有的值讓使用者選擇。
例如:
午餐吃什麼?
有[雞腿飯, 魯肉飯, 排骨飯, 水餃, 陽春麵]這些選項提供使用者選擇,
但是使用者只能選一個選項, 這樣就是一個Spinner的應用了。

如何使用Toggle Button

情境

如果你想要做一個開關的按鈕,
也就是說點一下就顯示開啟再點一下就顯示關閉,
那麼你就可以使用ToggleButton。

如何使用RadioButton

情境

如果想要做一個單選的按鈕選單, 可以使用RadioButton這個元件。

如何使用CheckBox

情境

如果要使用一個勾選方塊
可以使用 CheckBox 這個元件
它會出現一個選取方塊讓使用者來進行勾選
一般來說它會是多選的模式
如果你想要用單選的方式來進行選取
那麼建議是使用 RadioButton 會比較恰當。

如何使用EditText

情境

如果想要讓使用者輸入一些文字
並且讓使用者能繼續修改或刪除的介面
又或者可以使用者輸入密碼並且顯示隱藏
EditText是一個很適合的元件。

如何使用Button



情境

Button 是 Android 剛入門一定會碰到的元件
根據使用者按下去
開發者寫出對應的反應
在外觀上就是一個單純的按鈕

書單-工具書




這篇書單是源自於我平時所讀過的書籍
讓我有所進步的一些書籍
但是不一定適用於每一個人
建議是到書局翻閱以後
再決定是否要購買

書單 - 休閒書



這篇書單是源自於我平時所讀過的書籍
讓我有所進步的一些書籍
但是不一定適用於每一個人
建議是到書局翻閱以後
再決定是否要購買

書單 - 觀念書



這篇書單是源自於我平時所讀過的書籍
讓我有所進步的一些書籍
但是不一定適用於每一個人

如何使用Java 8 Lambda 基礎概念

在 Java 8 Lambda 表示式中,很容易讓原本寫習慣 Java 匿名函式的開發者搞混,如下面程式碼所示,建立一個簡單的 Runnable。

如何寫一個檔案總管(FilesManager)-新增-刪除-修改

情境

如何寫一個檔案總管(FilesManager),其實少了很多功能,只是單純能夠看而已,所以我們要加上新增資料夾,刪除檔案,修改檔名的功能。

如何使用OkHttp

情境

OkHttp 是 Square 出產的一個 Open source project,是一個很有效率的Http連線的第三方,一些有名的連線套件都是基於這個第三方加入更多的功能,例如Volley和Retrofit。

如何解決Android Studio自動搜尋失效的問題

遇到一個問題,Android Studio一般可以找到某個類別被哪幾隻程式碼引用,這個功能突然之間失效了,無論更新或者重開都沒有用,
因此上網找了一下,
http://stackoverflow.com/questions/28859441/find-usage-of-id-not-working-in-android-studio-on-windows
發現這篇解決了我的困擾。

如何使用Runtime Permission

情境

當你在Android6.0以上的版本,加強了隱私權的重視,因此在操作APP上,就必須讓使用者自行勾選是否開放這些權限。

問題

如何使用Runtime Permission讓使用者勾選隱私權選項

完整程式碼

由於此次範例比較短, 因此將完整程式碼貼在此處
也可以透過Github下載來看
github

注意 : 你必須在Android 6.0以上的裝置才能使用這個章節的權限控制
package com.example.givemepass.permissiondemo;

import android.Manifest;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    private static final int MY_PERMISSIONS_REQUEST_READ_CONTACTS = 100;

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

        // Here, thisActivity is the current activity
        if (ContextCompat.checkSelfPermission(MainActivity.this,
                Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED ) {
            if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
                    Manifest.permission.CAMERA)) {
                new AlertDialog.Builder(MainActivity.this)
                        .setMessage("我真的沒有要做壞事, 給我權限吧?")
                        .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                ActivityCompat.requestPermissions(MainActivity.this,
                                        new String[]{Manifest.permission.CAMERA},
                                        MY_PERMISSIONS_REQUEST_READ_CONTACTS);
                            }
                        })
                        .setNegativeButton("No", new DialogInterface.OnClickListener() {
                            @Override
                            public void onClick(DialogInterface dialog, int which) {
                                finish();
                            }
                        })
                        .show();
            } else {

                ActivityCompat.requestPermissions(MainActivity.this,
                        new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE},
                        MY_PERMISSIONS_REQUEST_READ_CONTACTS);
            }
        }
    }
    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {

                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                } else {
                    finish();
                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return;
            }

            // other 'case' lines to check for other
            // permissions this app might request
        }
    }
}

在Android 6.0之後, 多了一個功能叫做Request Permission at Run Time.
https://developer.android.com/training/permissions/requesting.html
也就是說在執行程式的時候, 會跟user請求是否開放權限給APP,
如果使用者同意, APP才可以使用這些權限。
在新版的權限管理將權限分為兩大類:

  • 一般的權限
  • 危險的權限

https://developer.android.com/guide/topics/security/permissions.html#normal-dangerous
由這個連結可以看到危險的權限有哪些。
http://www.tablesgenerator.com/markdown_tables

權限群組(Permission Group) 權限(Permissions)
行事曆(CALENDAR) READ_CALENDAR
WRITE_CALENDAR
照相機(CAMERA) CAMERA
聯絡人(CONTACTS) READ_CONTACTS
WRITE_CONTACTS
GET_ACCOUNTS
位置(LOCATION) ACCESS_FINE_LOCATION
ACCESS_COARSE_LOCATION
麥克風(MICROPHONE) RECORD_AUDIO
電話(PHONE) READ_PHONE_STATE
CALL_PHONE
READ_CALL_LOG
WRITE_CALL_LOG
ADD_VOICEMAIL
USE_SIP
PROCESS_OUTGOING_CALLS
感應器(SENSORS) BODY_SENSORS
簡訊(SMS) SEND_SMS
RECEIVE_SMS
READ_SMS
RECEIVE_WAP_PUSH
RECEIVE_MMS
儲存(STORAGE) READ_EXTERNAL_STORAGE
WRITE_EXTERNAL_STORAGE

也就是說, 除了在androidMainfes上面宣告以外, 還要額外在程式內進行判斷,
否則APP拿不到危險權限, 則會有閃退的危機。
如果你想要操作權限控管, 那麼你必須在Gradle內設定target version為23或以上,
且minSdkVersion也必須在23或以上。

android {
    compileSdkVersion 23
    buildToolsVersion "23.0.1"

    defaultConfig {
        applicationId "com.example.givemepass.permissiondemo"
        minSdkVersion 23
        targetSdkVersion 23
        versionCode 1
        versionName "1.0"
    }
}

一開始可以使用checkSelfPermission來檢查是否擁有這個權限。

// Assume thisActivity is the current activity
int permissionCheck = ContextCompat.checkSelfPermission(thisActivity,
        Manifest.permission.WRITE_CALENDAR);

你會得到PackageManager.PERMISSION_GRANTED跟PackageManager.PERMISSION_DENIED兩種結果。
如果是PackageManager.PERMISSION_GRANTED,
代表你已經獲得使用者同意APP可以使用該權限,
否則就可以透過requestPermissions來跟使用者要求權限。

 ActivityCompat.requestPermissions(thisActivity,
     new String[]{Manifest.permission.READ_CONTACTS},
     MY_PERMISSIONS_REQUEST_READ_CONTACTS);

MY_PERMISSIONS_REQUEST_READ_CONTACTS是你自定義常數,
透過requestPermissions方法呼叫, 會出現這樣的一個畫面。

當使用者按下DENY or ALLOW, 就會回傳至onRequestPermissionsResult方法

第二個參數是你所要求的權限, 可以同時要求多個權限,

ActivityCompat.requestPermissions(MainActivity.this,
    new String[]{Manifest.permission.CAMERA,    Manifest.permission.READ_EXTERNAL_STORAGE },
    MY_PERMISSIONS_REQUEST_READ_CONTACTS);

那麼你就會看到權限Dialog會出現數字, 並且要按下同意數次。

而當使用者按下的結果會回傳至onRequestPermissionsResult方法,
只需透過requestCode 你自訂的參數, 以及permissions跟grantResults的順序,
就可以知道使用者同意了那些權限。

@Override
public void onRequestPermissionsResult(int requestCode,
        String permissions[], int[] grantResults) {
    switch (requestCode) {
        case MY_PERMISSIONS_REQUEST_READ_CONTACTS: {
            // If request is cancelled, the result arrays are empty.
            if (grantResults.length > 0
                && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                // permission was granted, yay! Do the
                // contacts-related task you need to do.

            } else {

                // permission denied, boo! Disable the
                // functionality that depends on this permission.
            }
            return;
        }

        // other 'case' lines to check for other
        // permissions this app might request
    }
}

如果你把permissions和grantResults印出來就會看到

permissions:["android.permission.CAMERA","android.permission.READ_EXTERNAL_STORAGE"]
grantResults:[0,0]

grantResults回來的結果如果0, 代表使用者同意權限,
如果回來的是-1, 代表被拒絕惹。

如果想知道APP是否有開啟權限,
可以到設定->應用程式->你的APP->PERMISSION

就可以看到APP內權限是否被打開

在Google官方網站的範例中,
使用shouldShowRequestPermissionRationale方法來跟使用者解釋更多需要使用這些權限的理由,
當使用者第一次看到授權畫面, 這個方法會先回傳false,
當使用者按下了拒絕, 而第二次再進入app的時候,
shouldShowRequestPermissionRationale就會回傳true,
讓你透過客製化的畫面來跟使用者強調拿到這個權限並沒有要做甚麼壞事:P

// Should we show an explanation?
if (ActivityCompat.shouldShowRequestPermissionRationale(thisActivity,
        Manifest.permission.READ_CONTACTS)) {

    // Show an expanation to the user *asynchronously* -- don't block
    // this thread waiting for the user's response! After the user
    // sees the explanation, try again to request the permission.

} else {

    // No explanation needed, we can request the permission.

    ActivityCompat.requestPermissions(thisActivity,
            new String[]{Manifest.permission.READ_CONTACTS},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);

    // MY_PERMISSIONS_REQUEST_READ_CONTACTS is an
    // app-defined int constant. The callback method gets the
    // result of the request.
}

可以透過這個方法進行這樣的修改

if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,
        Manifest.permission.CAMERA)) {
    new AlertDialog.Builder(MainActivity.this)
            .setMessage("我真的沒有要做壞事, 給我權限吧?")
            .setPositiveButton("OK", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    ActivityCompat.requestPermissions(MainActivity.this,
                            new String[]{Manifest.permission.CAMERA},
                            MY_PERMISSIONS_REQUEST_READ_CONTACTS);
                }
            })
            .setNegativeButton("No", new DialogInterface.OnClickListener() {
                @Override
                public void onClick(DialogInterface dialog, int which) {
                    finish();
                }
            })
            .show();
} else {

    ActivityCompat.requestPermissions(MainActivity.this,
            new String[]{Manifest.permission.CAMERA, Manifest.permission.READ_EXTERNAL_STORAGE},
            MY_PERMISSIONS_REQUEST_READ_CONTACTS);
}

如此一來, 使用者可以決定是否給權限,
則無法操作某些功能或者整個app無法操作(當然使用者經驗會變差)

參考
https://developer.android.com/training/permissions/requesting.html#perm-request
https://developer.android.com/guide/topics/security/permissions.html
http://android-developers.blogspot.tw/2015/08/building-better-apps-with-runtime.html

如何寫一個檔案總管(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