編輯:關於Android編程
我們先來考慮這樣一個問題:
打開手機設置,選擇應用管理,選擇任意一個App,然後你會看到兩個按鈕,一個是清除緩存,另一個是清除數據,那麼當我們點擊清除緩存的時候清除的是哪裡的數據?當我們點擊清除數據的時候又是清除的哪裡的數據?讀完本文相信你會有答案。
在android開發中我們常常聽到這樣幾個概念,內存,內部存儲,外部存儲,很多人常常將這三個東西搞混,那麼我們今天就先來詳細說說這三個東西是怎麼回事?
內存,我們在英文中稱作memory,內部存儲,我們稱為InternalStorage,外部存儲我們稱為ExternalStorage,這在英文中本不會產生歧義,但是當我們翻譯為中文之後,前兩個都簡稱為內存,於是,混了。
那麼究竟什麼是內部存儲什麼是外部存儲呢?
首先我們打開DDMS,有一個File Explorer,如下:
這裡有三個文件夾需要我們重視,一個是data,一個是mnt,一個是storage,我們下面就詳細說說這三個文件夾。
data文件夾就是我們常說的內部存儲,當我們打開data文件夾之後(沒有root的手機不能打開該文件夾),裡邊有兩個文件夾值得我們關注,如下:
一個文件夾是app文件夾,還有一個文件夾就是data文件夾,app文件夾裡存放著我們所有安裝的app的apk文件,其實,當我們調試一個app的時候,可以看到控制台輸出的內容,有一項是uploading .....就是上傳我們的apk到這個文件夾,上傳成功之後才開始安裝。另一個重要的文件夾就是data文件夾了,這個文件夾裡邊都是一些包名,打開這些包名之後我們會看到這樣的一些文件:
1.data/data/包名/shared_prefs
2.data/data/包名/databases
3.data/data/包名/files
4.data/data/包名/cache
如果打開過data文件,應該都知道這些文件夾是干什麼用的,我們在使用sharedPreferenced的時候,將數據持久化存儲於本地,其實就是存在這個文件中的xml文件裡,我們App裡邊的數據庫文件就存儲於databases文件夾中,還有我們的普通數據存儲在files中,緩存文件存儲在cache文件夾中,存儲在這裡的文件我們都稱之為內部存儲。
外部存儲才是我們平時操作最多的,外部存儲一般就是我們上面看到的storage文件夾,當然也有可能是mnt文件夾,這個不同廠家有可能不一樣。
一般來說,在storage文件夾中有一個sdcard文件夾,這個文件夾中的文件又分為兩類,一類是公有目錄,還有一類是私有目錄,其中的公有目錄有九大類,比如DCIM、DOWNLOAD等這種系統為我們創建的文件夾,私有目錄就是Android這個文件夾,這個文件夾打開之後裡邊有一個data文件夾,打開這個data文件夾,裡邊有許多包名組成的文件夾。
說到這裡,我想大家應該已經可以分清楚什麼是內部存儲什麼是外部存儲了吧?好,分清楚之後我們就要看看怎麼來操作內部存儲和外部存儲了。
首先,經過上面的分析,大家已經明白了,什麼是內部存儲,什麼是外部存儲,以及這兩種存儲方式分別存儲在什麼位置,一般來說,我們不會自己去操作內部存儲空間,沒有root權限的話,我們也沒法操作內部存儲空間,事實上內部存儲主要是由系統來維護的。不過在代碼中我們是可以訪問到這個文件夾的。由於內部存儲空間有限,在開發中我們一般都是操作外部存儲空間,Google官方建議我們App的數據應該存儲在外部存儲的私有目錄中該App的包名下,這樣當用戶卸載掉App之後,相關的數據會一並刪除,如果你直接在/storage/sdcard目錄下創建了一個應用的文件夾,那麼當你刪除應用的時候,這個文件夾就不會被刪除。
經過以上的介紹,我們可以總結出下面一個表格:
一目了然,什麼是內部存儲,什麼是外部存儲。
如果按照路徑的特征,我們又可以將文件存儲的路徑分為兩大類,一類是路徑中含有包名的,一類是路徑中不含有包名的,含有包名的路徑,因為和某個App有關,所以對這些文件夾的訪問都是調用Context裡邊的方法,而不含有包名的路徑,和某一個App無關,我們可以通過Environment中的方法來訪問。如下圖:
大家看到,有包名的路徑我們都是調用Context中的方法來獲得,沒有包名的路徑,我們直接調用Environment中的方法獲得,那麼其中有兩個方法需要傳入一個String類型的參數,這個參數我們使用了Environment中的常量,參數的意思是我們要訪問這個路徑下的哪個文件夾,比如getExternalFilesDir方法,我們看看它的源碼:
/** * * @param type The type of files directory to return. May be null for * the root of the files directory or one of * the following Environment constants for a subdirectory: * {@link android.os.Environment#DIRECTORY_MUSIC}, * {@link android.os.Environment#DIRECTORY_PODCASTS}, * {@link android.os.Environment#DIRECTORY_RINGTONES}, * {@link android.os.Environment#DIRECTORY_ALARMS}, * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, * {@link android.os.Environment#DIRECTORY_PICTURES}, or * {@link android.os.Environment#DIRECTORY_MOVIES}. * * @return The path of the directory holding application files * on external storage. Returns null if external storage is not currently * mounted so it could not ensure the path exists; you will need to call * this method again when it is available. * * @see #getFilesDir * @see android.os.Environment#getExternalStoragePublicDirectory */ @Nullable public abstract File getExternalFilesDir(@Nullable String type);
它的注釋非常多,我這裡只列出其中一部分,我們看到,我們可以訪問files文件夾下的Music文件夾、Movies文件夾等等好幾種。
說到這裡,我想大家對內部存儲、外部存儲該有了一個清晰的認識了吧。我們在開發中,不建議往內部存儲中寫太多的數據,畢竟空間有限。外部存儲在使用的時候最好能夠將文件存放在私有目錄下,這樣有利於系統維護,也避免用戶的反感。
現在我們再來看看我們一開始提出的問題,當我們點擊清除數據的時候清除的是哪裡的數據呢?毫無疑問,當然是內部存儲目錄中相應的files和cache文件夾中的文件和外部存儲中相應的files和cache文件夾中的文件,至於這些文件夾的路徑我想你應該已經明白了。
好了,最後再送給大家一個文件操作工具類:
public class SDCardHelper { // 判斷SD卡是否被掛載 public static boolean isSDCardMounted() { // return Environment.getExternalStorageState().equals("mounted"); return Environment.getExternalStorageState().equals( Environment.MEDIA_MOUNTED); } // 獲取SD卡的根目錄 public static String getSDCardBaseDir() { if (isSDCardMounted()) { return Environment.getExternalStorageDirectory().getAbsolutePath(); } return null; } // 獲取SD卡的完整空間大小,返回MB public static long getSDCardSize() { if (isSDCardMounted()) { StatFs fs = new StatFs(getSDCardBaseDir()); long count = fs.getBlockCountLong(); long size = fs.getBlockSizeLong(); return count * size / 1024 / 1024; } return 0; } // 獲取SD卡的剩余空間大小 public static long getSDCardFreeSize() { if (isSDCardMounted()) { StatFs fs = new StatFs(getSDCardBaseDir()); long count = fs.getFreeBlocksLong(); long size = fs.getBlockSizeLong(); return count * size / 1024 / 1024; } return 0; } // 獲取SD卡的可用空間大小 public static long getSDCardAvailableSize() { if (isSDCardMounted()) { StatFs fs = new StatFs(getSDCardBaseDir()); long count = fs.getAvailableBlocksLong(); long size = fs.getBlockSizeLong(); return count * size / 1024 / 1024; } return 0; } // 往SD卡的公有目錄下保存文件 public static boolean saveFileToSDCardPublicDir(byte[] data, String type, String fileName) { BufferedOutputStream bos = null; if (isSDCardMounted()) { File file = Environment.getExternalStoragePublicDirectory(type); try { bos = new BufferedOutputStream(new FileOutputStream(new File( file, fileName))); bos.write(data); bos.flush(); return true; } catch (Exception e) { e.printStackTrace(); } finally { try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return false; } // 往SD卡的自定義目錄下保存文件 public static boolean saveFileToSDCardCustomDir(byte[] data, String dir, String fileName) { BufferedOutputStream bos = null; if (isSDCardMounted()) { File file = new File(getSDCardBaseDir() + File.separator + dir); if (!file.exists()) { file.mkdirs();// 遞歸創建自定義目錄 } try { bos = new BufferedOutputStream(new FileOutputStream(new File( file, fileName))); bos.write(data); bos.flush(); return true; } catch (Exception e) { e.printStackTrace(); } finally { try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return false; } // 往SD卡的私有Files目錄下保存文件 public static boolean saveFileToSDCardPrivateFilesDir(byte[] data, String type, String fileName, Context context) { BufferedOutputStream bos = null; if (isSDCardMounted()) { File file = context.getExternalFilesDir(type); try { bos = new BufferedOutputStream(new FileOutputStream(new File( file, fileName))); bos.write(data); bos.flush(); return true; } catch (Exception e) { e.printStackTrace(); } finally { try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return false; } // 往SD卡的私有Cache目錄下保存文件 public static boolean saveFileToSDCardPrivateCacheDir(byte[] data, String fileName, Context context) { BufferedOutputStream bos = null; if (isSDCardMounted()) { File file = context.getExternalCacheDir(); try { bos = new BufferedOutputStream(new FileOutputStream(new File( file, fileName))); bos.write(data); bos.flush(); return true; } catch (Exception e) { e.printStackTrace(); } finally { try { bos.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } return false; } // 保存bitmap圖片到SDCard的私有Cache目錄 public static boolean saveBitmapToSDCardPrivateCacheDir(Bitmap bitmap, String fileName, Context context) { if (isSDCardMounted()) { BufferedOutputStream bos = null; // 獲取私有的Cache緩存目錄 File file = context.getExternalCacheDir(); try { bos = new BufferedOutputStream(new FileOutputStream(new File( file, fileName))); if (fileName != null && (fileName.contains(".png") || fileName .contains(".PNG"))) { bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos); } else { bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos); } bos.flush(); } catch (Exception e) { e.printStackTrace(); } finally { if (bos != null) { try { bos.close(); } catch (IOException e) { e.printStackTrace(); } } } return true; } else { return false; } } // 從SD卡獲取文件 public static byte[] loadFileFromSDCard(String fileDir) { BufferedInputStream bis = null; ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { bis = new BufferedInputStream( new FileInputStream(new File(fileDir))); byte[] buffer = new byte[8 * 1024]; int c = 0; while ((c = bis.read(buffer)) != -1) { baos.write(buffer, 0, c); baos.flush(); } return baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { baos.close(); bis.close(); } catch (IOException e) { e.printStackTrace(); } } return null; } // 從SDCard中尋找指定目錄下的文件,返回Bitmap public Bitmap loadBitmapFromSDCard(String filePath) { byte[] data = loadFileFromSDCard(filePath); if (data != null) { Bitmap bm = BitmapFactory.decodeByteArray(data, 0, data.length); if (bm != null) { return bm; } } return null; } // 獲取SD卡公有目錄的路徑 public static String getSDCardPublicDir(String type) { return Environment.getExternalStoragePublicDirectory(type).toString(); } // 獲取SD卡私有Cache目錄的路徑 public static String getSDCardPrivateCacheDir(Context context) { return context.getExternalCacheDir().getAbsolutePath(); } // 獲取SD卡私有Files目錄的路徑 public static String getSDCardPrivateFilesDir(Context context, String type) { return context.getExternalFilesDir(type).getAbsolutePath(); } public static boolean isFileExist(String filePath) { File file = new File(filePath); return file.isFile(); } // 從sdcard中刪除文件 public static boolean removeFileFromSDCard(String filePath) { File file = new File(filePath); if (file.exists()) { try { file.delete(); return true; } catch (Exception e) { return false; } } else { return false; } } }
本文實例講述了android中Handle類的用法。分享給大家供大家參考。具體如下:當我們在處理下載或是其他需要長時間執行的任務時,如果直接把處理函數放Activity的
1.屬性動畫概述動畫一直是App增強用戶交互和用戶體驗的一個重要環節,特別是在某些提示場景或者廣告場景中,合理使用動畫可以給用戶帶來更加愉悅的使用體驗,因此我們很有必要掌
在用微信的時候,發現微信建立了自己的獨立賬戶管理,同時在聯系人中,可以直接點擊發送信息,查看朋友圈等功能,感覺挺方便了 然後就做了相關方面的調研,主要從兩個方面,進行了研
代碼中用的自定義常量 public static final int TYPE_Normal = 1; public static final int TYP