安卓提供了三种方式用于简单的数据持久化功能:文件储存,SharedPreference存储,数据库储存。
文件储存
用于保存一些简单的文本数据或二进制数据。
使用到的方法:Context类中提供了openFileOutput(String str,int a)方法 和 openFileInput(String str)方法
openFileOutput()方法:
文件默认的存储到data/data/<package name>/ files/目录下。
拥有两个参数 第一个是文件名 第二个是文件的操作方式字段。
文件的操作方式:
MODE_PRIVATE当指定同样文件名时会覆盖原文件中的内容
MODE_APPEND当该文件已存在时就往文件中追加内容,不会创建新文件
文件存储使用:java流
FileOutputStream out = openFileOutput("save", MODE_PRIVATE);
//方法得到的是一个FileOutputStream对象
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(out));
//用OutputStreamWriter输出流读写器包装输出流,再用缓冲流包装输出流。
writer.write(text);//调用读写器方法写入数据text
openFileIntput()方法:
FileInputStream in = openFileInput("save");
//方法得到的是一个FileInputStream对象
BufferedReader reader = new BufferedReader(new InputStreamReader(in));
//用InputStreamReader输入流读写器包装输出流,再用缓冲流包装输入流。
String len = "";
StringBuilder content=new StringBuilder();
while ((len = reader.readLine()) != null) {//调用读写器方法按行读取数据
content.append(len) };//每行均黏贴入缓冲域
content.toString();//缓冲域的内容转化为String
——————————————————————————————————————————
SharedPreferences储存:
sharedPreferences是采用键值对的方式存储数据的,它的储存方式比文件储存简单易用。
getSharedPreferences()方法:
默认的储存路径是:data/data/<package name>/shared_prefs/下
此方法接受两个参数:
第一个参数是文件名,如果文件不存在则会创建一个。
第二个参数是指定操作模式:
MODE_PRIVATE 表示只有当前应用程序可以对sharedPreferences文件读写。
MODE_MULTI_PROCESS 用于会有多个进程中对同一个sharedPreferences文件读取,6.0中废弃。
存入
SharedPreferences.Editor editor = getSharedPreferences("save", MODE_PRIVATE).edit();
//拿到编辑器对象才能放入数据
editor.putString("name","Tom");
editor.apply();//提交放入的数据
取出
SharedPreferences pref= getSharedPreferences("save", MODE_PRIVATE);
String str =pref.getString(''name","");//第二个参数为拿不到所设置的默认值
——————————————————————————————————————————
数据库储存-SQLiteOpenHelper:
当我们需要储存大量复杂的关系型数据的时候,前两种方法就有点力不从心了,例如保存短息,联系人信息等,这个时候我们就可以使用安卓内置的数据库。
安卓系统内置了SQLLite数据库,它支持SQL语法,还遵循数据库的ACID事务,是一款轻量级的数据库。
创建数据库
1.创建数据库需要继承SQLiteOpenHelper,我们需要重写它的两个方法,onCreate()和onUpgrade().分别在这连个方法中创建和升级数据库。
2.SQLiteOpenHelper的构造方法,四个参数 第一个Context 第二个 数据库名 第三个 查询数据时返回一个自定义的Cursor,一般都传null , 第四个是数据库的版本号。
3.SQLiteOpenHelper中有两个非常重要的实例方法,getReadableDatabase()和getWritableDatabase()。这两个方法都可以创建和打开一个现有的数据库。当磁盘空间满的时候getReadableDatabase()会打开一个只读的数据库,getWritableDatabase()会出现异常。磁盘空间未满的时候都是创建或打开一个可读可写的数据库,并返回一个SQLiteDatabase对象,可以用其进行CRUD操作。
4.在SQLite数据库中数据类型 integer表示整形 real表示浮点型 text 表示文本类型 blob表示二进制类型,数据库文件会存放在data/data/<package name>/databases/下。
//MySQLiteOpenHelper实现类
public class MySQLiteOpenHelper extends SQLiteOpenHelper {
public static final String Create_contact = "create table person(_id integer primary key autoincrement, " +
"name char(10), " +
"salary char(20), " +
"phone integer(20))";
public MySQLiteOpenHelper(Context context, String name,CursorFactory factory, int version) {
super(context, name, factory, version);
mcontext = context;
}
public void onCreate(SQLiteDatabase db) {
//当创建数据库的时候会调用此方法在此方法中创建表
db.execSQL(Create_contact);
Toast.makeText(mcontext, "数据库创建了", 0).show();
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
在数据库实现类中使用建表语言:
由于实现类继承了SQLiteOpenHelper,由此获得了SQLiteDatabase的操作对象与功能,并传入onCreate();与onUpgrade();在这两个方法中,就可以使用SQLiteDatabase的execSQL(String str)语句
执行字符串str中的建表语句。
升级数据库:
重写实现类 onUpgrade()方法。
并且修改实现类构造函数中的参数使其大于上一版本。
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
switch (oldVersion) {//系统自动完成上一次new实现类对象的版本号传递
case 1:
db.execSQL(Create_sms);// 如果用户从1版本升级过来的话,就不会创建两张表而是再升级中添加一张表
case 2:
db.execSQL("alter table person add column category_id integer");// 如果用户从2版本升级过来的话,就会直接添加一个列字段
default:
}
Create/insert & Update/update & Delete/delete:增删改
//创建帮助类实例
MySQLiteOpenHelper dbHelper=new MySQLiteOpenHelper(this,"SQL.db",null,0);
//获得操作数据库的功能对象
SQLiteDatabase db= dbHelper.getWritableDatabase();
//利用赋值容具类ContentValues完成对一行多列数据的转存
ContentValues values=new ContentValues();
//增:
values.put("column1","text1")
values.put("column2","text2")
...
//第二个参数nullColumnHack:当values参数为空或者里面没有内容的时候,我们insert是会失败的(底层数据库不允许插入一个空行)
//为了防止这种情况,在这里指定一个列名,到时候如果发现将要插入的行为空行时,就会将你指定的这个列名的值设为null,然后再向数据库中插入。
db.insert(String table(插入表名),columns, values);
//删: 删除指定列满足条件的数据
//第二个参数(selection:查询条件)相当于SQL语句中where,?是一个占位符,由后一个参数str提供
db.delete(String table(删除表名),"column+关系式+?",string str);
//改:更改指定列满足条件的数据
//第三个参数(selection:查询条件)相当于SQL语句中where,?是一个占位符,由后一个参数str提供
//由values提供列名与修改内容
db.update(String table(更新表名),values,"column+关系式+?",string str);
Retrieve/select:查询
query(String table,String []Columns, String selection, String[]selectionArgs, String having, string orderBy);共7个参数 :
table:表名,不能为null
columns:要查询的列名,可以是多个,可以为null,表示查询所有列
selection:查询条件,比如id=? and name=? 可以为null
selectionArgs:对查询条件赋值,一个问号(占位符)对应一个值,按顺序 可以为null
groupBy: 指定需要按第二个参数来groupby分组的列,可以为null
having:语法having设置分组条件,可以为null
orderBy:指定查询结果排序方法,可以为null
调用query都会返回一个Cursor对象,对这个对象进行遍历即可得到查询后的所有数据
Cursor cursor = db.query("person", null, null, null, null, null, null);
if(cursor.moveToFirst()) {
do{
String colunm1 = cursor.getString(cursor.getColumnIndex("colunm1"));
String colunm2 = cursor.getString(cursor.getColumnIndex("colunm2"));
.....
}while(cursor.moveToNext());
}
cursor.close();
此外,也可使用db.execSQL(String str)执行SQL语言完成增删改,查询则使用db.rawQuery(String str);
——————————————————————————————————————————
数据库储存-LitePal:
快速配置
引入Jar包或源码
LitePal的开源已经提交到 jcenter,故我们想要使用,只需要编辑app/build.gradle文件,在dependencies闭包中添加以下内容:
compile 'org.litepal.android:core:1.4.1' //1.4.1是版本号,最新版本号在引用可见配置litepal.xml
接着在项目的main目录下创建assets目录并新建一个litepal.xml文件,并将以下代码拷贝进去:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="demo" ></dbname>
<version value="1" ></version>
<list>
</list>
</litepal>
配置文件相当简单,<dbname>用于设定数据库的名字,<version>用于设定数据库的版本号,<list>用于设定所有的映射模型,我们稍后就会用到。
- 配置LitePalApplication
由于操作数据库时需要用到Context,而我们显然不希望在每个接口中都去传一遍这个参数,那样操作数据库就显得太繁琐了。因此,LitePal使用了一个方法来简化掉Context这个参数,只需要在AndroidManifest.xml中配置一下LitePalApplication,所有的数据库操作就都不用再传Context了,如下所示:
<manifest>
<application
android:name="org.litepal.LitePalApplication"
...
>
...
</application>
</manifest>
创建数据库
配置映射:
package com.example.databasetest.model;
public class News {
//定义字段,可以进行对象关系映射的数据类型一共有8种,int、short、long、float、double、boolean、String和 Date。
//只要是声明成这8种数据类型的字段都会被自动映射到数据库表中,并不需要进行任何额外的配置。
//自动生成get,set方法
}
完成映射:
<?xml version="1.0" encoding="utf-8"?>
<litepal>
<dbname value="demo" ></dbname>
<version value="1" ></version>
<list>
<mapping class="com.example.databasetest.model.News"></mapping>//添加到关系类列表
</list>
</litepal>
成功创建:
在活动中运行:LitePal.getDatabase();方法则成功完成创建。
升级数据库
不需要去编写任何与升级相关的逻辑,也不需要关心程序是从哪个版本升级过来的,唯一要做的就是确定好最新的Model结构是什么样的,然后将litepal.xml中的版本号加1,所有的升级逻辑就都会自动完成了。LitePal确实将数据库表的升级操作变得极度简单,使很多程序员可以从维护数据库表升级的困扰中解脱出来。
Create/insert & Update/update & Delete/delete:增删改
进行CRUD操作时就不行了,LitePal要求所有的实体类都要继承自DataSupport这个类
【具体操作参见:】http://blog.csdn.net/guolin_blog/article/details/39345833
添加:每new出一个对应类的对象,则为添加一行数据,save();方法提交,save()返回为存储的结果。调用save();后则这个对象为已存储,此时再调用isSave():则为TRUE
修改:
1.先调用set方法设置新属性,然后使用 该对象.update(long id) //快捷修改,会默认传入类对象并省略values
2.如果是需要设置条件的复杂修改,则需要与ContentValues values联用,使用DataSupport.update();或DataSupport.updateAll();
删除:与修改类似,不过是deleteAll();与delete();方法。
Retrieve/select:查询
简单查询:
News news = DataSupport.find(News.class, 1); //查id为1的记录
News firstNews = DataSupport.findFirst(News.class); //查第一条
News lastNews = DataSupport.findLast(News.class);
List<News> newsList = DataSupport.findAll(News.class, 1, 3, 5, 7); //后边传入任意id,无则为全部
连缀查询:原本query的多个参数被封装成各自的方法,在DataSupport.find(.class)前连缀使用
激进查询:
News news = DataSupport.find(News.class, 1, true); //这会将和news表关联的所有表中的数据也一起查出来
该查询效率不高,最佳写法是在Model类中添加了一个get()方法,而这个方法的内部就是使用了一句连缀查询,查出了当前类对象关联的所有类对象。
此外,也可使用原生语句SQL执行SQL语言完成查询;
Cursor cursor = DataSupport.findBySQL("select * from news where commentcount>?", "0");
——————————————————————————————————————————
【github新版本】https://github.com/LitePalFramework/LitePal
【配置问题】http://blog.csdn.net/guolin_blog/article/details/38556989
【LitePal实现表内连接】 http://blog.csdn.net/guolin_blog/article/details/39207945
【LitePal实现查询】 http://blog.csdn.net/guolin_blog/article/details/40153833
——————————————————————————————————————————
【样本方法实例:】http://blog.csdn.net/itluochen/article/details/52605392
【数据库CRUD操作参数详解】http://blog.csdn.net/nomisshe/article/details/17797631