我们都知道,android为了操作数据库,一般是继承SQLiteOpenHelper类,并实现他的三个函数。

如下所示:

  1. package jz.his.db;
  2.  
  3. import android.content.Context;
  4. import android.database.sqlite.SQLiteDatabase;
  5. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  6. import android.database.sqlite.SQLiteOpenHelper;
  7.  
  8. public class MessageDataBase extends SQLiteOpenHelper {
  9.  
  10. public MessageDataBase(Context context, String name, CursorFactory factory,
  11. int version) {
  12. super(context, name, factory, version);
  13. }
  14.  
  15. @Override
  16. public void onCreate(SQLiteDatabase db) {
  17. db.execSQL("create table lgx_table(_id integer primary key autoincrement ," +
  18. "name varchar(20),content varchar(40),time varchar(20) ,head varchar(20),isCheck byte)");
  19. }
  20.  
  21. @Override
  22. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
  23. }
  24.  
  25. }
  1. </pre><p>可以看到创建了一个名为lgx_table的表,里面有一id,name,content等列。</p><p></p>然后在Activity里,通过getWritableDatabase或者getReadableDatabase()方法来实例化一个SQLiteDatabase<p></p><p></p><pre name="code" class="java">MessageDataBase messageDataBase = new MessageDataBase(context, "lgx", null, 1);
  2. SQLiteDatabase database = messageDataBase.getWritableDatabase();

我们可以看到,创建了一个名字为“lgx”的数据库。

这里提出一个问题,通过以上的步骤后,数据库保存在哪里了呢?

数据库保存在data/data/[your packageName]/databses,

1.如果是模拟器,直接通过Eclipse下,通过这样的步骤去看  DBMS--->File Explorer-->data---->data--->your packageName

  1.  

网上很多介绍,我这里不介绍。

2.如果是真机,首先这个真机是root过了,下载一个Root Explorer。我的测试机是华为荣耀3c。

当我们执行完了以上的步骤后,进入data/data/jz.his.jzhis/databases/会看到这样的情景。

其实lgx就是我们刚刚创建的数据库,lgx-journal是数据库日志。

现在我们知道了,数据库存储的位置了,你以为这就是我写这篇博客的目的?继续往下看吧,嘿嘿。

如果我不想再手机系统内存中保存数据库,而是想将我的数据库放在手机sd卡中,那应该怎么做呢。

首先,我在res/raw中放一个现成的数据库,待会在代码里,将它拷入手机sd卡中。

