一起學Android之Storage

来源:https://www.cnblogs.com/hsiang/archive/2019/04/02/10645965.html
-Advertisement-
Play Games

在Android開發中,存儲(Storage)的方式根據具體的需求不同而不同,例如數據對應用程式是私有的還是其他應用程式(和用戶)可以訪問的,以及保存數據需要多大的空間。 ...


概述

在Android開發中,存儲(Storage)的方式根據具體的需求不同而不同,例如數據對應用程式是私有的還是其他應用程式(和用戶)可以訪問的,以及保存數據需要多大的空間。

存儲分類

主要的存儲方式有以下幾種(本文主要涉及前三種):

  1. Shared Preferences:以鍵值對( key-value pairs)的方式存儲在程式內部;
  2. Internal Storage:將數據保存在設備記憶體中;
  3. External Storage:將公有數據保存在外部存儲中(SD卡);
  4. SQLite Databases:保存結構化數據到私有資料庫中;
  5. Network Connection:通過網路伺服器,將數據存儲在web上。

涉及知識點

涉及的知識點如下:

  1. SharedPreferences 共用目錄介面,通過Context中的getSharedPreferences進行實例化。
  2. SharedPreferences.Editor 共用目錄編輯器,需要以commit進行保存。
  3. FileOutputStream 文件輸出流,用write方法將數據保存文件。
  4. FileInputStream 文件輸入流,用於讀取文件的內容,通過Context中的openFileInput進行實例化,用read方法進行讀取內容。
  5. deleteFile Context中的方法,刪除指定路徑的文件
  6. Environment.getExternalStorageDirectory() 獲取外部存儲的根目錄。
  7. Environment.getExternalStorageState() 獲取外部存儲卡的狀態。
  8. File.separator 文件路徑分割符,用斜杠(/)進行表示。
  9. BitmapFactory.decodeResource(getResources(), R.drawable.bg) 通過資源文件實例化對象。
  10. BitmapFactory.decodeFile(imgFile.getAbsolutePath() 通過具體文件的路徑實例化對象。
  11. 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: 結束

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

記錄學習,記錄成長!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 本篇文章並非原創,只是看到其中內容講的非常好,搬過來,還望海涵。 原文鏈接地址:http://wpceo.com/user-database-table-design/ 說起用戶表,大概是每個應用/網站立項動工(碼農們)考慮的第一件事情。用戶表結構的設計,算是整個後臺架構的基石。如果基石不穩,待到後 ...
  • 索引模板就是將已經創建好的某個索引參數設置(settings)和索引映射(mapping)保存下來作為模板, 在創建新索引時, 指定使用某個模板就可以直接使用已經定義好的設置和映射. ...
  • Numpy 基礎操作¶ 以numpy的基本數據例子來學習numpy基本數據處理方法 主要內容有: 創建數組 數組維度轉換 數據選區和切片 數組數據計算 隨機數 數據合併 數據統計計算 In [1]: import numpy as np 創建一維數組¶ In [2]: data = np.arang ...
  • [20190402]關於semtimedop函數調用2.txt--//前幾天做了sql語句在mutexes上的探究.今天看看_mutex_wait_time設置很大的情況下是否semtimedop會喚醒.1.環境:SYS@book> @ hide mutexNAME DESCRIPTION DEFA ...
  • [20190402]對比_mutex_wait_scheme不同模式cpu消耗.txt--//前幾天做了sql語句在mutexes上的探究.今天對比不同_mutex_wait_scheme模式cpu消耗.1.環境:SYS@book> @ hide mutexNAME DESCRIPTION DEFA ...
  • 快捷鍵 ctrl+l 清屏 ctrl +a 回到行首 ctrl + e 回到行末 資料庫操作 進入資料庫 方式1 mysql -u用戶名 -p 密碼 直接輸入密碼,缺點,會暴露自己的密碼哦😝 方式2 mysql -u用戶名 -p 回車後輸入密碼 主要內容:查詢 1、查詢當前所有的資料庫 show ...
  • 文章大綱 一、OkHttp簡介二、OkHttp簡單使用三、OkHttp封裝四、項目源碼下載 一、OkHttp簡介 1. 什麼是OkHttp 一般在Java平臺上,我們會使用Apache HttpClient作為Http客戶端,用於發送 HTTP 請求,並對響應進行處理。比如可以使用http客戶端與第 ...
  • 文章大綱 一、什麼是RxJava二、為什麼要用RxJava三、RxJava使用詳解四、項目源碼下載五、參考文章 一、什麼是RxJava Rx(Reactive Extensions)是一個庫,用來處理事件和非同步任務,在很多語言上都有實現,RxJava是Rx在Java上的實現。簡單來說,RxJava就 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...