提到安卓的数据库存储,很多开发者都会想到使用继承SQLiteOpenHelper,然后使用安卓框架中给出的接口进行数据库和数据表的创建、删除、更新。
然而,因为安卓的sdk中封装了接口,让我在很长的一段时间内都认为数据库的使用只能通过SQLiteOpenHelper来操作。其实还有其他方式,一般有:
1 直接继承SQLiteOpenHelper,调用它的getReadableDatabase和getWritableDatabase进行操作。
2 使用FileOutputStream把assets目录下的数据库拷贝到应用的安装目录下进行操作。
3 使用openOrCreateDatabase直接创建一个db文件,并且execSQL相关的表进去。
4 直接使用openOrCreateDatabase打开一个sd卡或者其他路径下的数据库进行CRUD。
实现SQLiteOpenHelper
在onCreate()中对数据库进行创建,然后使用getReadableDatabase和getWritableDatabase得到 SQLiteDatabase 实例,然后进行操作。
public class DemoSqlOpenHelper extends SQLiteOpenHelper {
private static DemoSqlOpenHelper helper;
public DemoSqlOpenHelper getIns(Context context){
if(helper == null){
helper = new DemoSqlOpenHelper(context, "demo.db", null, 1);
}
return helper;
}
public DemoSqlOpenHelper(Context context, String name,
CursorFactory factory, int version,
DatabaseErrorHandler errorHandler) {
super(context, name, factory, version, errorHandler);
}
public DemoSqlOpenHelper(Context context, String name,
CursorFactory factory, int version) {
super(context, name, factory, version);
}
@Override
public void onCreate(SQLiteDatabase db) {
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
public void test(){
helper.getReadableDatabase();
helper.getWritableDatabase();
}
}
可以查看到操作数据库的接口:
在android.database.sqlite.SQLiteOpenHelper下查看getReadableDatabase()和getWritableDatabase()的具体实现:
读和写分别使用一个bool值进行区分:
public SQLiteDatabase getReadableDatabase() {
synchronized (this) {
return getDatabaseLocked(false);
}
}
public SQLiteDatabase getWritableDatabase() {
synchronized (this) {
return getDatabaseLocked(true);
}
}
private SQLiteDatabase getDatabaseLocked(boolean writable) {
······
try {
if (DEBUG_STRICT_READONLY && !writable) {
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
} else {
db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ?
Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0,
mFactory, mErrorHandler);
}
} catch (SQLiteException ex) {
if (writable) {
throw ex;
}
Log.e(TAG, "Couldn't open " + mName
+ " for writing (will try read-only):", ex);
final String path = mContext.getDatabasePath(mName).getPath();
db = SQLiteDatabase.openDatabase(path, mFactory,
SQLiteDatabase.OPEN_READONLY, mErrorHandler);
}
······
}
这里调用到了Context中的openOrCreateDatabase()方法,从命名可以比较清晰的猜到这是打开或者创建数据库的接口,所以,数据库的创建是在调用到openOrCreateDatabase()的时候才会执行也就是调用getReadableDatabase()和getWritableDatabase(),new一个SQLiteOpenHelper是不会创建数据库的,也就是SQLiteOpenHelper中的onCreate()也是在。那么现在应该进入到Context里面了解具体的实现:
进入发现Context中发现这个方法没有被实现,只是抽象类
public abstract SQLiteDatabase openOrCreateDatabase(String name,
int mode, CursorFactory factory, DatabaseErrorHandler errorHandler);
进入子类(ContextWrapper extends Context ):
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
return mBase.openOrCreateDatabase(name, mode, factory);
}
发现也没有被实现,那么就是在接口中实现了:
果然是这样,查看ContextImpl extends Context
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory) {
return openOrCreateDatabase(name, mode, factory, null);
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, CursorFactory factory,
DatabaseErrorHandler errorHandler) {
File f = validateFilePath(name, true);
int flags = SQLiteDatabase.CREATE_IF_NECESSARY;
if ((mode & MODE_ENABLE_WRITE_AHEAD_LOGGING) != 0) {
flags |= SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING;
}
SQLiteDatabase db = SQLiteDatabase.openDatabase(f.getPath(), factory, flags, errorHandler);
setFilePermissionsFromMode(f.getPath(), mode, 0);
return db;
}
这里调用了SQLiteDatabase的静态方法。
SQLiteDatabase.openDatabase
查看openDatabase方法:直到这里才创建了一个数据库实例SQLiteDatabase。
public static SQLiteDatabase openDatabase(String path, CursorFactory factory, int flags,
DatabaseErrorHandler errorHandler) {
SQLiteDatabase db = new SQLiteDatabase(path, flags, factory, errorHandler);
db.open();
return db;
}
至此,完全打开了一个数据库,可以看到:
过程中调用了静态方法 SQLiteDatabase.openDatabase().
使用assets目录下的数据库文件
编译apk的时候把数据库文件也编写进去,使用FileOutputStream流把数据库文件拷贝到应用安装的data/data/dtabases/目录下。
拷贝到安装目录下之后,操作同第一种方式:
public class CopyAssetsDB {
private Context context;
private String DBNAME = "TestDemo.db";
private final int BUFFER_SIZE = 400000;
private String databasePath = null;
private SQLiteDatabase db = null;
public CopyAssetsDB(Context context) {
super();
this.context = context;
StringBuilder builder = new StringBuilder();
builder.append("/data");
builder.append(Environment.getDataDirectory().getAbsolutePath());//等同data/
builder.append("/");
builder.append(context.getPackageName());
builder.append("/");
builder.append(DBNAME);
databasePath = builder.toString();
Log.i(getClass().getSimpleName(),"DBPath="+databasePath);
}
public SQLiteDatabase openDatabase() {
if(db != null){
return db;
}
File file = new File(databasePath);
if (!file.exists()) {
InputStream is;
try {
is = context.getResources().getAssets().open(DBNAME);
FileOutputStream fos = new FileOutputStream(databasePath);
byte[] buffer = new byte[BUFFER_SIZE];
int count = 0;
while ((count = is.read(buffer)) > 0) {
fos.write(buffer, 0, count);//写入ROM中
}
Log.i(getClass().getSimpleName(),"数据库文件不存在,创建文件");
fos.close();
is.close();
} catch (IOException e) {// 包含有 FileNotFoundException
e.printStackTrace();
}
}else{
Log.i(getClass().getSimpleName(),"数据库文件存在,直接打开");
}
db = SQLiteDatabase.openOrCreateDatabase(databasePath, null);
return db;
}
}
openOrCreateDatabase直接创建db文件
public class CreateDB {
private static final String DATABASE_NAME = "myDatabase.db";
private static final String DATABASE_TABLE = "mainTable";
private static final String DATABASE_CREATE =
"create table " + DATABASE_TABLE +
"( _id integer primary key autoincrement," +
"column_one text not null);";
SQLiteDatabase myDatabase;
public void createDatabase(Context context) {
myDatabase = context.openOrCreateDatabase(DATABASE_NAME, Context.MODE_PRIVATE, null);
myDatabase.execSQL(DATABASE_CREATE);
}
}
操作sd卡路径下的数据库
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<!-- 往SD卡写入数据的权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
public class OpensdCardDB {
private SQLiteDatabase db;
private String databasePath = null;
private String DBNAME = "TestDemo.db";
public OpensdCardDB() {
super();
StringBuilder path = new StringBuilder();
path.append(Environment.getExternalStorageDirectory());
path.append("/");
path.append(DBNAME);
databasePath = path.toString();
}
public SQLiteDatabase openDB(){
db = SQLiteDatabase.openOrCreateDatabase(databasePath, null);
return db;
}
}
不一定只有这几种方式,还有其他更多的方式,比如网络上down下来的数据库文件。
完成之后使用SQLiteDatabase进行操作:
private SQLiteDatabase database;
/**
* 查询数据
*/
private void query(){
Cursor c = database.rawQuery("select * from Student", null);
if(c.moveToFirst()){
do{
StringBuilder builder = new StringBuilder();
builder.append(c.getString(0)+" , ");
builder.append(c.getString(1)+" , ");
builder.append(c.getString(2));
Log.i(getClass().getSimpleName(),"读取结果为="+builder.toString());
}while(c.moveToNext());
}else{
Log.i(getClass().getSimpleName(),"读取结果为=null");
}
}
/**
* 插入数据
*/
private void insert(){
Cursor c = database.rawQuery("insert into Student values('hello','18','女')", null);
boolean result = c.moveToFirst();
}
直到得到SQLiteDatabase对象即可对使用封装在安卓SDK中的接口继续数据库操作.
转载请联系作者并且注明出处http://blog.csdn.net/dreamintheworld/article/details/38665195