前言
在新建数据库sqlite的时候,我们已经知道了数据库默认路径为
/data/data/com.example.pei.textdemo/databases/test_demo.db
那么,如果我们想在创建数据库时,自定义一个自己的路径该如何处理呢,需要涉及到三步
- 自定义Context,重写sqlite存储路径
- 修改继承于SQLiteOpenHelper的DBOpenHelper类
- 数据库的调用
下面就来讲讲具体操作。
一.自定义Context,重写sqlite存储路径
我们在创建数据库的时候,会涉及到一个类SQLiteOpenHelper,一般建数据库的时候,都要继承SQLiteOpenHelper实现一个自己的helper类,这里,我写一个自己的helper来继承SQLiteOpenHelper,部分代码如下:
public class DBOpenHelper extends SQLiteOpenHelper{
......
}
然后在DBOpenHelper这个类中,我们会有两个构造方法
public DBOpenHelper(Context context) {
this(context, DB_NAME, null, 1);
this.mContext= context;
}
public DBOpenHelper(Context context, String dbName, SQLiteDatabase.CursorFactory factory, int version) {
super(context, dbName, factory, version);
}
其中 mContext为Context,Context类会涉及到sqlite的储存路径,为了自定义数据库路径,我们需要实现一个自己的context,来自定义数据库路径,然而Context有一个子类ContextWrapper,可以方便用户对Context进行自定义,看源码中ContextWrapper继承关系如下:
/**
* Proxying implementation of Context that simply delegates all of its calls to
* another Context. Can be subclassed to modify behavior without changing
* the original Context.
*/
public class ContextWrapper extends Context {
Context mBase;
public ContextWrapper(Context base) {
mBase = base;
}
那么,我们就写一个类ContextWrapper来继承ContextWrapper实现自己的context,代码如下:
package com.example.pei.textdemo.sqlite;
import android.content.Context;
import android.content.ContextWrapper;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import com.example.pei.textdemo.util.SDCardUtil;
import java.io.File;
/**
* Title:
* Description:
* <p>
* Created by pei
* Date: 2017/11/20
*/
public class DataBaseContext extends ContextWrapper {
private Context mContext;
public DataBaseContext(Context context){
super(context);
this.mContext=context;
}
/**重写数据库路径方法**/
@Override
public File getDatabasePath(String name) {
// String path1= SDCardUtil.getDiskFilePath(name);
// String dirPath=path1.replace(name,"");
String dirPath=SDCardUtil.getInnerSDCardPath();
String path=null;
File parentFile=new File(dirPath);
if(!parentFile.exists()){
parentFile.mkdirs();
}
String parentPath=parentFile.getAbsolutePath();
if(parentPath.lastIndexOf("\\/")!=-1){
path=dirPath + File.separator + name;
}else{
path=dirPath+name;
}
File file = new File(path);
return file;
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), factory);
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, DatabaseErrorHandler errorHandler) {
return SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name).getAbsolutePath(),factory,errorHandler);
}
}
其中我们需要重写getDatabasePath(String name)方法来自定义自己的数据库存储路径,然后重写ContextWrapper 的两个openOrCreateDatabase方法,代码中SDCardUtil.getInnerSDCardPath()方法代码如下
/**获取内置sdcard路径(数据会保存,应用删除的时候,数据不会被清理掉)**/
public static String getInnerSDCardPath(){
if(isSdcardExist()){
//------/storage/emulated/0/
return Environment.getExternalStorageDirectory() + File.separator;
}
return null;
}
二.编写继承于SQLiteOpenHelper的DBOpenHelper类
我们需要用自己定义的DataBaseContext 来代替之前的 Context,代码如下:
package com.example.pei.textdemo.sqlite;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Title:创建数据库
* Description:
* <p>
* Created by pei
* Date: 2017/11/16
*/
public class DBOpenHelper extends SQLiteOpenHelper{
private static final String DB_NAME = "tf_demo.db";//数据库文件名
private static SQLiteDatabase INSTANCE;
private DataBaseContext mContext;
public SQLiteDatabase getInstance(){
if (INSTANCE == null) {
INSTANCE = new DBOpenHelper(mContext).getWritableDatabase();
}
return INSTANCE;
}
public DBOpenHelper(Context context) {
this(context, DB_NAME, null, 1);
this.mContext= (DataBaseContext) context;
}
public DBOpenHelper(Context context, String dbName, SQLiteDatabase.CursorFactory factory, int version) {
super(context, dbName, factory, version);
}
/**获取数据库路径**/
public String getDBPath(){
return mContext.getDatabasePath(DB_NAME).getAbsolutePath();
}
//首次创建数据库时调用,一般进行建库建表操作
@Override
public void onCreate(SQLiteDatabase db) {
String createTable = "CREATE TABLE IF NOT EXISTS user(_id integer NOT NULL PRIMARY KEY AUTOINCREMENT,\n" +
" name text,\n" +
" sex text,\n" +
" age integer);";
//创建表
db.execSQL(createTable);
}
//当数据库的版本发生变化的时候会自动执行,禁止人为调用
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
三.在DBHelper中调整DBOpenHelper的调用
代码如下:
package com.example.pei.textdemo.sqlite;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.example.pei.textdemo.app.AppContext;
import java.util.List;
/**
* Title:数据库增删改查帮助类
* Description:
* <p>
* Created by pei
* Date: 2017/11/16
*/
public abstract class DBHelper {
protected DBOpenHelper mDBOpenHelper;
private DBOpenHelper getDBOpenHelper(){
if(mDBOpenHelper==null){
// mDBOpenHelper=new DBOpenHelper(AppContext.getInstance());
mDBOpenHelper=new DBOpenHelper(new DataBaseContext(AppContext.getInstance()));
}
return mDBOpenHelper;
}
/**获取数据库对象**/
protected SQLiteDatabase getDateBase(){
return getDBOpenHelper().getInstance();
}
/**关闭数据库**/
protected void closeDB(){
SQLiteDatabase db = getDateBase();
if(db!=null){
db.close();
}
}
/**
* 判断表是否存在
* @param tableName:表名
* @return
*/
protected boolean isTableExist(String tableName){
Cursor cursor = getDateBase().rawQuery("select name from sqlite_master where type='table';", null);
while(cursor.moveToNext()){
//遍历出表名
String name = cursor.getString(0);
if(name.equals(tableName)){
return true;
}
}
return false;
}
/**查询**/
protected abstract List<?> checkAll();
/**添加**/
protected abstract void insert(Object obj);
/**删除**/
protected abstract void delete(Object obj);
/**更新**/
protected abstract void update(Object obj);
}
然后,写一个自己的UserDBHelper类去继承DBHelper,来实现具体的增删改查,就可以愉快的调用了,以下是我写的一个UserDBHelper范例:
public class UserDBHelper extends DBHelper{
private UserDBHelper() {
}
private static class Holder {
private static UserDBHelper instance = new UserDBHelper();
}
public static UserDBHelper getInstance() {
return Holder.instance;
}
@Override
protected List<Person> checkAll() {
List<Person> list = new ArrayList<>();
//COLLATE NOCASE 忽略大小写查询
// Cursor cursor = getDateBase().rawQuery("select * from T_cpz where isqy='True' COLLATE NOCASE;", null);
Cursor cursor = getDateBase().rawQuery("select * from user", null);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String sex = cursor.getString(cursor.getColumnIndex("sex"));
int age=cursor.getInt(cursor.getColumnIndex("age"));
Person person=new Person();
person.setName(name);
person.setSex(sex);
person.setAge(age);
list.add(person);
}
cursor.close();
return list;
}
@Override
protected void insert(Object obj){
Person person= (Person) obj;
String sql="INSERT INTO user(name,sex,age) VALUES('"+ person.getName()+"','"+ person.getSex()+"','"+ person.getAge()+"');";
getDateBase().execSQL(sql);
}
@Override
protected void delete(Object obj) {
Person person = (Person) obj;
String sql = "DELETE FROM user WHERE name='" + person.getName() + "';";
getDateBase().execSQL(sql);
}
@Override
protected void update(Object obj) {
Person person = (Person) obj;
String sql="UPDATE user SET age="+person.getAge()+" WHERE name='"+person.getName()+"';";
getDateBase().execSQL(sql);
}
}
然后在activity中,你可以这样获取数据库存储路径
String dbPath=UserDBHelper.getInstance().getDataBasePath();
LogUtil.e("=====dbPath===000=="+dbPath);
当然,由于你自定义路径会涉及到存储的读写问题,所以要在mainfast总增加相应权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
还要在代码中添加Android7.0以上权限,关于代码授权,这里就不做介绍了。
ok,关于sqlite自定义数据库路径,今天就讲到这里了,谢谢!