本人在网上找了好多大牛的资料,研究了几天终于调试出来了。以下是笔记;

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进去就可以了。

代码如下:

 package com.slc.qhfpsj.DAO;

 import android.content.Context;
import android.content.ContextWrapper;
import android.database.DatabaseErrorHandler;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log; import java.io.File; /**
* Created by Administrator on 2015/11/22.
* Coder:Mengjinluohua
* version:1.0
*/
public class DatabaseContext extends ContextWrapper {
public DatabaseContext(Context base) {
super(base);
} /**
* 获得数据库路径,如果不存在,则创建对象对象
*
* @param name
*
*/
@Override
public File getDatabasePath(String name) {
// return super.getDatabasePath(name);
//判断是否存在sd卡
boolean sdExist = android.os.Environment.MEDIA_MOUNTED.equals(android.os.Environment.getExternalStorageState());
if (!sdExist) {//如果不存在,
Log.e("SD卡管理:", "SD卡不存在,请加载SD卡");
return null;
} else {//如果存在
//获取sd卡路径
// String dbDir= FileUtils.getFlashBPath();
String dbDir = android.os.Environment.getExternalStorageDirectory().getAbsolutePath();//sd卡路径
dbDir += "/DB";//数据库所在目录 在这里修改SD卡下文件的保存路径
// String dbPath = dbDir + "/" + name;//数据库路径
File dbfile = getFilePath(dbDir, name);
return dbfile; }
} private File getFilePath(String dbDir, String name) {
File file = null;
makeRootDirectory(dbDir);
try {
file = new File(dbDir+ "/" + name);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return file; } private void makeRootDirectory(String dbPath) {
File file = null;
try {
file = new File(dbPath);
if (!file.exists()) {
file.mkdir();
}
} catch (Exception e) { }
} @Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
return result;
}
@Override
public SQLiteDatabase openOrCreateDatabase(String name, int mode, SQLiteDatabase.CursorFactory factory,
DatabaseErrorHandler errorHandler) {
SQLiteDatabase result = SQLiteDatabase.openOrCreateDatabase(getDatabasePath(name), null);
return result;
} }

然后我们在继承SQLiteOpenHelper时这么写就可以了:

 package com.slc.qhfpsj.DAO;

 import android.content.Context;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log; /**
* Created by Administrator on 2015/11/23.
* Coder:Mengjinluohua
* version:1.0
*/
public class SdCardDBHelper extends SQLiteOpenHelper { public static final String TAG = "SdCardDBHelper";
/**
* 数据库名称
**/
public static String DATABASE_NAME = "sddb.db"; /**
* 数据库版本
**/
public static int DATABASE_VERSION = 2; /**
* 构造函数
*
* @param context 上下文环境
**/
public SdCardDBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
} @Override
public void onCreate(SQLiteDatabase db) {
Log.e(TAG, "开始创建数据库表");
try{
//创建用户表(user)
db.execSQL("create table PovertyFamilyMumberListInfoTab (_id integer primary key autoincrement,name varchar(20)," +
"ID varchar(30),sex varchar(10),relationship varchar(20),people varchar(10),educationDegree varchar(30),studentCondition varchar(30)," +
"healthCondition varchar(30),workAbility varchar(30),workCondition varchar(30),workTime varchar(30),isJoinVillageMedical integer(10)," +
"isJoinCityOrTownMedical integer(10))");
Log.e(TAG, "创建离线所需数据库表成功"); }
catch(SQLException se){
se.printStackTrace();
Log.e(TAG, "创建离线所需数据库表失败"); } } @Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { }
}

这样使用:建立一个 DAO类 操作数据库

 public class Jbqk_listinfoDAO {

     private final SdCardDBHelper sdCardDBHelper;

     public Jbqk_listinfoDAO(Context context) {
DatabaseContext databaseContext = new DatabaseContext(context);
sdCardDBHelper = new SdCardDBHelper(databaseContext);
} public boolean add(String name, String sex, String ID, String relationship, String people, String educationDegree, String studentCondition,
String healthCondition,
String workAbility, String workCondition, String workTime, String isJoinVillageMedical, String isJoinCityOrTownMedical) { SQLiteDatabase db = sdCardDBHelper.getWritableDatabase();
ContentValues contentValues = new ContentValues();
contentValues.put("ID", ID);
contentValues.put("name", name);
contentValues.put("sex", sex);
contentValues.put("relationship", relationship);
contentValues.put("people", people);
contentValues.put("educationDegree", educationDegree);
contentValues.put("studentCondition", studentCondition);
contentValues.put("healthCondition", healthCondition);
contentValues.put("workAbility", workAbility);
contentValues.put("workCondition", workCondition);
contentValues.put("workTime", workTime);
contentValues.put("isJoinVillageMedical", isJoinVillageMedical);
contentValues.put("isJoinCityOrTownMedical", isJoinCityOrTownMedical); long rowid = db.insert("PovertyFamilyMumberListInfoTab", null, contentValues); if (rowid == -1) {
return false;
} else {
return true;
} }
}

测试代码:

  public void testAdd() {
DatabaseContext databaseContext = new DatabaseContext(mcontext);
Jbqk_listinfoDAO Dao = new Jbqk_listinfoDAO(databaseContext); for (int i = 0; i < Cheeses.name.length; i++) {
String name = Cheeses.name[i];
String ID = Cheeses.ID[i];
String sex = Cheeses.sex[i];
String relationship = Cheeses.relationship[i];
String people = Cheeses.people[i];
String educationDegree = Cheeses.educationDegree[i];
String studentCondition = Cheeses.studentCondition[i];
String healthCondition = Cheeses.healthCondition[i];
String workAbility = Cheeses.workAbility[i];
String workCondition = Cheeses.workCondition[i];
String workTime = Cheeses.workTime[i];
String isJoinVillageMedical = Cheeses.isJoinVillageMedical[i];
String isJoinCityOrTownMedical = Cheeses.isJoinCityOrTownMedical[i]; boolean add = Dao.add(name, sex, ID, relationship, people, educationDegree, studentCondition, healthCondition,
workAbility, workCondition, workTime, isJoinVillageMedical, isJoinCityOrTownMedical);
}
}

使用SQLiteOpenHelper管理SD卡中的数据库的更多相关文章

  1. Android中使用SQLiteOpenHelper管理SD卡中的数据库

    使用Android中自带的SQLiteOpenHelper可以完成数据库的创建与管理,但有两点局限: (1)数据库创建在内存卡中,大小受限,创建位置位于/data/data/应用程序名/databas ...

  2. android 将项目下的数据库拷贝到sd卡中

    /** * 将项目下的数据库拷贝到sd卡中 */ public static boolean copyDbToSdCard() { FileInputStream fis = null; FileOu ...

  3. 与众不同 windows phone (37) - 8.0 文件系统: StorageFolder, StorageFile, 通过 Uri 引用文件, 获取 SD 卡中的文件

    [源码下载] 与众不同 windows phone (37) - 8.0 文件系统: StorageFolder, StorageFile, 通过 Uri 引用文件, 获取 SD 卡中的文件 作者:w ...

  4. android中拷贝assets下的资源文件到SD卡中(可以超过1M)

    很多手机游戏,在安装APK之后都得需要下载相应的资源包,然后才能进入游戏. 有这样一个需求:就是游戏中需要的资源包打在APK内,随apk一起进行安装到手机中. 这样就不需要,在安装APK之后,去下载资 ...

  5. Android -- 拷贝assets下的资源文件到SD卡中(可以超过1M)

    很多手机游戏,在安装APK之后都得需要下载相应的资源包,然后才能进入游戏. 有这样一个需求:就是游戏中需要的资源包打在APK内,随apk一起进行安装到手机中. 这样就不需要,在安装APK之后,去下载资 ...

  6. 获取SD卡中的音乐文件

    小编近期在搞一个音乐播放器App.练练手: 首先遇到一个问题.怎么获取本地的音乐文件? /** * 获取SD卡中的音乐文件 * * @param context * @return */ public ...

  7. 【记录】尝试用android-logging-log4j去实现log输出内容到sd卡中的文件的功能

    [背景] 折腾: [记录]给Android中添加log日志输出到文件 期间,已经试了: [记录]尝试用android中microlog4android实现log输出到文件的功能 但是不好用. 然后就是 ...

  8. Android--手持PDA读取SD卡中文件

    近两年市场上很多Wince设备都开始转向Android操作系统,最近被迫使用Android开发PDA手持设备.主要功能是扫描登录,拣货,包装,发货几个功能.其中涉及到商品档的时候大概有700左右商品要 ...

  9. android 读取sd卡中的图片

    一.获取读取SD卡的权限 <!--在SDCard中创建与删除文件权限  -->    <uses-permission android:name="android.perm ...

随机推荐

  1. 删除文件时提示“找不到该项目”,怎么解决? 转摘自:http://jingyan.baidu.com/article/e4d08ffdf5ab470fd2f60df4.html

    故障现象:在使用Windows系统删除文件或者文件夹的时候,有时会出现“找不到该项目”的错误提示,可能再次“重试”也无济于事. 那么,接下来T库小编就为库友们简单概括一下出现该问题的原因. 故障原因: ...

  2. 【Database】MySQL实战45讲

    01 | 基础架构:一条SQL查询语句是如何执行的? 1. MySQL 的基本架构图: MySQL可以分成: Server层 和 存储引擎层 两部分. Server层:包含连接器.查询缓存.分析器.优 ...

  3. 使用CSS3的@media来编写响应式的页面

    首先要知道,我们为什么要写自适应的页面(响应式页面) [直接看干货] 众所周知,电脑.平板.手机的屏幕是差距很大的,假如在电脑上写好了一个页面,在电脑上看起来不错,但是如果放到手机上的话,那可能就会乱 ...

  4. js 输入整数

    1.我用 /^\+?[1-9][0-9]*$/ 貌似不对(小数也可以输入) 2.输入整数  n = /^[1-9]\d*$/; . -]\d*$/; //判断字符串是否为数字 if (!value) ...

  5. css雪碧图实现数字切换

    vue中 css 雪碧图应用及数字切换demo 1. CSS Sprites一般只能使用到固定大小的盒子(box)里,这样才能够遮挡住不应该看到的部分. 2.使用css雪碧图的优点: 利用CSS Sp ...

  6. oracle的查询结果按照in条件顺序输出

    业务需要,通过lucene查出符合搜索条件的id,然后在详情表里查出这些id的详情 ? 1 SELECT id,QUESTION,QUESTIONCOMMENT FROM "ASKDBA_Q ...

  7. Session 工作原理

    Session 工作原理 1.创建Session 当用户访问到一个服务器,如果服务器启用Session,服务器就要为该用户创建一个SESSION,在创建这个SESSION的时候,服务器首先检查这个用户 ...

  8. 【LeetCode 36】有效的数独

    题目链接 [题解] 就一傻逼模拟题 [代码] class Solution { public: bool isValidSudoku(vector<vector<char>>& ...

  9. AcWing 228. 异或 (dfs+线性基)打卡

    题目:https://www.acwing.com/problem/content/230/ 题意:有一个图,每条边有一个权值,现在求1-n的一条路径的最大异或和,一条边能经过多次,相应的也要计算那么 ...

  10. Python之-异常处理

    1.python中处理异常的方式 #coding:utf8 filename=raw_input("请输入你要操作的文件") try: f=open(filename) print ...