数据存储

1,000 阅读6分钟

如今大数据的时代,数据在我们生活中扮演的角色越来越重要了,我们使用的手机产生的大量数据,很好的反应了我们的生活习惯、作息规律、兴趣爱好等。接下来我们就来小谈一下 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详解

网络存储

网络存储就是调用接口得到返回值进行数据展示