在Android開發中,存儲(Storage)的方式根據具體的需求不同而不同,例如數據對應用程式是私有的還是其他應用程式(和用戶)可以訪問的,以及保存數據需要多大的空間。 ...
概述
在Android開發中,存儲(Storage)的方式根據具體的需求不同而不同,例如數據對應用程式是私有的還是其他應用程式(和用戶)可以訪問的,以及保存數據需要多大的空間。
存儲分類
主要的存儲方式有以下幾種(本文主要涉及前三種):
- Shared Preferences:以鍵值對( key-value pairs)的方式存儲在程式內部;
- Internal Storage:將數據保存在設備記憶體中;
- External Storage:將公有數據保存在外部存儲中(SD卡);
- SQLite Databases:保存結構化數據到私有資料庫中;
- Network Connection:通過網路伺服器,將數據存儲在web上。
涉及知識點
涉及的知識點如下:
- SharedPreferences 共用目錄介面,通過Context中的getSharedPreferences進行實例化。
- SharedPreferences.Editor 共用目錄編輯器,需要以commit進行保存。
- FileOutputStream 文件輸出流,用write方法將數據保存文件。
- FileInputStream 文件輸入流,用於讀取文件的內容,通過Context中的openFileInput進行實例化,用read方法進行讀取內容。
- deleteFile Context中的方法,刪除指定路徑的文件
- Environment.getExternalStorageDirectory() 獲取外部存儲的根目錄。
- Environment.getExternalStorageState() 獲取外部存儲卡的狀態。
- File.separator 文件路徑分割符,用斜杠(/)進行表示。
- BitmapFactory.decodeResource(getResources(), R.drawable.bg) 通過資源文件實例化對象。
- BitmapFactory.decodeFile(imgFile.getAbsolutePath() 通過具體文件的路徑實例化對象。
- File 文件對象,mkdirs() 創建多層目錄 mkdirs創建單個目錄,exists() 判斷文件或目錄是否存在,createNewFile() 創建新文件。
Shared Preferences
此種方式,只能保存簡單的數據類型如下圖所示:
代碼如下:
1 /** 2 * SharedPreferences保存 3 * @param v 4 */ 5 public void sharedSave(View v){ 6 String name=etName.getText().toString().trim(); 7 String age=etAge.getText().toString().trim(); 8 if(TextUtils.isEmpty(name)||TextUtils.isEmpty(age)){ 9 return; 10 } 11 //構造一個編輯器----筆 12 SharedPreferences.Editor editor = sp.edit(); 13 //數據的存儲---只能存儲簡單的數據 14 editor.putString("name",name); 15 editor.putString("age",age); 16 //提交--保存 17 editor.commit(); 18 //清空 19 etName.setText(""); 20 etAge.setText(""); 21 } 22 23 /** 24 * SharedPreferences讀取 25 */ 26 public void sharedRedo(View v){ 27 String name=sp.getString("name",""); 28 String age=sp.getString("age",""); 29 etName.setText(name); 30 etAge.setText(age); 31 }
Internal Storage
將數據內容轉換為位元組的方式保存在文件中,如下圖所示:
代碼如下:
1 /** 2 * 內部保存 3 * @param v 4 */ 5 public void internalSave(View v) { 6 String name = etName.getText().toString().trim(); 7 String age = etAge.getText().toString().trim(); 8 if (TextUtils.isEmpty(name) || TextUtils.isEmpty(age)) { 9 return; 10 } 11 12 try { 13 String content = "這是我的姓名:" + name + "這是我的年齡:" + age; 14 FileOutputStream fos = openFileOutput(sname, MODE_PRIVATE); 15 fos.write(content.getBytes()); 16 fos.close(); 17 etName.setText(""); 18 etAge.setText(""); 19 } catch (IOException e) { 20 e.printStackTrace(); 21 } 22 } 23 24 /** 25 * 內部讀取 26 * @param v 27 */ 28 public void internalRedo(View v) { 29 try { 30 FileInputStream fis = openFileInput(sname); 31 byte[] buffer = new byte[fis.available()]; 32 fis.read(buffer); 33 fis.close(); 34 String content = new String(buffer); 35 Toast.makeText(this, content, Toast.LENGTH_SHORT).show(); 36 } catch (IOException e) { 37 e.printStackTrace(); 38 } 39 } 40 41 /** 42 * 刪除文件 43 * @param v 44 */ 45 public void internalDel(View v){ 46 boolean del=deleteFile(sname); 47 if(del){ 48 Toast.makeText(this, "刪除成功", Toast.LENGTH_SHORT).show(); 49 }else{ 50 Toast.makeText(this, "刪除失敗", Toast.LENGTH_SHORT).show(); 51 } 52 }
External Storage
在外部存儲中,需要在AndroidManifest.xml中配置相關的讀寫許可權,如下所示:
1 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> 2 <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 3 <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
保存在SD卡中,如下圖所示:
代碼如下:
1 /** 2 * 外部存儲 3 * @param v 4 */ 5 public void externalSave(View v) { 6 7 try { 8 Log.i(TAG, "externalSave: 開始"); 9 Bitmap img = BitmapFactory.decodeResource(getResources(), R.drawable.bg); 10 ByteArrayOutputStream bass = new ByteArrayOutputStream(); 11 img.compress(Bitmap.CompressFormat.JPEG, 100, bass); 12 img.recycle(); 13 Log.i(TAG, "externalSave: saveImg"); 14 boolean saveOk = saveImg("dog.jpg", bass.toByteArray()); 15 Log.i(TAG, "externalSave: saveImg:"+saveOk); 16 if (saveOk) { 17 Toast.makeText(this, "保存成功", Toast.LENGTH_SHORT).show(); 18 } 19 bass.close(); 20 Log.i(TAG, "externalSave: 結束"); 21 } catch (IOException e) { 22 e.printStackTrace(); 23 Log.i(TAG, "externalSave: 異常"+e.getMessage()); 24 } 25 } 26 27 /** 28 * 外部讀取 29 * @param v 30 */ 31 public void externalRedo(View v) { 32 if (!isMounted()) { 33 return; 34 } 35 try { 36 Bitmap img = readImg("dog.jpg"); 37 iv01.setImageBitmap(img); 38 } catch (Exception e) { 39 e.printStackTrace(); 40 } 41 } 42 43 private boolean saveImg(String fileName,byte[] data){ 44 Log.i(TAG, "saveImg: 開始"); 45 if(!isMounted()){ 46 Log.i(TAG, "saveImg: 掛載失敗"); 47 return false; 48 } 49 Log.i(TAG, "saveImg: 路徑:"+storedPath); 50 File dir=new File(storedPath); 51 if(!dir.exists()){ 52 boolean f= dir.mkdirs(); 53 if(f){ 54 Log.i(TAG, "saveImg: 創建目錄成功:"+storedPath); 55 }else{ 56 Log.i(TAG, "saveImg: 創建目錄失敗:"+storedPath); 57 } 58 } 59 Log.i(TAG, "saveImg: 判斷路徑:ok"); 60 try { 61 File file=new File(storedPath,fileName); 62 if(file.exists()){ 63 Log.i(TAG, "saveImg: 判斷文件:1"); 64 file.delete(); 65 } 66 Log.i(TAG, "saveImg: 判斷文件:2"); 67 file.createNewFile(); 68 Log.i(TAG, "saveImg: 判斷文件:ok"); 69 FileOutputStream fos=new FileOutputStream(file); 70 fos.write(data); 71 fos.close(); 72 return true; 73 } catch (IOException e) { 74 e.printStackTrace(); 75 Log.i(TAG, "saveImg: 異常:"+e.getMessage()); 76 return false; 77 } 78 } 79 80 public Bitmap readImg(String fileName){ 81 if(!isMounted()){ 82 return null; 83 } 84 File imgFile=new File(storedPath,fileName); 85 if(imgFile.exists()){ 86 return BitmapFactory.decodeFile(imgFile.getAbsolutePath()); 87 } 88 return null; 89 } 90 91 private boolean isMounted(){ 92 String state=Environment.getExternalStorageState(); 93 return state.equals(Environment.MEDIA_MOUNTED); 94 }
備註
在進行外部存儲時,如果預設關閉了APP的存儲空間許可權,沒有前往設置開啟應用許可權,即使manifest中正常註冊許可權,該APP仍讓無法讀寫文件。調試日誌如下:
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
未開啟App的存儲許可權
04-02 21:21:59.173 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 開始
04-02 21:21:59.407 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:21:59.408 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 開始
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 路徑:/storage/emulated/0/hex/images
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判斷路徑:ok
04-02 21:21:59.412 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 判斷文件:2
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: saveImg: 異常:No such file or directory
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: saveImg:false
04-02 21:21:59.414 30863-30863/com.hex.demostorage I/DemoStorage: externalSave: 結束
開啟App的存儲許可權
04-02 21:22:48.519 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 開始
04-02 21:22:48.754 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg
04-02 21:22:48.755 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 開始
04-02 21:22:48.759 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 路徑:/storage/emulated/0/hex/images
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判斷路徑:ok
04-02 21:22:48.760 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判斷文件:2
04-02 21:22:48.761 31306-31306/com.hex.demostorage I/DemoStorage: saveImg: 判斷文件:ok
04-02 21:22:48.763 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: saveImg:true
04-02 21:22:48.787 31306-31306/com.hex.demostorage I/DemoStorage: externalSave: 結束
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
記錄學習,記錄成長!