數據存儲


如今大數據的時代,數據在我們生活中扮演的角色越來越重要了,我們使用的手機產生的大量數據,很好的反應了我們的生活習慣、作息規律、興趣愛好等。接下來我們就來小談一下 Android 中的數據存儲的五種方式。

目錄

-SharedPreferences

-File

-SQLite

-ContentProvider

-網絡存儲

SharedPreferences

SharedPreferences 用於保存少量、數據格式簡單(字符串、基本類型)的數據,例如:App 的配置信息,鎖屏密碼等。保存基於 XML 文件存儲的 key-value 鍵值對數據,通常用來存儲一些簡單的配置信息。通過 DDMS 的 File Explorer 面板,展開文件瀏覽樹,很明顯 SharedPreferences 數據總是存儲在/data/data//shared_prefs 目錄下

Context.MODE_PRIVATE: 指定該 SharedPreferences 數據只能被本應用程序讀、寫。
Context.MODE_WORLD_READABLE: 指定該 SharedPreferences 數據能被其他應用程序讀,但不能寫。
Context.MODE_WORLD_WRITEABLE: 指定該 SharedPreferences 數據能被其他應用程序讀,寫

主要方法:
Editor putXXX(String key, @Nullable XXX value);//存入指定 key 的各種基本類型的數據
Editor remove(String key);//刪除指定 key 的數據
Editor clear();//清空所有數據
boolean commit();//提交數據
void apply();//提交數據

注:SharedPreference 相關修改使用 apply 方法進行提交會先寫入內存,然後異步寫入磁盤,commit 方法是直接寫入磁盤。如果頻繁操作的話 apply 的性能會優於 commit,apply 會將最後修改內容寫入磁盤。 但是如果希望立刻獲取存儲操作的結果,並據此做相應的其他操作,應當使用 commit。

存儲數據:

//創建一個 SharedPreferences.Editor 接口對象,madreain 表示要寫入的 XML 文件名,MODE_PRIVATE 讀寫操作
SharedPreferences.Editor editor = getSharedPreferences("madreain", MODE_PRIVATE).edit();
//將值放入文件
editor.putString("test", "存儲的值");
editor.apply();

獲取數據

SharedPreferences.Editor editor = getSharedPreferences("madreain", MODE_PRIVATE).edit();
String value = editor.getString("test");

一般這裏都會封裝 SharedPreference 的工具類,可參考SPUtils

File

Context 提供了兩個方法來打開數據文件裏的文件 IO 流 FileInputStream openFileInput(String name); FileOutputStream(String name , int mode),這兩個方法第一個參數 用於指定文件名,第二個參數指定打開文件的模式。

打開文件的模式有以下幾種:
MODE_PRIVATE:爲默認操作模式,代表該文件是私有數據,只能被應用本身訪問,在該模式下,寫入的內容會覆蓋原文件的內容。
MODE_APPEND:模式會檢查文件是否存在,存在就往文件追加內容,否則就創建新文件。
MODE_WORLD_READABLE:表示當前文件可以被其他應用讀取;
MODE_WORLD_WRITEABLE:表示當前文件可以被其他應用寫入。

Context 其他重要的相關方法:
getDir(String name , int mode):在應用程序的數據文件夾下獲取或者創建 name 對應的子目錄
File getFilesDir():獲取該應用程序的數據文件夾得絕對路徑
String[] fileList():返回該應用數據文件夾的全部文件

讀取文件相關代碼