看下面的代码:

  1. package com.example.province;
  2.  
  3. import java.io.File;
  4. import java.io.FileOutputStream;
  5. import java.io.IOException;
  6. import java.io.InputStream;
  7. import java.util.ArrayList;
  8.  
  9. import android.content.Context;
  10. import android.database.Cursor;
  11. import android.database.sqlite.SQLiteDatabase;
  12. import android.database.sqlite.SQLiteDatabase.CursorFactory;
  13. import android.database.sqlite.SQLiteException;
  14. import android.database.sqlite.SQLiteOpenHelper;
  15. import android.os.Environment;
  16.  
  17. public class CopyOfCityInfoDataSupport2 {
  18. private static CopyOfCityInfoDataSupport2 cityInfoDataSupport;
  19. /**
  20. * 数据库在手机里的路径
  21. */
  22. private static String DATABASE_PATH = Environment
  23. .getExternalStorageDirectory() + "/aaaaa/";
  24. /**
  25. * 数据库的名称
  26. */
  27. public static final String dbName = "mzk_db";
  28. private SQLiteDatabase mSDB;
  29.  
  30. public static CopyOfCityInfoDataSupport2 getInstance(Context context) {
  31. initDataBase(context);
  32. if (cityInfoDataSupport == null) {
  33. cityInfoDataSupport = new CopyOfCityInfoDataSupport2();
  34. }
  35. return cityInfoDataSupport;
  36.  
  37. }
  38.  
  39. /**
  40. * 初试化数据库
  41. */
  42. private static void initDataBase(Context context) {
  43. boolean dbExist = checkDataBase();
  44. if (dbExist) {
  45.  
  46. } else {
  47. // 如果不存在,则将raw里的数据存入手机sd卡
  48. copyDataBase(context);
  49. }
  50. }
  51.  
  52. /**
  53. * 复制数据库到手机指定文件夹下
  54. *
  55. * @throws IOException
  56. */
  57. private static void copyDataBase(Context context) {
  58. String databaseFilenames = DATABASE_PATH + dbName;
  59. File dir = new File(DATABASE_PATH);
  60. FileOutputStream os = null;
  61. InputStream is = null;
  62. // 判断文件夹是否存在,不存在就创建一个
  63. if (!dir.exists()) {
  64. dir.mkdirs();
  65. }
  66. try {
  67. // 得到数据库的输出流
  68. os = new FileOutputStream(databaseFilenames);
  69. // 得到数据文件的输入流
  70. is = context.getResources().openRawResource(R.raw.mzk_db);
  71. byte[] buffer = new byte[8192];
  72. int count = 0;
  73. while ((count = is.read(buffer)) != -1) {
  74. os.write(buffer, 0, count);
  75. os.flush();
  76. }
  77. // 之所以不在这里初始化,是因为这边是静态的方法,而mSDB并没有设置为静态的,也不推荐设为静态的
  78. // mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH +
  79. // dbName, null);
  80. } catch (Exception e) {
  81. e.printStackTrace();
  82. } finally {
  83. try {
  84. os.close();
  85. is.close();
  86. } catch (IOException e) {
  87. e.printStackTrace();
  88. }
  89.  
  90. }
  91.  
  92. }
  93.  
  94. /**
  95. * 判断数据库是否存在
  96. *
  97. * @return
  98. */
  99. private static boolean checkDataBase() {
  100. SQLiteDatabase checkDB = null;
  101. String databaseFilename = DATABASE_PATH + dbName;
  102. // 要自己加上try catch方法
  103. try {
  104. // 返回最新的数据库
  105. checkDB = SQLiteDatabase.openDatabase(databaseFilename, null,
  106. SQLiteDatabase.OPEN_READONLY);
  107. } catch (SQLiteException e) {
  108. // TODO: handle exception
  109. }
  110.  
  111. if (checkDB != null) {
  112. checkDB.close();
  113. }
  114. // 如果checkDB为null,则没有数据库,返回false
  115. return checkDB == null ? false : true;
  116. }
  117.  
  118. /**
  119. * 查询所有省份的信息
  120. *
  121. * @return 省份信息
  122. */
  123. public ArrayList<City> queryProvince() {
  124. // 创建数据库的实例
  125. mSDB = SQLiteDatabase
  126. .openOrCreateDatabase(DATABASE_PATH + dbName, null);
  127. ArrayList<City> list = new ArrayList<City>();
  128. String sql = "select * from fs_province";
  129. Cursor cursor = mSDB.rawQuery(sql, null);
  130. while (cursor.moveToNext()) {
  131. City city = new City();
  132. String id = cursor.getString(cursor.getColumnIndex("ProvinceID"));
  133. String name = cursor.getString(cursor
  134. .getColumnIndex("ProvinceName"));
  135. city.setName(name);
  136. city.setId(id);
  137. list.add(city);
  138. }
  139. if (cursor != null) {
  140. cursor.close();
  141. }
  142. return list;
  143. }
  144.  
  145. public void closeDataBase() {
  146. if (mSDB != null) {
  147. mSDB.close();
  148. }
  149. }
  150. }

我们看到,如果将数据库写到手机sd卡中,都不需要SQLiteOpenHelper类了,而是直接通过

mSDB = SQLiteDatabase.openOrCreateDatabase(DATABASE_PATH + dbName, null);就可以获得数据库的实例了。

但是这个方法有个缺点,就是不能进行数据库的升级了。显然这样是非常不好的。

那么如果我们还想用SQLiteOpenHelper,又将其写到sd卡中,又该怎么做呢。

