Android 架構:使用枚舉重新設計緩存目錄的構建

首先聲明,這篇文章不是講getCacheDir()、getFilesDir()、getExternalFilesDir()、getExternalCacheDir()等等文件目錄的存放位置,及使用方法的。

本文章,主要是想說下通過枚舉來管理緩存目錄(就是上面那麼目錄),是否比我們常用的常量管理緩存目錄更有優勢。

我們先看下Android下的緩存目錄
在這裏插入圖片描述
上面就是一般,我們需要用的一些緩存數據的目錄,比如配置文件,廣告,數據緩存等等。



通常情況下,在管理緩存數據的目錄結構的時候,我是怎麼操作的呢。

  • 1,首先創建一個路徑管理類
  • 2,然後,創建緩存目錄的常量。比如,adsPath=rootPath+"/ads/";
  • 3,使用時候,判斷初始化,把路徑引用過去。save(adsPath+xx.png)

這樣做有什麼不好的地方呢?

  • 1,初始化緩存目錄不方面,每次用的時候,都需要判斷是否創建。
  • 2,到處引用路徑,如果管理不好,想要修改的話,會是個災難。
  • 3,緩存文件,有被修改的可能。如果,有人沒有把路徑寫到這個類裏面呢?

下面,我們嘗試使用枚舉來管理緩存的路徑,看看是否更優雅,更有優勢呢。

當然,Android不建議使用枚舉,因爲枚舉的每個變量其實,都會生成一個對象屬性,並且還會有一個包換所有屬性的對象數組。這樣,相比與其他常量來說會帶來更大的內存消耗。但是,使用枚舉來管理,也有它的優勢。(不然,還寫啥呢…)

使用枚舉有很多優勢:

  • 安全
  • 構造方法私有
  • 管理,操作方便

比如,多賬號登陸,每個賬號下的緩存文件夾的功能差不多,圖片,用戶信息等。
在這裏插入圖片描述

這樣的話,通過常量的方式來管理緩存目錄,就需要不斷的拼接字符串,來實現每個賬號下的緩存目錄,既不方便,也容易出錯。

下面,就通過枚舉來設計一個緩存文件夾管理的架構。看看是不是比我們常用的方式,更方便呢?

創建步驟:

1,創建一個通用的緩存文件目錄

一般來說,圖片緩存,數據緩存都是我們常用的,我們就添加這兩個緩存目錄

/**
 * cache中緩存的文件路徑
 */
public enum CommonCacheFile {
  /**
   * cache的圖片文件路徑。
   */
  CACHE_IMAGE("/common/image/"),
  /**
   * 文件的緩存路徑
   */
  CACHE_FILE("/common/file/");


  private String path;

  CommonCacheFile(String path) {
    this.path = path;
  }

  public String getValue() {
	//緩存的根目錄+緩存的相對路徑
    return SDCardUtils.getAppCacheFile(false) + path;
  }
}

這個枚舉,保存的都是我們緩存的相對路徑。通過getValue()方法,來獲取絕對路徑。這樣,控制我們的緩存路徑是不是看着更加直觀呢。

下面,我們爲多賬號登陸也設計一個枚舉類。

2,創建每個賬號下的緩存路徑

有時候,我們需要設計多賬號的緩存目錄,每個賬號下的緩存目錄結構,基本是一樣的。
這個時候,如果使用常量,是不是就沒有那麼方便了。

我們創建一個枚舉類來實現。


public enum UserFile {
  /**
   * 用戶信息路徑
   */
  fileUserInfo("/userInfo/");

  private String value;

  UserFile(String path) {
    this.value = path;
  }

  public String getValue() {
	//這裏,我們模擬一個userId(12345)。
    return SDCardUtils.getAppSubFile(false, "12345") + value;
  }
}

通過上面的枚舉,我們只要動態替換了"12345",就達到了多賬號,緩存目錄的創建。
相當於根目錄+userId+緩存目錄相對路徑

緩存目錄的枚舉創建好了之後,我們就需要在進入APP的時候,把我們的文件夾都初始化。
這樣,也就避免了我們每次使用的時候需要判斷的缺點。

3,創建初始化緩存目錄類

我們剛進入APP的時候,就把我們需要的緩存文件目錄都初始化。
這樣的好處:

  • 1,不用每次使用的時候,都需要判斷是否初始化。
  • 2,如果忘了初始化,就會造成IO異常。
public class FileEngine {

  public static void init(Context applicationContext) {
    SDCardUtils.init(applicationContext);
    //通用的緩存目錄 枚舉 。通過values()獲取所有的緩存目錄
    CommonCacheFile[] cacheFiles = CommonCacheFile.values();
	//用戶下的緩存目錄 枚舉
    UserFile[] userFiles = UserFile.values();

    List<String> path = new ArrayList<>();
    //把所有路徑,都放到集合
	for (CommonCacheFile cacheFile : cacheFiles) {
		
      path.add(cacheFile.getValue());
    }
    for (CommonFile cacheFile : files) {
      path.add(cacheFile.getValue());
    }
      path.add(cacheFile.getValue());
    }
	//創建所有的緩存文件目錄
    for (String p : path) {
      initDir(new File(p));
    }
  }

  private static boolean initDir(File dir) {
    return FileUtils.createDir(dir);
  }
}

