首先聲明,這篇文章不是講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));
}
}