所有应用程序必然有数据的输入输出,Android也是一样的,Android应用程序的参数设置、运行状态数据这些都需要保存到外部存储器上,保证关机后数据不丢失,如下是几种Android常见的数据存储方式: SharedPreferences:适合保存少量数据(一些配置信息、积分之类);SQLite:一个真正轻量级数据库,没有后台进程,整个数据库就对应于一个文件,适合大量数据需要存储、访问的情况。下来详细来看看它们的用法。Android系统主要提供了3种方式用于简单地实现数据持久化功能,即文件存储、SharedPreferences存储以及SQLite数据库存储。
1.文件存储
文件存储是Android中最基本的一种数据存储方式,它不对存储的内容做任何的格式化处理,所有数据都是原封不动地保存到文件当中,比较适合用于存储一些简单的文本数据或二进制数据,不适合存储一些较为复杂的文本数据。
1.将数据存储到文件中
Context 类提供了openFileOutput()方法,用于将数据存储到指定的文件中。所有的文件默认都是存储在 /data/data/< packagename>/files 目录下的。
public void save(String inputText) { FileOutputStream out = null; BufferedWriter writer = null; try { // 两种模式,MODE_PRIVATE:默认私有,指定相同文件名则覆盖原文件内容;MODE_APPEND:指定相同文件名则追加内容。 // 其实还有MODE_WORLD_READABLE和MODE_WORLD_WRITEABLE两种模式,因为安全因素已经在 Android4.2中被弃用。 out = openFileOutput("data", Context.MODE_PRIVATE); writer = new BufferedWriter(new OutputStreamWriter(out)); writer.write(inputText); } catch (IOException e) { e.printStackTrace(); } finally { try { if (writer != null) { writer.close(); } } catch (IOException e) { e.printStackTrace(); } } }123456789101112131415161718192021
2.从文件中读取数据
Context 类提供了openFileInput()方法,用于从文件中读取数据,只接受一个参数 文件名,系统会自动加载存储目录下的这个文件,并返回一个 FileInputStream 对象。
public String load() { FileInputStream in = null; BufferedReader reader = null; StringBuilder content = new StringBuilder(); try { in = openFileInput("data"); reader = new BufferedReader(new InputStreamReader(in)); String line = ""; while ((line = reader.readLine()) != null) { content.append(line); } } catch (IOException e) { e.printStackTrace(); } finally { if (reader != null) { try { reader.close(); } catch (IOException e) { e.printStackTrace(); } } } return content.toString(); }123456789101112131415161718192021222324
2.SharedPreferences存储
不同于文件存储,SharedPreferences是使用 键值对 的方式来存储数据的。
1.SharedPreferences接口
主要负责读取应用程序的Preferences数据,提供了如下常见方法来访问SharedPreferences中的key-value对:
boolean contains(String key) // 判断是否包含key对应的数据 abstract Map<String, ?> getAll() // 获取全部key-value对 boolean getXxx(String key, xxx defValue) // 获取指定key的value值1234
2.将数据存储到SharedPreferences中
要想使用SharedPreferences来存储数据,首先需要获取到SharedPreferences对象,Android主要提供了3种方法用于获取SharedPreferences对象:
1)Context 类中的 getSharedPreferences()方法; 2)Activity 类中的 getPreferences()方法; 3)PreferenceManager 类中的 getDefaultSharedPreferences()方法。1234
SharedPreferences数据总是以xml格式存储在 /data/data/< packagename>/shared_prefs 目录下的。
// SharedPreferences接口本身没有写入数据的能力,而是通过内部接口,调用edit()方法即获取Editor对象SharedPreferences.Editor editor = getSharedPreferences("data", MODE_PRIVATE).edit(); editor.putString("name", "USER_NAME"); editor.putInt("age", 25); editor.apply(); // 除此之外,Editor对象还包含clear()和remove(String key)等方法12345
3.从SharedPreferences中读取数据
SharedPreferences pref = getSharedPreferences("data", MODE_PRIVATE); String name = pref.getString("name", "");int age = pref.getInt("age", 0);123
3.SQLite数据库存储
SQLite是一个嵌入式的数据库引擎,适用于资源有限的设备上适量存取数据(SQLite数据库只是一个文件)。SQLiteDatabase表示一个数据库(底层是一个数据库文件),Android通过SQLiteDatabase对象来管理、操作数据库。
1.创建SQLite数据库
SQLiteDatabaseHelper类可用于管理数据库的创建和版本更新,SQLiteDatabaseHelper包含如下常用方法:
getReadableDatabase() // 以读写的方式打开数据库对应的SQLiteDatabase对象 getWritableDatabase() // 以写的方式打开数据库对应的SQLiteDatabase对象 onCreate(SQLiteDatabase db) // 第一次创建回调 onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) // 当数据库版本更新时回调 close() // 关闭所有打开的SQLiteDatabase123456
继承SQLiteOpenHelper,创建MyDatabaseHelper数据库帮助类:
public class MyDatabaseHelper extends SQLiteOpenHelper { /** * integer表示整型,real表示浮点型,text表示文本类型,blob表示二进制类 * primary key表示将id设为主键,并用auto_increment键字表示id是自增长的 */ private static final String CREATE_TABLE_PERSON = "create table person(" + "id integer primary key autoincrement," + "name text," + "age integer)"; private Context mContext; /** * 构造方法 * * @param context 上下文 * @param name 数据库名,创建数据库时使用的就是这里的名称 * @param factory 允许我们在查询数据时返回一个自定义的Cursor,一般传入null * @param version 数据库版本号 */ public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); mContext = context; } /** * 创建数据库 * * @param db */ @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_TABLE_PERSON); } /** * 升级数据库 * * @param db * @param oldVersion * @param newVersion */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }12345678910111213141516171819202122232425262728293031323334353637383940414243
然后就可以在应用程序中创建数据库了:
MyDatabaseHelper dbHelper = new MyDatabaseHelper(this, "person.db", null, 1); dbHelper.getWritableDatabase();12
升级数据库只需要将版本号增加,然后 onUpgrade() 方法就可以被执行了。
2.SQLite数据库的增删改查
我们对数据库的操作无非4种:CRUD:
C Create 添加 insert R Retrieve 查询 select U Update 更新 update D Delete 删除 delete12345
首先创建数据库表的实体类PersonBean:
public class PersonBean { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }12345678910111213141516
前面我们知道,调用 SQLiteOpenHelper 的 getReadableDatabase() 或 getWritableDatabase() 方法可以用于创建和升级数据库的,不仅如此,这两个方法还都会返回一个 SQLiteDatabase 对象,借助这个对象就可以对数据进行 CRUD 操作了。
SQLiteDatabase db = dbHelper.getWritableDatabase();1
接下来将数据库person表的增删改查操作封装起来,如下PersonDB:
public class PersonDB { private MyDatabaseHelper dbHelper; public PersonDB(Context context){ dbHelper = new MyDatabaseHelper(context, "person.db", null, 1); } /** * 增 */ public boolean add(PersonBean bean){ SQLiteDatabase db = dbHelper.getWritableDatabase(); ContentValues values = new ContentValues(); values.put("name", bean.getName()); values.put("age", bean.getAge()); /** * 执行插入,返回值(如果插入成功将插入成功的行号返回,失败返回-1) * table: 表名 * nullColumnHack: 一般传null * values: 表中添加的一行的数据内容, ContentValues以Map封装 */ long result = db.insert("person", "null", values); // 内部在拼装sql语句 // 关闭数据库 db.close(); if (result == -1) { return false; } return true; } /** * 删 */ public int delete(String name){ SQLiteDatabase db = dbHelper.getWritableDatabase(); /** * table: 表名 * whereClause: 删除条件 * whereArgs: 删除条件占位符的参数 * 返回值是: 成功删除了多少行 */ int result = db.delete("person", "name = ?", new String[]{name}); // 关闭数据库 db.close(); return result; } /** * 改 */ public int update(PersonBean bean){ SQLiteDatabase db = dbHelper.getWritableDatabase(); /** * table: 表名 * values: 更改字段的内容, 以map封装 * whereClause: 更新条件 * whereArgs: 更新条件占位符的参数 * sql: update person set age=18 where name='zhangsan'; */ ContentValues values = new ContentValues(); values.put("age", bean.getAge()); // 返回的值: 成功修改了多少行 int result = db.update("person", values, "name = ?", new String[]{bean.getName()}); // 关闭数据库 db.close(); return result; } /** * 查 */ public PersonBean query(String name){ SQLiteDatabase db = dbHelper.getReadableDatabase(); PersonBean bean = new PersonBean(); /** * table: 指定查询的表名 * columns: 指定查询的列名(null:查询所有) * selection: 指定where的约束条件 * selectionArgs: 为where中的占位符提供具体的值 * groupBy: 指定需要group by的列 * having: 对group by后的结果进一步约束 * orderBy: 指定查询结果的排序方式 */ Cursor cursor = db.query("person", new String[]{"id","name","age"}, "name = ?", new String[] {name}, null, null, "id desc"); /** * 判断结果集中是否有数据 */ if(cursor != null && cursor.getCount() >0){ // 循环遍历结果集获取结果集的内容 while(cursor.moveToNext()){ // 获取这一行上所有的数据内容 int id = cursor.getInt(0); bean.setName(cursor.getString(1)); bean.setAge(Integer.parseInt(cursor.getString(2))); } } // 关闭数据库 db.close(); return bean; } }12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
到此我们就可以通过创建PersonDB的实例,调用该实例的方法来增删改查数据库person表了:
PersonDB personDB = new PersonDB(context);// 增PersonBean bean = new PersonBean(); bean.setName("zhangsan"); bean.setAge(20); personDB.add(bean);// 删personDB.delete("zhangsan");// 改PersonBean bean = new PersonBean(); bean.setName("zhangsan"); bean.setAge(25); personDB.update(bean);// 查PersonBean bean = personDB.query("zhangsan");123456789101112131415
4.使用SQL操作数据库
首先打开数据库对应的 SQLiteDatabase 对象:
MyDatabaseHelper dbHelper = new MyDatabaseHelper(context, "person.db", null, 1); SQLiteDatabase db = dbHelper.getWritableDatabase();12
然后我们就可以直接使用 SQL语句 操作数据库:
// 增db.execSQL("insert into person (name ,age) values (?, ?)", new String[]{"wangwu","26"});// 删db.execSQL("delete from person where age>?", new String[]{"20"});// 改db.execSQL("update person set age=? where name=?", new String[]{"19", "wangwu"});// 查db.rawQuery("select * from person", null);12345678
5.使用数据库开源库操作数据库
现在公司里的代码非常强调稳定性,而我们自己写出的代码往往结构越复杂就越容易出现问题,相反,开源项目的代码都是经过时间验证的,通常比我们自己的代码要稳定的多。因此,现在很多公司为了追求开发效率以及项目的稳定性,都会选择使用开源库。
数据库开源库 | 说明 | 地址 |
---|---|---|
DBFlow | 一个基于AnnotationProcessing(注解处理器)的强大、健壮同时又简单的ORM框架 | https://github.com/Raizlabs/DBFlow |
OrmLite | JDBC和Android的轻量级ORM java包 | https://github.com/j256/ormlite-android |
Sugar | 用超级简单的方法处理Android数据库 | https://github.com/satyan/sugar |
GreenDao | 一种轻快地将对象映射到SQLite数据库的ORM解决方案 | https://github.com/greenrobot/greenDAO |
ActiveAndroid | 以活动记录方式为Android SQLite提供持久化 | https://github.com/pardom/ActiveAndroid |
SQLBrite | SQLiteOpenHelper和ContentResolver的轻量级包装 | https://github.com/square/sqlbrite |
Realm | 移动数据库:一个SQLite和ORM的替换品 | https://github.com/realm/realm-java |