這裏,我們通過枚舉的values()方法,拿到所有的緩存目錄的集合,然後,全部初始化。以後,我們枚舉如果添加新的緩存目錄,這裏也不需要改動。

4,初始化緩存目錄及效果

這裏,我們就找個Activity初始化,看下效果。


public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
	//這樣,我們的緩存目錄就初始化好了
    FileEngine.init(getApplicationContext());
  }
}

這裏,我們通過一行代碼,所有需要的緩存目錄就都初始化好了,是不是很簡單。

到這裏,我們的APP的緩存目錄管理,就做完了。

通過枚舉來管理緩存目錄,確實比常量要消耗更多的內存。但是,這樣我們可以更加直觀的管理緩存,操作上也方便很多,尤其在多賬號的時候,作用更明顯。

下面看下效果

在這裏插入圖片描述
這裏,我們就看到了,我們調用初始化方法後。我們的common緩存跟賬戶12345下面的userInfo緩存目錄就已經創建好了。

如果,我們想實現多賬號的緩存目錄管理的話,我們只需要動態修改UserFile枚舉裏的 12345就可以達到目的了。

public enum UserFile {
  /**
   * 用戶信息路徑
   */
  fileUserInfo("/userInfo/");

  private String value;

  UserFile(String path) {
    this.value = path;
  }

  public String getValue() {
    return SDCardUtils.getAppSubFile(false, "12345") + value;
  }
}

只需要動態替換掉 12345這個賬號,就會在對應賬號下創建緩存目錄了。

這樣的多賬號緩存設計,是不是更優雅呢。

通過枚舉實現緩存目錄的管理,到這裏就完成了。

5,其他的工具類

FileUtil,文件工具類

public class FileUtils {

  public static boolean createDir(File dir) {
    if (dir == null) {
      return false;
    }
    if (checkFileExist(dir)) {
      return true;
    }
    return makeDir(dir);
  }

  private static boolean checkFileExist(File file) {
    return file != null && file.exists();
  }

  private static boolean makeDir(File dir) {
    if (dir.exists() && !dir.isFile()) {
      return true;
    }
    return dir.mkdirs();
  }

}

權限工具類

public class PermissionUtils {

    private static volatile PermissionUtils sInstance;

    public static final String[] PERMISSIONS_STORAGE = {
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE};

    private PermissionUtils() {
    }

    public static PermissionUtils getsInstance() {
        if (sInstance == null) {
            sInstance = new PermissionUtils();
        }
        return sInstance;
    }

    public boolean checkPermission(Context context, String... permissions) {

        for (String permission : permissions) {
            // 判斷當前該權限是否允許
            if (ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED) {
                return false;
            }
        }

        return true;
    }

    /**
     * 判斷是否需要動態申請權限
     */
    public static boolean needRequestPermission() {
        return Build.VERSION.SDK_INT >= 23;
    }
}

SD卡工具類,獲取根目錄


public class SDCardUtils {

  private static Context context;

  public static void init(Context application) {
    context = application;
  }


  /**
   * 獲取app 的file
   */
  public static String getAppFile(boolean internal) {
    if (internal) {
      return getAppInternalDir();
    }
    return getAppExternalDir();
  }

  /**
   * 獲取app 的cache File
   */
  public static String getAppCacheFile(boolean internal) {
    if (internal) {
      return getAppInternalCacheDir();
    }
    return getAppExternalCacheDir();
  }

  /**
   * 這裏是提供 根目錄下的二級目錄
   */
  public static String getAppSubFile(boolean internal, String name) {
    return getAppFile(internal) + File.separator + "liu" + File.separator + name + File.separator;
  }

  public static String getAppInternalDir() {
    return context.getFilesDir().getPath();
  }

  public static String getAppInternalCacheDir() {
    return context.getCacheDir().getPath();
  }

  public static String getAppExternalDir() {
    String path = "";
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
        && hasSDCardPermission()) {
      File fileDir = context.getExternalFilesDir(null);
      if (fileDir != null) {
        path = fileDir.getPath();
      } else {
        fileDir = context.getFilesDir();
        if (fileDir != null) {
          path = fileDir.getPath();
        }
      }
    }
    return path;
  }

  public static String getAppExternalCacheDir() {
    String path = "";
    if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)
        && hasSDCardPermission()) {
      File fileDir = context.getExternalCacheDir();
      if (fileDir != null) {
        path = fileDir.getPath() ;
      } else {
        fileDir = context.getFilesDir();
        if (fileDir != null) {
          path = fileDir.getPath();
        }
      }
    }
    return path;
  }


  public static boolean hasSDCardPermission() {
    return (!PermissionUtils.needRequestPermission()
        || PermissionUtils.getsInstance()
        .checkPermission(context, PermissionUtils.PERMISSIONS_STORAGE));
  }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章