本人在网上找了好多大牛的资料,研究了几天终于调试出来了。以下是笔记;
SQLiteOpenHelper是Android框架为我们提供的一个非常好的数据库打开、升级与关闭的工具类。但是这个工具类会自动把db文件创建到“ /data/data/com.*.*(package name)/” 目录下,这么做可能是与Android文件系统的设计思路有关。
但是在实战过程中,我们可能有各种原因需要自定义db文件路径(例如db文件较大放到sd卡更安全等等),相信很多人都遇到了这个需求,网上也有很多解决方法,这些方法大多是抛弃Android框架为我们提供的SQLiteOpenHelper类,自己重头写一个DbHelper类完成自定义路径的数据库打开关闭等。这么做虽然可以解决问题,但并不是一个最好的方法,因为自己写的DbHelper可靠性和功能自然难和google巨匠相提并论。
所以可以采用这样一种方法,通过继承和添加代码,并复用SQLiteOpenHelper的代码,来解决自定义db路径的问题。
首先我们来分析一下SQLiteOpenHelper的源代码。getReadableDatabase()和getWritableDatabase()在内部都是调用getDatabaseLocked()。getDatabaseLocked()的源代码很容易理解,分析得知:
- 如果以只读方式打开,是通过mContext.getDatabasePath(mName)来获取db文件的路径并使用SQLiteDatabase.openDatabase()直接打开数据库;
- 如果以读写方式打开,是通过mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ? Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0, mFactory, mErrorHandler)打开或创建数据库。
所以我们需要改变mContext的行为。Android框架提供了一个ContextWrapper类,是Context的一个代理,可以通过继承的方式拉改变Context的行为,所以我们继承ContextWrapper,复写它的openOrcreatDatabase()方法,然后实例化SQLiteOpenHelper时,传我们复写的Context进去就可以了。
代码如下:
1 package com.slc.qhfpsj.DAO; 2 3 import android.content.Context; 4 import android.content.ContextWrapper; 5 import android.database.DatabaseErrorHandler; 6 import android.database.sqlite.SQLiteDatabase; 7 import android.util.Log; 8 9 import java.io.File; 10 11 /** 12 * Created by Administrator on 2015/11/22. 13 * Coder:Mengjinluohua 14 * version:1.0 15 */ 16 public class DatabaseContext extends ContextWrapper { 17 public DatabaseContext(Context base) { 18 super(base); 19 } 20 21 /** 22 * 获得数据库路径,如果不存在,则创建对象对象 23 * 24 * @param name 25 * 26 */ 27 @Override 28 public File getDatabasePath(String name) { 29 // return super.getDatabasePath(name); 30 //判断是否存在sd卡 31 boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState()); 32 if (!sdExist) {//如果不存在, 33 Log.e("SD卡管理:", "SD卡不存在,请加载SD卡"); 34 return null; 35 } else {//如果存在 36 //获取sd卡路径 37 // String dbDir= FileUtils.getFlashBPath(); 38 String dbDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();//sd卡路径 39 dbDir += "/DB";//数据库所在目录 在这里修改SD卡下文件的保存路径 40 // String dbPath = dbDir + "/" + name;//数据库路径 41 File dbfile = getFilePath(dbDir, name); 42 return dbfile; 43 44 } 45 } 46 47 48 private File getFilePath(String dbDir, String name) { 49 File file = null; 50 makeRootDirectory(dbDir); 51 try { 52 file = new File(dbDir+ "/" + name); 53 } catch (Exception e) { 54 // TODO Auto-generated catch block 55 e.printStackTrace(); 56 } 57 return file; 58 59 60 } 61 62 private void makeRootDirectory(String dbPath) { 63 File file = null; 64 try { 65 file = new File(dbPath); 66 if (!file.exists()) { 67 file.mkdir(); 68 } 69 } catch (Exception e) { 70 71 } 72 } 73 74 75 76 @Override 77 public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) { 78 SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null); 79 return result; 80 } 81 @Override 82 public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory, 83 DatabaseErrorHandler errorHandler) { 84 SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null); 85 return result; 86 } 87 88 }
然后我们在继承SQLiteOpenHelper时这么写就可以了:
1 package com.slc.qhfpsj.DAO; 2 3 import android.content.Context; 4 import android.database.SQLException; 5 import android.database.sqlite.SQLiteDatabase; 6 import android.database.sqlite.SQLiteOpenHelper; 7 import android.util.Log; 8 9 /** 10 * Created by Administrator on 2015/11/23. 11 * Coder:Mengjinluohua 12 * version:1.0 13 */ 14 public class SdCardDBHelper extends SQLiteOpenHelper { 15 16 public static final String TAG = "SdCardDBHelper"; 17 /** 18 * 数据库名称 19 **/ 20 public static String DATABASE_NAME = "sddb.db"; 21 22 /** 23 * 数据库版本 24 **/ 25 public static int DATABASE_VERSION = 2; 26 27 /** 28 * 构造函数 29 * 30 * @param context 上下文环境 31 **/ 32 public SdCardDBHelper(Context context) { 33 super(context, DATABASE_NAME, null, DATABASE_VERSION); 34 } 35 36 @Override 37 public void onCreate(SQLiteDatabase db) { 38 Log.e(TAG, "开始创建数据库表"); 39 try{ 40 //创建用户表(user) 41 db.execSQL("create table PovertyFamilyMumberListInfoTab (_id integer primary key autoincrement,name varchar(20)," + 42 "ID varchar(30),sex varchar(10),relationship varchar(20),people varchar(10),educationDegree varchar(30),studentCondition varchar(30)," + 43 "healthCondition varchar(30),workAbility varchar(30),workCondition varchar(30),workTime varchar(30),isJoinVillageMedical integer(10)," + 44 "isJoinCityOrTownMedical integer(10))"); 45 Log.e(TAG, "创建离线所需数据库表成功"); 46 47 } 48 catch(SQLException se){ 49 se.printStackTrace(); 50 Log.e(TAG, "创建离线所需数据库表失败"); 51 52 53 } 54 55 } 56 57 @Override 58 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 59 60 } 61 }
这样使用:建立一个 DAO类 操作数据库
1 public class Jbqk_listinfoDAO { 2 3 private final SdCardDBHelper sdCardDBHelper; 4 5 public Jbqk_listinfoDAO(Context context) { 6 DatabaseContext databaseContext = new DatabaseContext(context); 7 sdCardDBHelper = new SdCardDBHelper(databaseContext); 8 } 9 10 public boolean add(String name, String sex, String ID, String relationship, String people, String educationDegree, String studentCondition, 11 String healthCondition, 12 String workAbility, String workCondition, String workTime, String isJoinVillageMedical, String isJoinCityOrTownMedical) { 13 14 SQLiteDatabase db = sdCardDBHelper.getWritableDatabase(); 15 ContentValues contentValues = new ContentValues(); 16 contentValues.put("ID", ID); 17 contentValues.put("name", name); 18 contentValues.put("sex", sex); 19 contentValues.put("relationship", relationship); 20 contentValues.put("people", people); 21 contentValues.put("educationDegree", educationDegree); 22 contentValues.put("studentCondition", studentCondition); 23 contentValues.put("healthCondition", healthCondition); 24 contentValues.put("workAbility", workAbility); 25 contentValues.put("workCondition", workCondition); 26 contentValues.put("workTime", workTime); 27 contentValues.put("isJoinVillageMedical", isJoinVillageMedical); 28 contentValues.put("isJoinCityOrTownMedical", isJoinCityOrTownMedical); 29 30 long rowid = db.insert("PovertyFamilyMumberListInfoTab", null, contentValues); 31 32 if (rowid == -1) { 33 return false; 34 } else { 35 return true; 36 } 37 38 39 } 40 }
测试代码:
1 public void testAdd() { 2 DatabaseContext databaseContext = new DatabaseContext(mcontext); 3 Jbqk_listinfoDAO Dao = new Jbqk_listinfoDAO(databaseContext); 4 5 6 for (int i = 0; i < Cheeses.name.length; i++) { 7 String name = Cheeses.name[i]; 8 String ID = Cheeses.ID[i]; 9 String sex = Cheeses.sex[i]; 10 String relationship = Cheeses.relationship[i]; 11 String people = Cheeses.people[i]; 12 String educationDegree = Cheeses.educationDegree[i]; 13 String studentCondition = Cheeses.studentCondition[i]; 14 String healthCondition = Cheeses.healthCondition[i]; 15 String workAbility = Cheeses.workAbility[i]; 16 String workCondition = Cheeses.workCondition[i]; 17 String workTime = Cheeses.workTime[i]; 18 String isJoinVillageMedical = Cheeses.isJoinVillageMedical[i]; 19 String isJoinCityOrTownMedical = Cheeses.isJoinCityOrTownMedical[i]; 20 21 boolean add = Dao.add(name, sex, ID, relationship, people, educationDegree, studentCondition, healthCondition, 22 workAbility, workCondition, workTime, isJoinVillageMedical, isJoinCityOrTownMedical); 23 } 24 } 25 26 27