SaveData-android储存数据
文章目录
简述
对于一个App而言,对数据的储存肯定是必不可少的,根据数据的不同,也应该使用不同的储存方式,就android而言,基础的有以下5种方式储存数据:
- SharedPreferences
- 写入文件中
- 数据库
- contentProvider
- 写入云端
一一讲解
一.SharedPreferences
- SharedPreferences是Android平台上一个轻量级的存储类,主要是保存一些常用的配置比如窗口状态,比如在Activity中重载窗口状态onSaveInstanceState保存一般使用SharedPreferences完成,它提供了Android平台常规的Long长 整形、Int整形、String字符串型的保存,它的本质是基于XML文件存储key-value键值对数据,其存储位置在/data/data/<包名>/shared_prefs目录下。
- 支持类型:boolean,int,float,long和String五种简单的数据类型
- 使用
Context context = MainActivity.this;
SharedPreferences sp = context.getSharedPreferences("sp", MODE_PRIVATE);//建议使用全局context来获取
SharedPreferences.Editor edit = sp.edit();
edit.putInt("A",1);
edit.putBoolean("B",true);
edit.putFloat("C",1.0f);
edit.putLong("D", 2L);
edit.putString("E","String");
edit.apply();//使用apply提交事务
二.写入文件
- Activity提供了openFileOutput()方法可以用于把数据输出到文件中,具体的实现过程与在J2SE环境中保存数据到文件中是一样的。
- 使用(这里可以参考java文件操作,后面附链接)
public void saveData(){
try {
FileOutputStream outputStream = this.openFileOutput("a.txt",Context.MODE_PRIVATE);
outputStream.write("A".getBytes());
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
penFileOutput()方法的第二参数用于指定操作模式,有四种模式,分别为:
Context.MODE_PRIVATE:为默认操作模式,代表该文件是私有数据,只能被应用本身访问,
在该模式下,写入的内容会覆盖原文件的内容,如果想把新写入的内容追加到原文件中。可以使用Context.MODE_APPEND
Context.MODE_APPEND:模式会检查文件是否存在,存在就往文件追加内容,否则就创建新文件。
Context.MODE_WORLD_READABLE和Context.MODE_WORLD_WRITEABLE用来控制其他应用是否有权限读写该文件。
MODE_WORLD_READABLE:表示当前文件可以被其他应用读取;
MODE_WORLD_WRITEABLE:表示当前文件可以被其他应用写入。
- 另外,在使用文件储存的时候一般写在sdCard内,这个还需要申请权限
三.数据库
1. SQLite轻量级数据库
1.1 简洁
SQLite是一款轻型的数据库,是遵守ACID的关联式数据库管理系统,它的设计目标是嵌入 式的,而且目前已经在很多嵌入式产品中使用了它,它占用资源非常的低,在嵌入式设备中,可能只需要几百K的内存就够了。它能够支持 Windows/Linux/Unix等等主流的操作系统,同时能够跟很多程序语言相结合,比如Tcl、PHP、Java、C++、.Net等,还有ODBC接口,同样比起 Mysql、PostgreSQL这两款开源世界著名的数据库管理系统来讲,它的处理速度比他们都快。
1.2 使用
这点就不写了,学习学习SQlite语句就差不多了,事实上,目前android应用上,这个已经几乎是不被使用了,可参考跳转至SQLite详解
2. Room数据库
目前的主流数据库之一,从greenDao演变而来
- 使用:
导包:
//room
def room_version="2.4.2"
implementation "androidx.room:room-runtime:$room_version"
annotationProcessor "androidx.room:room-compiler:$room_version"
//implementation "androidx.room:room-rxjava2:$room_version"
//implementation "androidx.room:room-rxjava3:$room_version"
//implementation "androidx.room:room-guava:$room_version"
//testImplementation "androidx.room:room-testing:$room_version"
//implementation "androidx.room:room-paging:2.5.0-alpha01"
第一步:创建映射实体类
创建实体类,这个实体类就是数据库映射的接受类,对应的是数据库的user表,可以将数据库的表结构映射成Java Bean。使用注解标记相应的功能,通过名字就可以非常清楚的知道。
@Entity 表结构实体
@PrimaryKey 主键
@ColumnInfo 列/字段信息
package com.example.singleton.age;
import androidx.room.ColumnInfo;
import androidx.room.Entity;
import androidx.room.PrimaryKey;
@Entity
public class Student{
@PrimaryKey
private int id;
@ColumnInfo
private String name;
@ColumnInfo
private int age;
}
第二步:创建Dao接口
创建我们的Dao接口,这种实现方式和Retrofit是非常相似的。其实最感觉的就是SQL语句。这里我们先只关系getAll这个方法就行,语句是最简单的"SELECT * FROM user"。
对应的注解也是非常容易理解,分别对应增删改查。
@ Query 查询
@ Delete 删除
@ Update 修改
@ Insert 插入
package com.example.singleton.age;
import androidx.room.Dao;
import androidx.room.Delete;
import androidx.room.Insert;
import androidx.room.Query;
import androidx.room.Update;
import java.util.List;
@Dao
public interface StudentDao {
@Insert
void insertStudent(Student student);
@Insert
void insertAllStudents(Student... students);
@Delete
boolean deleteStudent();
@Delete
boolean deleteAllStudents();
@Query("SELECT * FROM student")
List<Student> getAll();
@Query("SELECT * FROM Student WHERE id IN(:id)")
List<Student> getStudentById(int id);
@Update
void update(int id,Student student);
}
第三步:创建数据库抽象接口
需要继承RoomDatabase,通过@Database指定需要创建的表。还可以指定版本。
package com.example.singleton.age;
import androidx.room.Database;
import androidx.room.RoomDatabase;
@Database(entities = {StudentDao.class},version = 1)
public abstract class StudentDataBase extends RoomDatabase {
public abstract StudentDao studentDao();
}
第四步:调用数据库
StudentDataBase dataBase = Room.databaseBuilder(getApplicationContext(), StudentDataBase.class, "stu.db").build();
- 数据库迁移
自动迁移
Room,当字段有变化,按照前面的使用方法添加删除某字段,即可完成自升级,当然改了字段同时得加版本。
操作也很简单,如果两个版本之间自动迁移,需要在 @Database 注解中的 autoMigrations 参数中添加一个 @AutoMigration 注解即可。
如果 Room 发现迁移过程中有歧义,并且在未提供更多信息的时候无法制定确切的自迁移方案,在编译期间就会发生错误,这时开发者需要提供一个 AutoMigrationSpec 的实现。多数情况下,自迁移发生错误都是由下列的原因造成的。
删除或者重命名数据表名
删除或者重命名数据表的列名
对于这种编译错误,开发者可以定义一个 AutoMigrationSpec 对象,给Room准确地生成迁移路径提供必要的额外信息。在 RoomDatabase 内部定义一个 AutoMigrationSpec 实现类,并且用以下注解进行标注。
@DeleteTable:删除数据表 @RenameTable: 重命名数据表 @DeleteColumn:删除数据表中的列 @RenameColumn:重命名数据表中的列
在自动迁移数据库时使用 AutoMigrationSpec 实现类,只需要在 @AutoMigration 注解的 spec 参数中指定即可。如果应用需要在自动迁移完成之后做更多的操作,可以重写 onPostMigrate() 方法并在内部实现需要进行的操作,Room 会在自动迁移完成之后调用这个方法。如下示例所示:
//version升级为2
@Database(entities = {Student.class}, version = 2,autoMigrations = {@AutoMigration(from = 1,to = 2)})
public abstract class StudentDataBase extends RoomDatabase {
public abstract StudentDao studentDao();
static final Migration MIGRATION_1_2 = new Migration(1,2) {
@Override
public void migrate(@NonNull SupportSQLiteDatabase database) {
//执行sql语句,表示增加字段sex
database.execSQL("ALTER TABLE sex ADD COLUMN duration INTEGER NOT NULL DEFAULT 0");
}
};
}
相应的entities和Dao也需要做更改,具体可以参考数据库升级
注意: Room 自动迁移是基于新版和旧版生成的数据库架构的,如果 @Database 的 exportSchema 设置为 false,(这里为false,系app一开始就没规划好导致,故无法验证示例代码,若你们的版本是2.4.0以后的,可以是尝试下自动迁移带来的便利),或者没有提升Room的版本号就进行编译,自动迁移操作将会失败。
四.contentProvider
跳转至contentProvider使用
参考跳转至contentProvider
五.网络储存
这个比较简单,就不详细介绍。