Android 数据存储提供了四种存储方式:
Shared Preferences
使用键值对(Map(key, value))来存储数据
Internal Storage
内部存储,存储在设备内存的 私人数据
External Storage
外部存储,存储在外部设备的 公共数据
SQLite Databases
存储在关系型数据库;SQLite 是类似MySQL 的关系型数据库,因为其体较小,功能全,被运用在了大多嵌入式设备
Network Connection
SQLite 简介
非常小的关系型数据库
SQLiteOpenHelper
CRUD(增删改查)
import android.app.Activity;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;public class SimpleActivity extends Activity {private static final String INFO = "SimpleActivity";@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.simple_layout);Log.i(INFO, INFO);SQLiteDatabase db = openOrCreateDatabase("simple.db", Context.MODE_PRIVATE, null);db.execSQL("DROP TABLE IF EXISTS Person");// 创建表db.execSQL("CREATE TABLE Person ("+ " id INTEGER PRIMARY KEY AUTOINCREMENT,"+ " name varchar(30),"+ " age SMALLINT"+ ")");Log.d(INFO, "Create Table Successful");Person person = new Person();person.name = "Tikitoo";person.age = 23;// 插入数据db.execSQL("INSERT INTO Person VALUES(NULL , ?, ?)", new Object[]{person.name, person.age});Log.d(INFO, "Insert Successful");person.name = "Davin";person.age = 30;ContentValues cv = new ContentValues();cv.put("name", person.name);cv.put("age", person.age);// 插入ContentValue 中的数据db.insert("Person", null, cv);Log.d(INFO, "ContentValues Insert Successful");cv = new ContentValues();cv.put("age", 35);// 更新数据db.update("Person", cv, "name = ?", new String[]{"Davin"});Log.d(INFO, "Update Successful");Cursor cursor = db.rawQuery("SELECT * FROM Person", null);while (cursor.moveToNext()) {int id = cursor.getInt(cursor.getColumnIndex("id"));String name = cursor.getString(cursor.getColumnIndex("name"));int age = cursor.getInt(cursor.getColumnIndex("age"));Log.d("INFO", id + name + age);}Log.d(INFO, "Query Successful");cursor.close();db.delete("Person", "age < ?", new String[]{"25"});Log.d(INFO, "Delete Successful");db.close();// deleteDatabase("tikitoo_sqlite.db");}
}
参考:
Android SQLite Database Tutorial
Android中SQLite应用详解 - scott's blog - 博客频道 - CSDN.NET
问题总结
使用SQLite 调试工具ADB(adb)
(android:adb环境变量的配置)[http://blog.csdn.net/huangbiao86/article/details/6664779]
使用ADB 工具查看adb shell
cd data,ls 出现错误,这是,输入su 回车即可,会请求访问权限,在手机同意一下;adb opendir failed ,permission denied
当然Android 对于SQLite 处理封装的对象 SQLiteOpenHelper 来返回 SQLiteDatabase 对象来实现增删改查
我们再开发的时候,不能像上面写得那么简单,需要对封装一个子类,提供SQLiteOpenHelper 对象;
封装的SQLiteOpenHelper 对象
package com.tikitoo.android.sqlite.util;import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;/*** Created by Tikitoo1 on 2014/11/12.*/
public class DBHelper extends SQLiteOpenHelper {private static final String DATABASE_NAME = "test.db";private static final int DATABASE_VERSION = 1;public DBHelper(Context context) {// 设置SQLiteDatabase.CursorFactory 为nullsuper(context, DATABASE_NAME, null, DATABASE_VERSION);}// 数据库第一次创建被调用@Overridepublic void onCreate(SQLiteDatabase db) {// 初始化创建一个表db.execSQL("CREATE TABLE IF NOT EXISTS Person"+ "(id INTEGER PRIMARY KEY AUTOINCREMENT, name varchar(30), age SMALLINT");}// 如果数据库版本改变,则会调用@Overridepublic void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {// 新增一个字段db.execSQL("ALTER TABLE Person ADD COLUMN other STRING");}
}
DatabaseSQLite 对象实现对数据库的增删改查
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;import java.util.ArrayList;
import java.util.List;public class DBManager {private static final String INFO = DBManager.class.toString();private DBHelper helper;private SQLiteDatabase db;public DBManager(Context context) {helper = new DBHelper(context);db = helper.getWritableDatabase();// helper.getReadableDatabase();}// 新增一条数据,将数据存在Person 对象,在放在List 集合中,遍历集合,可以实现多条数据插入;public void add(List<Person> persons) {db.beginTransaction();try {for (Person person : persons) {db.execSQL("INSERT INTO Person VALUES(NULL, ?, ?, ?)",new Object[]{person.name, person.age, person.info});}// 设置事物db.setTransactionSuccessful();} finally {// 结束事物db.endTransaction();}}// 更新一条数据,通过name 来修改agepublic void update(Person person) {ContentValues cv = new ContentValues();cv.put("age", person.age);cv.put("info", person.info);// 参数,(表名, ContentValues 对象, where 条件,where 条件对应的值)db.update("Person",cv, "name = ?", new String[]{person.name});}public void delete(Person person) {db.delete("Person", "age >= ?", new String[]{"" + person.age});// String.valueOf(person.age);}public List<Person> person() {List<Person> lists = new ArrayList<Person>();// 使用rawQuery() 方法,返回游标对象,遍历出数据库的数据Cursor cursor = db.rawQuery("SELECT * FROM Person", null);while (cursor.moveToNext()) {int _id = cursor.getInt(cursor.getColumnIndex("id"));String name = cursor.getString(cursor.getColumnIndex("name"));int age = cursor.getInt(cursor.getColumnIndex("age"));String info = cursor.getString(cursor.getColumnIndex("info"));Log.i(INFO, new Person(_id, name, age, info).toString());}return lists;}// 关闭数据库public void closeDB() {db.close();}
}
对了还有将数据表使用JavaBean 处理,将数据存储在Person 对象,比较方便
public class Person {public int _id; // id,唯一标识public String name; // 姓名public int age; // 年龄public String info; // 备注信息public Person() {}public Person(String name, int age, String info) {this.name = name;this.age = age;this.info = info;}public Person(int _id, String name, int age, String info) {this._id = _id;this.name = name;this.age = age;this.info = info;}// 重写toString() 方法@Overridepublic String toString() {StringBuilder sb = new StringBuilder();sb.append("Person[ ");sb.append("name = " + this.name);// sb.append("; id = " + _id);sb.append("; age = " + this.age);sb.append("; info = " + this.info);sb.append(" ]");return sb.toString();}
}
getReadableDatabase() 和getWritableDatabase() 方法的区别:
getReadableDatabase:
首先判断数据库实例是否是打开状态,
如果是,则打开一个可读写的数据库实例;
如果遇到磁盘已满,获取失败,再以可读模式打开数据库,返回数据库实例
getWritableDatabase:
如果不为空,已经打开,并不是以只读模式打开的,
如果mDatabase 不为空则加锁,然后创建或打开新的数据库实例,比较版本,为数据库设置新的版本号,最后把不为空的mDatabase 解锁,把新创建的数据库实例赋值给 mDatabase,并返回新的实例;
总结
所以,如果不遇到磁盘已满的情况下,两个方式返回的数据库实例是一样的,如果担心这种方式发生,先调用 getWritableDatabase 方法,
如果异常,则在调用 getReadableDatabase ,当然这个时候的数据库实例是只读的