public String read() {
        try {
            FileInputStream fileInputStream = openFileInput("madreain.txt");
            byte[] buffer = new byte[1024];
            int hasRead = 0;
            StringBuilder sb = new StringBuilder();
            while ((hasRead = fileInputStream.read(buffer)) != -1) {
                sb.append(new String(buffer, 0, hasRead));
            }

            fileInputStream.close();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

寫入文件相關代碼

public void write(String msg){
        if(msg == null) return;
        try {
            FileOutputStream fileOutputStream = openFileOutput("madreain.txt",MODE_APPEND);
            fileOutputStream.write(msg.getBytes());
            fileOutputStream.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

⚠️ 注意:
openFileOutput()方法的第一參數用於指定文件名稱,不能包含路徑分隔符“/” ,如果文件不存在,Android 會自動創建它。創建的文件保存在/data/data//files 目錄,如: /data/data/com.madreain.app/files/madreain.txt。 com.madreain.app 這裏是包名

sdcard 上的文件操作:
1.SD 卡的權限(模擬器:可通過 mksdcard 命令來創建虛擬存儲卡)

2.調用 Environment 的 getExternalStorageState()方法判斷手機上是否插了 sd 卡,且應用程序具有讀寫 SD 卡的權限,如下代碼將返回 true
Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)

3.調用 Environment.getExternalStorageDirectory()方法來獲取外部存儲器,也就是 SD 卡的目錄,或者使用"/mnt/sdcard/"目錄

4.使用 IO 流操作 SD 卡上的文件

讀取文件相關代碼

    private String read() {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            File file = new File(Environment.getExternalStorageDirectory()
                    .toString()
                    + File.separator
                    + DIR
                    + File.separator
                    + FILENAME);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            Scanner scan = null;
            StringBuilder sb = new StringBuilder();
            try {
                scan = new Scanner(new FileInputStream(file));
                while (scan.hasNext()) {
                    sb.append(scan.next() + "\n");
                }
                return sb.toString();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (scan != null) {
                    scan.close();
                }
            }
        } else {
            Toast.makeText(this, "讀取失敗,SD卡不存在!", Toast.LENGTH_LONG).show();
        }
        return null;
    }

寫入文件相關代碼

  private void write(String content) {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            File file = new File(Environment.getExternalStorageDirectory()
                    .toString()
                    + File.separator
                    + DIR
                    + File.separator
                    + FILENAME);
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            PrintStream out = null;
            try {
                out = new PrintStream(new FileOutputStream(file, true));
                out.println(content);
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (out != null) {
                    out.close();
                }
            }
        } else {
            Toast.makeText(this, "保存失敗,SD卡不存在!", Toast.LENGTH_LONG).show();
        }
    }

FileIO 的工具類,可參考FileIOUtils

SQLite

SQLite 是輕量級嵌入式數據庫引擎,它支持 SQL 語言,並且只利用很少的內存就有很好的性能。現在的主流移動設備像 Android、IOS 等都使用 SQLite 作爲複雜數據的存儲引擎,在我們爲移 動設備開發應用程序時,也許就要使用到 SQLite 來存儲我們大量的數據,所以我們就需要掌握移動設備上的 SQLite 開發技巧

通用方法

db.executeSQL(String sql);  
db.executeSQL(String sql, Object[] bindArgs);//sql語句中使用佔位符,然後第二個參數是實際的參數集 

增刪改查方法

db.insert(String table, String nullColumnHack, ContentValues values); 
db.delete(String table, String whereClause, String whereArgs); 
db.update(String table, Contentvalues values, String whereClause, String whereArgs);  
db.query(String table, String[] columns, String selection, String[] selectionArgs, String groupBy, String having, String orderBy);

執行數據庫的增刪改查操作前,我們得創建數據庫類

public class SqliteDBHelper extends SQLiteOpenHelper {

        //數據庫相關設置
        private static final String DATABASE_NAME = "madreain_db";//數據庫名字
        private static final int VERSION = 1;//數據庫版本號
        private static final String TABLE_NAME = "note";//數據庫表名 可創建多個表

        public SqliteDBHelper(Context context) {
            super(context, DATABASE_NAME, null, VERSION);
        }

        public SqliteDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
            super(context, name, factory, version);
        }

        /**
         * 數據庫第一次創建時調用
         * @param db
         */
        @Override
        public void onCreate(SQLiteDatabase db) {
            String strSQL = "create table " + TABLE_NAME + "(tid integer primary key autoincrement,title varchar(20),weather varchar(10),context text,publish date)";
            db.execSQL(strSQL);
        }

        /**
         * 數據庫版本號變化時調用
         * @param db
         * @param oldVersion
         * @param newVersion
         */
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

        }

    }

實際業務中,我們會創建一個Dao來封裝我們的業務方法

public class DiaryDao {

        private SqliteDBHelper sqliteDBHelper;
        private SQLiteDatabase db;

        // 重寫構造方法
        public DiaryDao(Context context) {
            this.sqliteDBHelper = new SqliteDBHelper(context);
            db = sqliteDBHelper.getWritableDatabase();
        }

        // 讀操作
        public String execQuery(final String strSQL) {
            try {
                // Cursor相當於JDBC中的ResultSet
                Cursor cursor = db.rawQuery(strSQL, null);
                // 始終讓cursor指向數據庫表的第1行記錄
                cursor.moveToFirst();
                // 定義一個StringBuffer的對象,用於動態拼接字符串
                StringBuffer sb = new StringBuffer();
                // 循環遊標,如果不是最後一項記錄
                while (!cursor.isAfterLast()) {
                    sb.append(cursor.getInt(0) + "/" + cursor.getString(1) + "/"
                            + cursor.getString(2) + "/" + cursor.getString(3) + "/"
                            + cursor.getString(4) + "#");
                    //cursor遊標移動
                    cursor.moveToNext();
                }
                db.close();
                return sb.deleteCharAt(sb.length() - 1).toString();
            } catch (RuntimeException e) {
                e.printStackTrace();
                return null;
            }
        }

        // 寫操作
        public boolean execOther(final String strSQL) {
            db.beginTransaction();  //開始事務
            try {
                db.execSQL(strSQL);
                db.setTransactionSuccessful();  //設置事務成功完成
                db.close();
                return true;
            } catch (RuntimeException e) {
                e.printStackTrace();
                return false;
            } finally {
                db.endTransaction();    //結束事務
            }

        }
    }

實際增刪改查操作

        //創建數據庫
        SqliteDBHelper sqliteDBHelper = new SqliteDBHelper(this);
        sqliteDBHelper.getWritableDatabase();
        //實例化
        DiaryDao diaryDao = new DiaryDao(this);
        // 增
        String strSQL = "insert into diary values(null,'" + "標題1" + "','" + "天氣" + "','" + "文章" + "','" + "時間" + "')";
        boolean flag = diaryDao.execOther(strSQL);
        // 刪
        strSQL = "delete from diary where tid = 1";
        flag = diaryDao.execOther(strSQL);
        // 改
        strSQL = "select * from diary order by publish desc";
        String data = diaryDao.execQuery(strSQL);
        // 查
        strSQL = "update diary set title = '標題1' where tid = 1";
        flag = diaryDao.execOther(strSQL);
        

推薦一下常用的第三方數據庫:OrmLite、GreenDao、LitePal、Realm、Afinal (可按照自己的需求去選擇相對應的第三方數據庫)

Android查看數據庫工具推薦:stethoAndroid-Debug-Database

ContentProvider

ContentProvider相關使用參考ContentProvider詳解

網絡存儲

網絡存儲就是調用接口得到返回值進行數據展示

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章