之前两篇文章我们分别对SharedPreferences和文件存储作了简单的介绍,现在没有来介绍下截止目前为止最先进和最强大的本地存储方法:android的数据库存储技术。
android使用的数据库是SQLite数据库,目前的版本为sqlite3这个文档android.database.sqlite 包含了操作数据库所需要的API.在android sdk的plaform-tools目录下有sqlite3。如果已经把该目录加到PATH中的话,在任意路径执行下列命令,即可打开sqlite3.
sqlite3
SQLite是什么
SQLite是款轻量级的关系数据库,它的运算速度快,体积小,独立且不依赖于服务器,是事务性的,并且能执行标准的SQL语言查询。
SQL(Structured Query Language 结构化查询语言)是专门用于在关系数据库中管理数据的语言。关系数据库允许用户提交插入,删除,更新和查询等操作,同时还允许用户创建和修改数据模式(就是修改数据库中的各个表)。
当需要存储大量复杂的关系型数据时,使用数据库进行存储。
定义数据库的模式
数据库模式(schema)是关系型数据库的主要原则之一。数据库模式定义了数据库中数据的组织方式。当创建数据库时,会在SQL语句中调用schema.下面是一个简单的模式,记录学生信息。
crate table student{
id integer primary key autoincrement,
name text,
age integer,
grade real
}
其实的integer ,text,real表示SQLite的数据类型,integer 表示整型,real表示浮点型,text表示文本类型,blob表示二进制类型,我们使用primary key 将id列设为主键,并用autoincrement关键字表示主键是自增长的。在代码中执行这条语句,就可以创建一个名为student的表。打开adb shell ,获得root权限,进入/data/data/package-name/目录下。
ls 列出目录下的内容,如果成功创建数据库,会出现一个daatabases目录
# ls
cache
databases
files
cd 进入到databases目录下
#cd databases
在ls列出目录下的内容
# ls
student.db
student.db-journal
使用sqlite3打开studen.db数据库,
#sqilte3 student.db
sqlite>
执行.schema即可查看建表语句
sqlite>.schema
CREATE TABLE android_metadata (locale TEXT);
CREATE TABLE student(id integer primary key autoincrement,name text,grade real,age integer);
使用SQL Helper创建数据库
android 提供了一个SQLiteOpenHelper帮助类,使用这个类可以非常简单的创建和升级数据库。
SQLiteOpenHelper是一个抽象类,需要创建新的类继承它,并且重写其中的抽象方法onCreate()和onUpgrade()。在onCreate()中要实现创建数据库的相关逻辑,在onUpgrade()中实现升级数据库的相关逻辑。
下面代码实现创建数据库。新建一个类继承自SQLiteHelper,代码如下所示
MyDataBaseHelper.java
package com.example.test.testdatabase.hleper;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class MyDatabaseHelper extends SQLiteOpenHelper {
//建表语句
public static final String CREATE_TABLE = "create table student("
+ "id integer primary key autoincrement,"
+ "name text,"
+ "grade real,"
+ "age integer)";
private Context mContext;
public MyDatabaseHleper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
在主布局文件中添加一个一个按钮点击按钮后创建数据库
主布局文件 /src/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
android:id="@+id/create_database"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="create database"
/>
</RelativeLayout>
在MainActivity中添加按钮点击事件
ManiActivity.java
package com.example.test.testdatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.test.testdatabase.hleper.MyDatabaseHelper;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyDatabaseHelper databaseHleper;
private Button mBtnCreate;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
databaseHleper = new MyDatabaseHelper(this,"Student.db",null,1);
mBtnCreate = (Button) findViewById(R.id.create_database);
mBtnCreate.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.create_database:
databaseHleper.getWritableDatabase();
break;
}
}
}
打开adb shell ,进入到程序默认存储路径下,可以查看创建好的数据库。
升级数据库
SQLiteOpenHelper中有onUpgrade()抽象方法,在继承SQLiteOpenHleler时要实现它,它用于数据库的升级,它接受三个参数,第一个是SQLDatabase,第二个,第三个参数都表示数据库版本,第二个为旧的数据库版本,第三个为新的数据库版本,新的版本要大于旧的版本。SQLiteOpenHelper构造器中也有个参数表示版本号,在上例的MyDatabaseHelper中,第四个参数表示版本号,要在不卸载程序的条件下更新数据库,创建一个新的MyDatabaseHelper对象,并将版本号提升,再调用getWritableDatabase()获取一个可以写的数据库,MyDatabaseHelper中的onUpgrade()方法会执行,只要在这个方法中实现升级数据库的逻辑,即可实现数据库升级。
现在要向上例中的Student数据库中添加一个新的表,表示学生考试安排,建表语句如下
create table test{
courseId integer primary key autoincrement,
courseName text,
time integer
}
在MyDatabsehelper中添加新的建表语句以及升级逻辑,MyDataBasehelper代码如下
package com.example.test.testdatabase.hleper;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyDatabaseHelper extends SQLiteOpenHelper {
//建表语句
private static final String TAG = "SQL";
public static final String CREATE_STUDENT = "create table student("
+ "id integer primary key autoincrement,"
+ "name text,"
+ "grade real,"
+ "age integer)";
public static final String CREATE_TEST = "create table test("
+ "courseId integer primary key autoincrement,"
+ "courseName text,"
+ "time integer)";
private Context mContext;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
Log.d(TAG,"constructor");
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_STUDENT);
db.execSQL(CREATE_TEST);
Log.d(TAG,"onCreate");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists student");
db.execSQL("drop table if exists test");
onCreate(db);
}
}
在onUpgrade()中,实现了升级数据库的逻辑,执行了两条SQL语句,如果表student和表test已经存在,则删除他们,重新调用onCreate,执行建表语句,创建表student 和表test
向表中添加数据
使用SQLiteDatabase的insert()方法向表中添加数据,该方法接收三个参数,第一个参数表示要插入数据的表,第二个参数用于在未指定添加数据的情况下给某些为空的列自动复制赋值NULL,一般不会用到,直接传入null即可。第三个参数为ContenValues对象,主要通过它来向表中添加数据,它有一些列的put()重载方法,就像Bundle中的put()方法,用于向ContentValues对象中添加数据,只要将表中的每个列名以及要添加的数据传入即可。
下面演示向表中添加数据
现在主布局文件中添加一个添加数据的按钮,主布局代码如下,这里将前面的RelativeLayout改成了LineaLayout.
/res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:id="@+id/create_database"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="create database"
/>
<Button
android:id="@+id/insert"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="insert data"
/>
</LinearLayout>
在MyDatabaseHelper中实现添加数据逻辑。insert()方法属于SQLiteDatabase,所以要在MyDatabasehelper中创建一个SQLietDatabase对象,代码如下
MyDatabaseHelper.java
package com.example.test.testdatabase.hleper;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyDatabaseHelper extends SQLiteOpenHelper {
//建表语句
private static final String TAG = "SQL";
private SQLiteDatabase database = getWritableDatabase();
public static final String CREATE_STUDENT = "create table student("
+ "id integer primary key autoincrement,"
+ "name text,"
+ "grade real,"
+ "age integer)";
public static final String CREATE_TEST = "create table test("
+ "courseId integer primary key autoincrement,"
+ "courseName text,"
+ "time integer)";
private Context mContext;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_STUDENT);
db.execSQL(CREATE_TEST);
Log.d(TAG,"onCreate");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists student");
db.execSQL("drop table if exists test");
onCreate(db);
}
public void insertData(){
ContentValues values = new ContentValues();
//添加第一条数据
values.put("id",1);
values.put("name","xiaohong");
values.put("grade",98.5);
values.put("age",15);
database.insert("student",null,values);
values.clear();//清除ContentValues中的数据
}
}
在MainAcitivity中监听添加数据按钮事件,代码如下
MainActivity.java
package com.example.test.testdatabase;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import com.example.test.testdatabase.hleper.MyDatabaseHelper;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private MyDatabaseHelper databaseHleper;
private Button mBtnCreate;
private Button mBtnInserte;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
databaseHleper = new MyDatabaseHelper(this,"Student.db",null,3);
mBtnCreate = (Button) findViewById(R.id.create_database);
mBtnInserte = (Button) findViewById(R.id.insert);
mBtnCreate.setOnClickListener(this);
mBtnInserte.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.create_database:
databaseHleper.getWritableDatabase();//创建数据库
break;
case R.id.insert:
databaseHleper.insertData();//添加数据
break;
}
}
}
在adb shell中打开Student.db,输入SQL查询语句
sqlite>select * from student;
1|xiaohong|98.5}15
sqlite>
这表语句表示在student表中查询所有数据,*匹配任意数据,要在语句后面添加“;”,如果需要查找特定数据项,制定数据项名称即可,比如要查询名字,输入下列语句、
sqlite>select name fromn student ;
xiaohong
sqlite>
更新表中的数据
SQLiteDatabase中有个updata()方法,用于更新表中的数据,这个方法接受四个参数,第一个参数和insert中的第一个参数一样,表示要更新数据的表名,第二个参数为ContentValues对象,把要更新的数据放到ContentValues对象中,第三个和第四个表示更新数据的位置,如果不指定,则默认更新所有行。
下面在上面例子的基础更新表,过了一年,小红长大了一岁,现在要更新她的年龄。
在MyDatabaseHelper中实现更新数据逻辑,新添一个更新数据的方法update(),代码如下
MyDatabaseHelper.java
package com.example.test.testdatabase.hleper;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class MyDatabaseHelper extends SQLiteOpenHelper {
//建表语句
private static final String TAG = "SQL";
private SQLiteDatabase database = getWritableDatabase();
ContentValues values = new ContentValues();
public static final String CREATE_STUDENT = "create table student("
+ "id integer primary key autoincrement,"
+ "name text,"
+ "grade real,"
+ "age integer)";
public static final String CREATE_TEST = "create table test("
+ "courseId integer primary key autoincrement,"
+ "courseName text,"
+ "time integer)";
private Context mContext;
public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_STUDENT);
db.execSQL(CREATE_TEST);
Log.d(TAG,"onCreate");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("drop table if exists student");
db.execSQL("drop table if exists test");
onCreate(db);
}
public void insertData(){
//添加第一条数据
values.put("id",1);
values.put("name","xiaohong");
values.put("grade",98.5);
values.put("age", 15);
database.insert("student", null, values);
values.clear();//清除ContentValues中的数据
}
public void updata(){
values.put("age",16);
Log.d(TAG,"update");
database.update("student",values,null,null);
}
}
在主布局文件添加一个更新数据按钮,
<Button
android:id="@+id/update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="uopdate"
/>
然后在MainActivity中实现监听事件,
public void onClick(View v){
switch(v.getId() ){
....
case R.id.update:
databaseHleper.updata();
break;
}
}
删除表中数据
和插入删除数据一样,SQLiteDatabase提供了删除的方法,那就时delete(),它接收三个参数,都一个还是表名,第二个,第三个用于删指定位置的数据,默认删除所有行。
现在要删除小红这条数据,在MyDatabaseHelper中新增delete()方法,实现删除逻辑。代码如下
public void delete(){
database.delete("student", "name = ?", new String[]{"xiaohong"});
}
在主布局中添加删除按钮,然后在MainActivity中监听处理删除事件,和更新数据一样,这里不再累述。
查询数据
数据库的四大操作“增删改查”中,查是较为复杂的操作,和前面几个操作一样,SQLiteDatabase提供了query()用于数据查询。这个方法比较复杂,有四个重载方法。
public Cursor query(boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit, null);
}
public Cursor query(boolean distinct, String table, String[] columns,
String selection, String[] selectionArgs, String groupBy,
String having, String orderBy, String limit, CancellationSignal cancellationSignal) {
return queryWithFactory(null, distinct, table, columns, selection, selectionArgs,
groupBy, having, orderBy, limit, cancellationSignal);
}
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, null /* limit */);
}
public Cursor query(String table, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having,
String orderBy, String limit) {
return query(false, table, columns, selection, selectionArgs, groupBy,
having, orderBy, limit);
}