Android:数据持久化(2/2) SQLite
2015-10-27 00:00
531 查看
摘要: 详细介绍了SQLite的使用,包括数据库的创建、CRUD操作。(事务操作以及升级数据库的best practice会在之后补上)
对SQLite的操作,从整体上来说分两步:
自定义一个Helper类,继承自***SQLiteOpenHelper***,用于获取数据库的实例对象(或者说用于打开数据库的助手类);
通过该Helper类的对象,获取具体的数据库对象来进行CRUD操作;
自定义Helper类的要求:
继承SQLiteOpenHelper类;
覆写(Override)
说明:
继承了SQLiteOpenHelper;
覆写了onCreate(),该方法在helper第一次获取数据库对象时调用,即创建Book表;
覆写了构造器(构造方法/Constructor),取得调用该实例的context,以便内部使用(如这里的Toast.makeText()需要该参数);
注意:文中用到的文件都是使用Android Studio的默认定义,如MainActivity.java, activity_main.xml等。
该部分为可选内容,不使用该工具也可以进行开发,只是查看资料会相当不便,所以还是建议学会使用。
配置环境变量,将platform-tools 目录加入到PATH中;
运行App,在启动模拟器后,可以在cmd/terminal中输入
切换目录到数据库所在文件夹:
通过
在进入了sqlite3的环境后,可使用
在代码中(MainActivity.java)中对按钮的点击事件进行监听绑定,通过定义数据库的名称及版本号来创建Helper类的实例,并通过getWritable()获取该数据库的实例。
第一次点击创建数据库的按钮,
调用SQLiteDatabase对象的insert();
定义了两个EditText来输入书名和作者,点击按钮进行插入。(activity_main.xml)
MainActivity.java
update()比insert()多了WHERE条件及相应参数;
在布局文件(activity_main.xml)中加入按钮进行update()的绑定:
MainActivity.java
虽然
至少出版了一本书且每本书的售价在50以上,返回作者名字及作品数:
等价于:
Abstract 概述
之前的随笔记录了普通文本文件和SharedPreferences两种保存数据的方式,现在来谈一谈用SQLite这个Android自带的数据库。对SQLite的操作,从整体上来说分两步:
自定义一个Helper类,继承自***SQLiteOpenHelper***,用于获取数据库的实例对象(或者说用于打开数据库的助手类);
通过该Helper类的对象,获取具体的数据库对象来进行CRUD操作;
Description 具体内容
1. 自定义Helper类
借助该Helper类的对象,我们才能获取数据库对象进行操作。自定义Helper类的要求:
继承SQLiteOpenHelper类;
覆写(Override)
onCreate()和
onUpgrade()两个方法;
public class MyDBHelper extends SQLiteOpenHelper { public static final String BOOK_STORE = "BookStore.db"; public static final String BOOK_TABLE = "Book"; private Context context; public static final String CREATE_BOOK = "create table Book (id integer primary key autoincrement, name text, author text, price real, cover text)"; public MyDBHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) { super(context, name, factory, version); this.context = context; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(CREATE_BOOK); Toast.makeText(context, "Database created.", Toast.LENGTH_SHORT).show(); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { Toast.makeText(context, "Just upgraded.", Toast.LENGTH_SHORT); } }
说明:
继承了SQLiteOpenHelper;
覆写了onCreate(),该方法在helper第一次获取数据库对象时调用,即创建Book表;
覆写了构造器(构造方法/Constructor),取得调用该实例的context,以便内部使用(如这里的Toast.makeText()需要该参数);
注意:文中用到的文件都是使用Android Studio的默认定义,如MainActivity.java, activity_main.xml等。
2. 获取数据库对象
2. 0 通过adb工具查看数据库内容
在SKD下有一个platform-tools文件夹,里面有一个adb的工具可查看sqlite的数据。该部分为可选内容,不使用该工具也可以进行开发,只是查看资料会相当不便,所以还是建议学会使用。
配置环境变量,将platform-tools 目录加入到PATH中;
运行App,在启动模拟器后,可以在cmd/terminal中输入
adb shell启动adb(可通过
exit来退出);
切换目录到数据库所在文件夹:
cd /data/data/com.scv.lawrence.databasetesting/databases(此处以Nexus为例,在真机上测试如小米等,目录很有可能不一样);
通过
ls命令可以看到当前所有数据库(参考下面2.1的内容),此时使用
sqlite3 databaseName命令可以打开该数据库。如2.1中创建了一个名为BookStore.db的数据库,含有一个Book表,则在adb shell中使用
ls时能看到BookStore.db,
sqlite3 BookStore.db;
在进入了sqlite3的环境后,可使用
.schema来查看创建表所执行的SQL语句,可使用
.table来查看所有表的名称,可使用
.exit来返回adb shell,同样可使用各种sqlite支持的SQL语句;
2. 1 创建数据库
在布局文件中定义一个按钮。<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:layout_width="match_parent" android:layout_height="wrap_content" android:text="Create DB" android:id="@+id/create_db"/> <LinearLayout/>
在代码中(MainActivity.java)中对按钮的点击事件进行监听绑定,通过定义数据库的名称及版本号来创建Helper类的实例,并通过getWritable()获取该数据库的实例。
Button createDB = (Button) findViewById(R.id.create_db); createDB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteOpenHelper helper = new MyDBHelper(MainActivity.this, MyDBHelper.BOOK_STORE, null, 1);//首先要获取相应数据库的helper,才能进行下一步操作 SQLiteDatabase db = helper.getWritableDatabase();//第一次执行这个方法,会自动调用helper中定义的onCreate() } });
第一次点击创建数据库的按钮,
onCreate()中的
Toast.makeText()会提示消息表示执行了该方法,第二次点击开始不再有提示,不再执行onCreate();
2. 2 更新数据库
在获取Helper对象时必须传入数据库的名称和版本号,如果传入的版本号高于以前的版本号,则会自动执行onUpgrade();
SQLiteOpenHelper helper = new MyDBHelper(MainActivity.this, MyDBHelper.BOOK_STORE, null, 2); upgradeDB = (Button) findViewById(R.id.upgrade_db); upgradeDB.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = helper.getWritableDatabase();//由于helper中的第4个参数,版本信息version高于之前,故调用onUpgrade() } });
3. CRUD操作
CRUD即增(Create)删(Delete)改(Update)查(Retrieve),均可使用执行SQL或调用api两种版本来执行;3. 1 Create 插入数据
将要插入的数据放入ContentValues的对象中;调用SQLiteDatabase对象的insert();
定义了两个EditText来输入书名和作者,点击按钮进行插入。(activity_main.xml)
<EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="book name" android:id="@+id/name"/> <EditText android:layout_width="match_parent" android:layout_height="wrap_content" android:hint="author" android:id="@+id/author"/> <Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="create" android:id="@+id/create"/>
MainActivity.java
Button createBtn = (Button) findViewById(R.id.create); createBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String bName = nameEdit.getText().toString(); String author = authorEdit.getText().toString(); ContentValues values = new ContentValues(); values.put("name", bName); values.put("author", author); SQLiteDatabase db = helper.getWritableDatabase(); db.insert(MyDBHelper.BOOK_TABLE, null, values);//与下面的SQL语句等价,且为了避免SQL注入攻击,必须使用传参的形式,不能自行拼装SQL语句。 //db.execSQL("INSERT INTO Book (name, author) VALUES (?, ?)", new Object[]{bName, author}); values.clear();//清空ContentValues对象的内容,为下次修改作准备 Toast.makeText(MainActivity.this, "Data inserted.", Toast.LENGTH_SHORT).show(); nameEdit.setText(null); authorEdit.setText(null); } });
3. 2 Update 更新数据
和insert()一样,以ContentValues对象来保存要更新的内容;update()比insert()多了WHERE条件及相应参数;
在布局文件(activity_main.xml)中加入按钮进行update()的绑定:
<Button android:layout_width="match_parent" android:layout_height="wrap_content" android:text="update" android:id="@+id/update"/>
MainActivity.java
Button updateBtn = (Button) findViewById(R.id.update); updateBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ContentValues values = new ContentValues(); values.put("author", "updated Author"); values.put("price", 23.33); SQLiteDatabase db = helper.getWritableDatabase(); db.update(MyDBHelper.BOOK_TABLE, values, "id=?", new String[]{"1"});//等价于下面的SQL语句 //db.execSQL("UPDATE Book SET author=?,price=? WHERE id=?", new Object[]{"updated SQL", 23.33, 1}); values.clear(); Toast.makeText(MainActivity.this, "Data updated.", Toast.LENGTH_SHORT).show(); } });
3. 3 Delete 删除数据
delete()只需要传入表的名称和WHERE条件及相应参数即可;Button deleteBtn = (Button) findViewById(R.id.delete); deleteBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = helper.getWritableDatabase(); db.delete(MyDBHelper.BOOK_TABLE, "id=?", new String[]{"3"});//等价于下面的SQL语句 //db.execSQL("DELETE FROM Book WHERE id=?;", new Object[]{1});//auto-boxing } });
3. 4 Retrieve 查询数据
查询的结果就是一张表格,需要使用Cursor对象的moveToNext()指向表格的每一行,在每一行中;
Button retrieveBtn = (Button) findViewById(R.id.retrieve); retrieveBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { SQLiteDatabase db = helper.getWritableDatabase(); // Cursor cursor = db.rawQuery("SELECT name, author, price FROM Book",null,null);//与下面的query()等价,然而要求API必须在16以上 Cursor cursor = db.query(MyDBHelper.BOOK_TABLE, null, null, null, null, null, null); if(cursor.moveToNext()){ do{ String name = cursor.getString(cursor.getColumnIndex("name")); String author = cursor.getString(cursor.getColumnIndex("author")); double price = cursor.getDouble(cursor.getColumnIndex("price")); Log.i(TAG, name + ", " + author + ", " + price); }while(cursor.moveToNext()); } } });
虽然
query()的参数很多,但只要将其视作完整的
SELECT语句的拆分,就会很方便理解:
query(from_table, select_columns, where, whereArgs, group_by, having, order_by)
至少出版了一本书且每本书的售价在50以上,返回作者名字及作品数:
SELECT author, count(name) FROM Book WHERE price>50 GROUP BY author HAVING count(name)>1 ORDER BY author
等价于:
db.query(MyDBHelper.BOOK_TABLE, "author, count(name)", "price>?", new String[]{"50"}, "author", "count(name)>1", "author");
Reference 参考
《第一行代码:Android》郭霖(著)相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories