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

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

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  
时间: 2024-10-13 12:03:44

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

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

使用Android中自带的SQLiteOpenHelper可以完成数据库的创建与管理,但有两点局限: (1)数据库创建在内存卡中,大小受限,创建位置位于/data/data/应用程序名/databases中(可使用Eclispe的DDMS查看). (2)如果无法获取Root权限,则无法直接查看创建的数据库. 鉴于上述限制及实际需要,打算使用SQLiteOpenHelper管理SD卡上的数据库,通过研究SQLiteOpenHelper的源码,发现其创建或打开数据库的代码位于getWritableD

SD卡中FAT32文件格式高速入门(图文具体介绍)

说明: MBR :Master Boot Record ( 主引导记录) DBR :DOS Boot Record ( 引导扇区) FAT :File Allocation Table ( 文件分配表) 硬件:本文SD卡为Kingston 4GB,FAT32格式,簇大小4KB,每扇区512字节. 第一章 硬盘结构与SD卡结构 1.1 硬盘介绍 1.1硬盘结构 假设你熟悉硬盘结构跳过本节.下图是硬盘的结构,假设你仅仅是为了学习SD卡FAT32文件系统的话,这里你仅仅须要注意硬盘排序结构:主引导记录

在SD卡上创建/删除文件夹 使用DDMS透视图管理SD卡

在SD卡上创建和删除文件夹 基本步骤: (1):在控制台中输入adb shell命令,进入shell控制台. (2):在shell控制台中输入cd sdcard 命令,进入SD卡中. (3):在shell控制台中输入ls -al 命令,查看sd卡中包含的全部文件和文件夹. (4):在shell控制台中输入mkdir mrsoft 命令,创建一个名为mrsoft的文件夹. (5):在shell控制台中输入ls -al命令,查看SD卡中包含的全部文件和文件夹.可以看到文件夹mrsoft已经创建. (

微信网页中上传文件时“只能选择SD卡中的文件”问题

需求描述:在微信网页中上传文件到我们自己的服务器,使用 input  type=file标准控件: <input type="file" name="upfile" id="upfile" > 问题来了:苹果可以顺利上传图片文件的,安卓下每次选择完图片文件之后会弹出提示"只能选择SD卡中的文件"不能上传图片.手机已经设置默认存储为SD卡. 百度搜了一个下午没有结果,微信公众平台更没有答案shiiiit. 最后在cs

Android文件存储往SD卡中写入文件路径出错问题求解。

============问题描述============   因为学习需要  看的老罗的视频  关于数据存储往SD卡写文件的那一部分  几乎完全照办的敲的代码   结果在pad上测试的时候和预想的有区别     本来应该存储到SD卡中的文件结果跑到pad自带内存中去了...   然后我尝试过把路径直接自己手动写  还是一样存到了自带内存中  这到底是为什么啊? 顺带吐槽一下万恶的导师  十一还要我们加班 求大神们指导呀~   国庆节玩的开学哟!!! ============解决方案1======

SD卡中的命令CMD

SD卡中的命令是SD控制器和SD卡之间的桥梁,它封装了SD卡的实现细节,不影响SD卡中FLASH的读写变更. 命令的长度是48位,它的字段如图: SD校准定义的CMD如下:

MAC下安装树莓派的镜像到SD卡中

参照http://shumeipai.nxez.com/2014/05/18/raspberry-pi-under-mac-osx-to-install-raspbian-system.html (/dev/disk1s1是分区,/dev/disk1是块设备,/dev/rdisk1是原始字符设备) mac下在将镜像写入sd卡中出现如下情况dd: invalid number '4m' error, 解决方法来自http://www.raspberrypi.org/documentation/in

Android -- 写xml到SD卡中

信息类                                                                                          private String body; private String number; private int type; private long id; 四个变量,然后有分别set和get.构造函数分别初始化这四个变量. 生成xml标签函数                                   

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

[背景] 折腾: [记录]给Android中添加log日志输出到文件 期间,已经试了: [记录]尝试用android中microlog4android实现log输出到文件的功能 但是不好用. 然后就是参考: http://stackoverflow.com/questions/2116260/logging-to-a-file-on-android 去看看: http://code.google.com/p/android-logging-log4j/ [[折腾过程] 1.去: https://