下面的这段代码是有错误的,你只需要注意看51行,正是因为下面的代码,我才研究了onCreate方法到底什么时候执行。

  1. package jz.his.db;
  2.  
  3. import java.io.BufferedReader;
  4. import java.io.File;
  5. import java.io.FileNotFoundException;
  6. import java.io.FileOutputStream;
  7. import java.io.IOException;
  8. import java.io.InputStream;
  9. import java.io.InputStreamReader;
  10. import java.util.ArrayList;
  11. import java.util.List;
  12.  
  13. import jz.his.jzhis.R;
  14. import android.content.Context;
  15. import android.database.Cursor;
  16. import android.database.sqlite.SQLiteDatabase;
  17. import android.database.sqlite.SQLiteException;
  18. import android.database.sqlite.SQLiteOpenHelper;
  19. import android.os.Environment;
  20. import android.util.Log;
  21.  
  22. public class CityInfoDataSupport extends SQLiteOpenHelper
  23. {
  24. private final static String TAG = "CityInfoDataSupport";
  25. public static final String dbName = "cityego";
  26. // 数据库在手机里的路径
  27. private static String DATABASE_PATH = Environment
  28. .getExternalStorageDirectory().getAbsolutePath()+"/com.bcinfo.pwzs/";
  29. private static int version = 1;
  30. private final String GEOCODING_TABLE_NAME = "GEOCODING";
  31. private SQLiteDatabase mSDB = getReadableDatabase();
  32. private static CityInfoDataSupport mDataSupport;
  33. Context context;
  34.  
  35. public static CityInfoDataSupport getInstance(Context context)
  36. {
  37. initDatabse(context);
  38.  
  39. if (mDataSupport == null)
  40. {
  41. mDataSupport = new CityInfoDataSupport(context);
  42. }
  43. return mDataSupport;
  44. }
  45.  
  46. CityInfoDataSupport(Context context)
  47. {
  48.  
  49. super(context, DATABASE_PATH+dbName, null, version);
  50. }
  51.  
  52. @Override
  53. public void onCreate(SQLiteDatabase db)
  54. {
  55. executeAssetsSQL(db, "geocoding_create.sql");
  56. }
  57.  
  58. @Override
  59. public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
  60. {
  61. String sql = "drop table if exits " + GEOCODING_TABLE_NAME;
  62. db.execSQL(sql);
  63. onCreate(db);
  64. }
  65.  
  66. private void loadSql(SQLiteDatabase db, String schemaName)
  67. {
  68. InputStream inputS;
  69. try
  70. {
  71. inputS = context.getAssets().open(schemaName);
  72. BufferedReader reader = new BufferedReader(new InputStreamReader(inputS));
  73. String sql = null;
  74. while ((sql = reader.readLine()) != null)
  75. {
  76. db.execSQL(sql.replace(";", ""));
  77. }
  78. reader.close();
  79. reader = null;
  80. }
  81. catch (IOException e)
  82. {
  83. // TODO Auto-generated catch block
  84. e.printStackTrace();
  85. }
  86. }
  87.  
  88. /**
  89. * 读取数据库文件(.sql),并执行sql语句
  90. * */
  91. private void executeAssetsSQL(SQLiteDatabase db, String schemaName)
  92. {
  93. Log.e("DataSupport", "executeAssetsSQL");
  94. BufferedReader in = null;
  95. try
  96. {
  97. in = new BufferedReader(new InputStreamReader(context.getAssets().open(schemaName)));
  98. String line;
  99. String buffer = "";
  100. while ((line = in.readLine()) != null)
  101. {
  102. buffer += line;
  103. if (line.trim().endsWith(";"))
  104. {
  105. db.execSQL(buffer.replace(";", ""));
  106. buffer = "";
  107. }
  108. }
  109. }
  110. catch (IOException e)
  111. {
  112. Log.e("db-error", e.toString());
  113. }
  114. finally
  115. {
  116. try
  117. {
  118. if (in != null)
  119. in.close();
  120. }
  121. catch (IOException e)
  122. {
  123. Log.e("db-error", e.toString());
  124. }
  125. }
  126. }
  127.  
  128. public synchronized void insertCityInfo()
  129. {
  130. loadSql(mSDB, "geocoding_data.txt");
  131. }
  132.  
  133. public synchronized List<City> queryDataById(String field, String id)
  134. {
  135. String sql = "";
  136. List<City> cityList = new ArrayList<City>();
  137. if (field.equals("grade"))
  138. {
  139. sql = "select * from " + GEOCODING_TABLE_NAME + " where grade = ? ";
  140. }
  141. else if (field.equals("parent"))
  142. {
  143. sql = "select * from " + GEOCODING_TABLE_NAME + " where parent = ? ";
  144. }
  145. String[] params = new String[]
  146. { id };
  147. Cursor c = mSDB.rawQuery(sql, params);
  148. while (c.moveToNext())
  149. {
  150. City city = new City();
  151. city.setGbCode(c.getString(c.getColumnIndex("gbcode")));
  152. city.setGbName(c.getString(c.getColumnIndex("gbname")));
  153. city.setGrade(c.getString(c.getColumnIndex("grade")));
  154. city.setLongitude(c.getString(c.getColumnIndex("longtitude")));
  155. city.setLatitude(c.getString(c.getColumnIndex("latitude")));
  156. city.setParent(c.getString(c.getColumnIndex("parent")));
  157. cityList.add(city);
  158. }
  159. if (c != null)
  160. {
  161. c.close();
  162. }
  163. return cityList;
  164. }
  165.  
  166. public void deleteAppTempTraffic()
  167. {
  168. String sql = "delete from " + GEOCODING_TABLE_NAME;
  169. mSDB.execSQL(sql);
  170. }
  171.  
  172. public static void initDatabse(Context cntext)
  173. {
  174. boolean dbExist = checkDataBase();
  175. //判断数据库是否存在 不存在就把raw里的数据库写入手机
  176. if (!dbExist)
  177. {
  178. try
  179. {
  180. copyDataBase(cntext);
  181. }
  182. catch (IOException e)
  183. {
  184. throw new Error("Error copying database");
  185. }
  186. }
  187. }
  188.  
  189. /**
  190. * 判断数据库是否存在
  191. * @return false or true
  192. */
  193. public static boolean checkDataBase()
  194. {
  195. SQLiteDatabase checkDB = null;
  196. try
  197. {
  198. String databaseFilename = DATABASE_PATH + dbName;
  199. checkDB = SQLiteDatabase.openDatabase(databaseFilename, null, SQLiteDatabase.OPEN_READONLY);
  200. }
  201. catch (SQLiteException e)
  202. {
  203. }
  204. if (checkDB != null)
  205. {
  206. checkDB.close();
  207. }
  208. return checkDB != null ? true : false;
  209. }
  210.  
  211. /**
  212. * 复制数据库到手机指定文件夹下
  213. * @throws IOException
  214. */
  215. public static void copyDataBase(Context context) throws IOException
  216. {
  217. String databaseFilenames = DATABASE_PATH + dbName;
  218. File dir = new File(DATABASE_PATH);
  219. FileOutputStream os = null;
  220. // 判断文件夹是否存在,不存在就新建一个
  221. if (!dir.exists())
  222. {
  223. dir.mkdirs();
  224. }
  225. try
  226. {
  227. // 得到数据库文件的写入流
  228. os = new FileOutputStream(databaseFilenames);
  229. }
  230. catch (FileNotFoundException e)
  231. {
  232. e.printStackTrace();
  233. }
  234. // 得到数据库文件的数据流
  235. InputStream is = context.getResources().openRawResource(R.raw.cityego);
  236. byte[] buffer = new byte[8192];
  237. int count = 0;
  238. try
  239. {
  240. while ((count = is.read(buffer)) > 0)
  241. {
  242. os.write(buffer, 0, count);
  243. os.flush();
  244. }
  245. }
  246. catch (IOException e)
  247. {
  248. }
  249. try
  250. {
  251. is.close();
  252. os.close();
  253. }
  254. catch (IOException e)
  255. {
  256. e.printStackTrace();
  257. }
  258. }
  259. }

通过上面的这个代码,我的onCreate方法一直没有执行。最终经过我多次试验,我知道了问题所在,所以在这里进行总结。

那么onCreate方法到底什么时候执行呢?

SQLiteOpenHelper的onCreate方法一定是在getReadableDatabase方法之后的

SQLiteDatabase mSDB = getReadableDatabase()这个方法首先检查手机中,是否有已经存在的数据库,如果没有,则执行onCreate方法,如果有,则不执行---->但是,这里有个前提是,你的supre(context, DATABASE_PATH+dbName, null, version),的第二个参数不能是已存在的数据库路径。

我这里,将第二个参数,弄成了已存在的数据库文件,所以onCreate方法永远不会执行。

那么当super(context, dbName, null, version);第二个参数正确和并且执行了getReadableDatabase这个方法,才会在系统内存有数据库。

折磨了我一个下午啊啊啊啊。

由sqlite在手机上的存储位置,引发的onCreate在哪里执行的小结的更多相关文章

  1. docker - 修改镜像/容器文件的在宿主机上的存储位置(转)

    背景 之前在使用docker的时候,由于启动container的时候用的是默认的mount(路径为 /var/lib/docker),这个目录对应的硬盘空间有限,只有200G左右.现在随着程序运行,有 ...

  2. docker - 修改镜像/容器文件或者 "Docker root dir" 的在宿主机上的存储位置

    背景 之前在使用docker的时候,由于启动container的时候用的是默认的mount(路径为 /var/lib/docker),这个目录对应的硬盘空间有限,只有200G左右.现在随着程序运行,有 ...

  3. 由sqlite在手机的内存位置,引起onCreate当运行总结

    转载请注明出处.谢谢:http://blog.csdn.net/harryweasley/article/details/46467495 我们都知道,android为了操作数据库,通常是继承SQLi ...

  4. Vue 在手机上键盘把底部菜单顶上去的解决方案

    Vue 在手机上键盘把底部菜单顶上去的解决方案 ios和安卓的键盘的区别 ios和安卓的键盘的区别弹起方式不同, ios直接弹出键盘, 不影响页面, 而安卓键盘弹起时会把页面顶起来, 这样就会把底部菜 ...

  5. fastclick与zepto的 tap事件关于在手机上click事件的300ms延迟的区别

    之前翻译过一篇关于fastclick的快速点击文章http://www.cnblogs.com/lilyimage/p/3568773.html,fastclick可以解决在手机上点击事件的300ms ...

  6. 如何正确地在手机上显示图片——QImage与QPixmap完全解析

    引言 用Qt程序在手机上显示一幅图片对编程人员来说是再基础不过的一件事情了.那么先让大家看两段代码: //dangerous should not be used, cannot display ea ...

  7. 构建安全的Xml Web Service系列之wse之证书存储位置

    原文:构建安全的Xml Web Service系列之wse之证书存储位置 我们在前几天对xml web service的安全性提出了一些建议,大家可以通过以下地址访问: 构建安全的Xml Web Se ...

  8. 可以在手机上看电脑本地html步骤,我自己总结的哦!

    1.打开控制面板 2.打开程序和功能 3.打开或关闭功能 4.internet信息服务展开后里面所有的都要选中 5.回到桌面,然后右键计算机,选择'管理' 6.先在E盘或者D盘创建一个文件夹,自己随意 ...

  9. ubuntu14.04 rabbitmq安装与使用 --修改RabbitMQ数据存储位置

    参考:https://blog.csdn.net/tianjiewang/article/details/58383062 说明: ubuntu14.04   rabiitmq 默认 安装路径 /va ...

随机推荐

  1. 【Linux】shell数学运算

    在Bash shell环境中,可以利用let.(())和[]执行基本的算术操作.而在进行高级操作时,expr和bc这两个工具就特别有用 let的使用 Script01.sh #!/bin/bash # ...

  2. 变量名解析:LEGB原则

    # -*- coding: cp936 -*- #python 27 #xiaodeng #变量名解析:LEGB原则 ''' L-----local 局部名字空间 E-----enclosing 直接 ...

  3. (转)Content-Disposition的使用和注意事项

    最近不少Web技术圈内的朋友在讨论协议方面的事情,有的说web开发者应该熟悉web相关的协议,有的则说不用很了解.个人认为这要分层次来看待这个问 题,对于一个新手或者刚入门的web开发人员而言,研究协 ...

  4. java 管道流代码示例

    import java.io.IOException;import java.io.PipedInputStream;import java.io.PipedOutputStream; public ...

  5. A. Dreamoon and Stairs(Codeforces Round #272)

    A. Dreamoon and Stairs time limit per test 1 second memory limit per test 256 megabytes input standa ...

  6. protobuf配置与使用

    Protobuf配置与安装 1 安装与配置 1.protobuf是google公司提出的数据存储格式,详细介绍可以参考:https://code.google.com/p/protobuf/ 2.下载 ...

  7. PHP5.4新特性

    PHP5.4 此次更新的关键新特性,包括:新增traits,更精简的Array数组语法,供测试使用的内建webserver,可以闭包使用的$this指针,实例化类成员访问, PHP 5.4.0 性能大 ...

  8. POJ 1836 Alignment (双向DP)

    Alignment Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 10804   Accepted: 3464 Descri ...

  9. iOS - App 与外设间的通信方式

    1.前言 一般 iOS 开发者做 App 开发大部分时候都是通过 Http(s) 请求跟后台服务器打交道,做一些信息展示和用户交互.很少涉及到去跟外部硬件设备连接的开发.随着近年来车联网和物联网的兴起 ...

  10. Interface_GL通过gl_interface导入日记账(案例)

    2014-06-17 BaoXinjian