Android学习文档之数据库操作
2015-10-19 13:22
686 查看
在项目中,数据库的重要性不言而喻,因为现在几乎所有的东西都是被存储,数据库便是存储数据的一种容器。今天,将由我带领大家一起来学习一下Android中的数据库知识。
今天,我们将按照一个完整项目的要求来模拟一种场景:针对用户联系人进行操作,其项目结构大致如下:
大家可以看到,在我们的项目中包含了utils包(应用包,主要用来保存一些常用的代码段或功能模块,如读取数据库,文件操作,常量设置等),domain包(又称bean包,用来构造对象),dao包(实现包,用来实现业务逻辑,有些项目将这一块分为dao和daoImpl,其实都是一样的),除此之外,还有什么service包,servlet包等,如果你想了解的更多欢迎前来咨询。
在domain中,我们新建一个UserInfo.java,其代码如下:
在Android中,针对数据库的操作需要继承SQLiteOpenHelper,在继承SQLiteOpenHelper后还需要重写其中的方法,在之前我们已经知道,对数据库的这类操作,我们放在utils包中,在utils包中,我们使用DBHelper来继承SQLiteOpenHelper,其代码如下:
在DBHelper.java文件中,super(context,ConstUtils.DB_NAME, null, ConstUtils.DB_VERSION);这句代码中,第一个参数表示上下文,第二个参数是数据库的名字,第三个是cursor工厂,表示使用什么cursor进行读取,一般我们都默认为系统的,故而设为null,最后一个参数当前数据库版本,默认是1
onCreate方法表示当程序第一次启动时要运行的代码段,如果当前版本没有更改则以后不再运行,故而这里一般都是用于数据库的创建。当版本更新时,如从1变成了3,代码将执行onUpgrade里的内容,这里一般执行一些数据库更改的内容,如新增了字段。
在DBHelper.java文件中我们使用到了一些常量,这些常量保存在ConstUtils.java文件中,其代码如下:
想必大家看到这个常量名就能明白是什么意思了吧?这里不再赘述。
在BaseDao.java中封装了对数据库的一些操作,主要是获取连接和关闭连接,其代码如下:
在UserInfoDao.java中,继承了BaseDao,其代码如下:
在insert方法中,我们主要是调用Android工程师为我们提供的插入方法,如果跟过代码的同学们就会发现他内部的原理就是insert语句。
在insert方法中,因为要插入,需要对数据库进行修改操作,我们首先获得一个可写的数据库连接,db = getWriteConnection();,然后再调用db.insert(ConstUtils.TABLE_USERINFO, null, values);,在这三个参数中,第一个表示要操作的表名,第二个是当插入为空时你希望做的处理,这里我们不做处理,第三个是你要插入的值。新建这个值的时候,你会发现其本身就是一个map类型,其键表示表中的字段,值表示对应字段的内容。调用系统给的插入语句能够返回当前插入的id,当然你也可以自己写sql语句然后通过db.execSQL(sql)来执行。
同样的,在delete方法中我们依然是要先获得一个可写的数据库连接,接着便是调用系统的删除api,在系统的删除api的方法中,需要带入三个参数,第一个是要操作的表名,第二个是where条件语句(不包含where,?表示占位符),第三个参数是where条件中对应的值,如果有多个where条件,其后面的值要对应,否则可能出现意想不到的错误。调用系统的删除api可以返回语句影响的条数。
update的使用方法和delete几乎类似,阅读者可以参照对delete方法的描述。
最后一个便是查找find/query方法了,由于查找不需要对数据库进行修改,只是去取数据库中的值,故而只需要获得一个可读的数据库连接(getReadableDatabase()),在获得连接后,需要在使用系统的query方法,query方法有七个参数,第一个参数是需要操作的表,第二个参数是你想返回的表中的列名称,如果你想返回所有,就置为null,第三个参数是选择条件即where语句,如果不想带任何条件,可置为null,第四个参数是where语句后跟的值,当第三个参数为null时,这个参数也必须为null,第五个参数是groupBy,指的是按照什么字段分组,如果不想分组,可置为null,第六个参数是having,其能力与groupBy差不多(我个人认为),具体可参照sql中关于having的描述,也可置为null,第七个参数是orderBy,指的是按照哪一个字段进行正序或倒叙排序,也可置为null。
在query方法中,如果想查找到所有的内容,则只需带入第一个参数即可。其次,在query方法中有一个cursor,表示游标,即标注当前读取的数据库的位置,有点类似指针,cursor有很多方法,其中最长用的是cursor.moveToNext();cursor.moveToFirst();和cursor.moveToLast(),分别表示往下移动一位,移动到最上面和移动到最下面,在我们遍历表中所有数据的数据时候,一般使用moveToNext,其返回的为布尔值,表示是否还能继续向下移动。
代码写完了,可是我们怎么才知道自己的代码是正确的呢?难道每次都要运行程序么?当然不是的,我们可以通过测试来查看自己的代码段是否正确。
在安卓中,测试一个项目中的代码段和在我们的java项目中不一样,安卓中需要在AndroidManifest.xml中注入如下代码段:
此代码段和uses-sdk统一等级,targetPackage表示你要测试的包的名称,name表示测试的名称,可任意。除了这一段代码外,还需注入
次代码段在application内,表示需要引用的安卓的测试包。
AndroidManifest.xml源码如下:
做完如上操作,我们便可以进行测试了,其测试代码如下:
TestDB.class
测试代码中包含了增删改查的操作,具体操作流程如下
双击选中方法名(如find),然后右键点击出现对话框,选中run as ,选择Android Juit Test,如果结果出现绿色表示通过,红色表示没通过,需要检查代码,这里就不做演示了。
Ok,说了这么多,也不知道大家明白了没有,我相信如果你有一点语言和数据库基础,我想你对前面的知识学起来肯定不是很难。但如果你觉得吃力,那么建议下面的内容暂时先不要学习,先弄懂前面所说的知识。
下一篇我们将介绍适配器和DDMS的内容,源码也将在下次奉上,谢谢大家
今天,我们将按照一个完整项目的要求来模拟一种场景:针对用户联系人进行操作,其项目结构大致如下:
大家可以看到,在我们的项目中包含了utils包(应用包,主要用来保存一些常用的代码段或功能模块,如读取数据库,文件操作,常量设置等),domain包(又称bean包,用来构造对象),dao包(实现包,用来实现业务逻辑,有些项目将这一块分为dao和daoImpl,其实都是一样的),除此之外,还有什么service包,servlet包等,如果你想了解的更多欢迎前来咨询。
在domain中,我们新建一个UserInfo.java,其代码如下:
package com.hackerant.userinfo.domain; public class UserInfo { private int userId; private String userName; private String userPhone; public UserInfo() { super(); } public UserInfo(int userId, String userName, String userPhone) { super(); this.userId = userId; this.userName = userName; this.userPhone = userPhone; } public UserInfo(String userName, String userPhone) { super(); this.userName = userName; this.userPhone = userPhone; } public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserPhone() { return userPhone; } public void setUserPhone(String userPhone) { this.userPhone = userPhone; } @Override public String toString() { return "UserInfo [userId=" + userId + ", userName=" + userName + ", userPhone=" + userPhone + "]"; } }
在Android中,针对数据库的操作需要继承SQLiteOpenHelper,在继承SQLiteOpenHelper后还需要重写其中的方法,在之前我们已经知道,对数据库的这类操作,我们放在utils包中,在utils包中,我们使用DBHelper来继承SQLiteOpenHelper,其代码如下:
package com.hackerant.userinfo.utils; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import android.database.sqlite.SQLiteOpenHelper; public class DBHelper extends SQLiteOpenHelper { public DBHelper(Context context) { super(context, ConstUtils.DB_NAME, null, ConstUtils.DB_VERSION); } @Override public void onCreate(SQLiteDatabase db) { String createUserTable = "create table userinfo(userId integer primary " + "key autoincrement,userName varchar(20),userPhone varchar(20));"; db.execSQL(createUserTable); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { } }
在DBHelper.java文件中,super(context,ConstUtils.DB_NAME, null, ConstUtils.DB_VERSION);这句代码中,第一个参数表示上下文,第二个参数是数据库的名字,第三个是cursor工厂,表示使用什么cursor进行读取,一般我们都默认为系统的,故而设为null,最后一个参数当前数据库版本,默认是1
onCreate方法表示当程序第一次启动时要运行的代码段,如果当前版本没有更改则以后不再运行,故而这里一般都是用于数据库的创建。当版本更新时,如从1变成了3,代码将执行onUpgrade里的内容,这里一般执行一些数据库更改的内容,如新增了字段。
在DBHelper.java文件中我们使用到了一些常量,这些常量保存在ConstUtils.java文件中,其代码如下:
package com.hackerant.userinfo.utils; public class ConstUtils { public static final String DB_NAME = "userinfo.db"; public static final int DB_VERSION = 1; public static final String TABLE_USERINFO = "userinfo"; }
想必大家看到这个常量名就能明白是什么意思了吧?这里不再赘述。
在BaseDao.java中封装了对数据库的一些操作,主要是获取连接和关闭连接,其代码如下:
package com.hackerant.userinfo.dao; import android.content.Context; import android.database.sqlite.SQLiteDatabase; import com.hackerant.userinfo.utils.DBHelper; public class BaseDao { private DBHelper dbHelper; private SQLiteDatabase db; public BaseDao(Context context) { dbHelper = new DBHelper(context); } public SQLiteDatabase getReadConnection(){ db = dbHelper.getReadableDatabase(); return db; } public SQLiteDatabase getWriteConnection(){ db = dbHelper.getWritableDatabase(); return db; } public void closeConnection(){ db.close(); } }
在UserInfoDao.java中,继承了BaseDao,其代码如下:
package com.hackerant.userinfo.dao; import java.util.ArrayList; import java.util.List; import android.content.ContentValues; import android.content.Context; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import com.hackerant.userinfo.domain.UserInfo; import com.hackerant.userinfo.utils.ConstUtils; public class UserInfoDao extends BaseDao { private SQLiteDatabase db; public UserInfoDao(Context context) { super(context); } public long insert(UserInfo userInfo) { long num = -1; db = getWriteConnection(); ContentValues values = new ContentValues(); values.put("userName", userInfo.getUserName()); values.put("userPhone", userInfo.getUserPhone()); num = db.insert(ConstUtils.TABLE_USERINFO, null, values); db.close(); return num; } public int delete(int values) { int num = -1; db = getWriteConnection(); num = db.delete(ConstUtils.TABLE_USERINFO, "userId=?", new String[] { values + "" }); db.close(); return num; } public int update(int id, String phone) { db = getWriteConnection(); int num = -1; ContentValues values = new ContentValues(); values.put("userPhone", phone); num = db.update(ConstUtils.TABLE_USERINFO, values, "userId=?", new String[] { id+"" }); db.close(); return num; } public UserInfo find(int id) { db = getReadConnection(); Cursor cursor = db.query(ConstUtils.TABLE_USERINFO, null, "userId=?", new String[] { id + "" }, null, null, null); cursor.moveToNext(); String userName = cursor.getString(cursor.getColumnIndex("userName")); String userPhone = cursor.getString(cursor.getColumnIndex("userPhone")); UserInfo info = new UserInfo(id,userName, userPhone); db.close(); return info; } public List<UserInfo> findAll() { List<UserInfo> userInfos = new ArrayList<UserInfo>(); db = getReadConnection(); Cursor cursor = db.query(ConstUtils.TABLE_USERINFO, null, null, null, null, null, null); while (cursor.moveToNext()) { int id = cursor.getInt(cursor.getColumnIndex("userId")); String userName = cursor.getString(cursor.getColumnIndex("userName")); String userPhone = cursor.getString(cursor.getColumnIndex("userPhone")); UserInfo info = new UserInfo(id, userName, userPhone); userInfos.add(info); } db.close(); return userInfos; } public SQLiteDatabase getDb() { return db; } public void setDb(SQLiteDatabase db) { this.db = db; } }
在insert方法中,我们主要是调用Android工程师为我们提供的插入方法,如果跟过代码的同学们就会发现他内部的原理就是insert语句。
在insert方法中,因为要插入,需要对数据库进行修改操作,我们首先获得一个可写的数据库连接,db = getWriteConnection();,然后再调用db.insert(ConstUtils.TABLE_USERINFO, null, values);,在这三个参数中,第一个表示要操作的表名,第二个是当插入为空时你希望做的处理,这里我们不做处理,第三个是你要插入的值。新建这个值的时候,你会发现其本身就是一个map类型,其键表示表中的字段,值表示对应字段的内容。调用系统给的插入语句能够返回当前插入的id,当然你也可以自己写sql语句然后通过db.execSQL(sql)来执行。
同样的,在delete方法中我们依然是要先获得一个可写的数据库连接,接着便是调用系统的删除api,在系统的删除api的方法中,需要带入三个参数,第一个是要操作的表名,第二个是where条件语句(不包含where,?表示占位符),第三个参数是where条件中对应的值,如果有多个where条件,其后面的值要对应,否则可能出现意想不到的错误。调用系统的删除api可以返回语句影响的条数。
update的使用方法和delete几乎类似,阅读者可以参照对delete方法的描述。
最后一个便是查找find/query方法了,由于查找不需要对数据库进行修改,只是去取数据库中的值,故而只需要获得一个可读的数据库连接(getReadableDatabase()),在获得连接后,需要在使用系统的query方法,query方法有七个参数,第一个参数是需要操作的表,第二个参数是你想返回的表中的列名称,如果你想返回所有,就置为null,第三个参数是选择条件即where语句,如果不想带任何条件,可置为null,第四个参数是where语句后跟的值,当第三个参数为null时,这个参数也必须为null,第五个参数是groupBy,指的是按照什么字段分组,如果不想分组,可置为null,第六个参数是having,其能力与groupBy差不多(我个人认为),具体可参照sql中关于having的描述,也可置为null,第七个参数是orderBy,指的是按照哪一个字段进行正序或倒叙排序,也可置为null。
在query方法中,如果想查找到所有的内容,则只需带入第一个参数即可。其次,在query方法中有一个cursor,表示游标,即标注当前读取的数据库的位置,有点类似指针,cursor有很多方法,其中最长用的是cursor.moveToNext();cursor.moveToFirst();和cursor.moveToLast(),分别表示往下移动一位,移动到最上面和移动到最下面,在我们遍历表中所有数据的数据时候,一般使用moveToNext,其返回的为布尔值,表示是否还能继续向下移动。
代码写完了,可是我们怎么才知道自己的代码是正确的呢?难道每次都要运行程序么?当然不是的,我们可以通过测试来查看自己的代码段是否正确。
在安卓中,测试一个项目中的代码段和在我们的java项目中不一样,安卓中需要在AndroidManifest.xml中注入如下代码段:
<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.hackerant.userinfo" />
此代码段和uses-sdk统一等级,targetPackage表示你要测试的包的名称,name表示测试的名称,可任意。除了这一段代码外,还需注入
<uses-library android:name="android.test.runner" />
次代码段在application内,表示需要引用的安卓的测试包。
AndroidManifest.xml源码如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.hackerant.userinfo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.hackerant.userinfo" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<uses-library android:name="android.test.runner" />
<activity
android:name="com.hackerant.userinfo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
做完如上操作,我们便可以进行测试了,其测试代码如下:
TestDB.class
package com.hackerant.userinfo.utils; import com.hackerant.userinfo.dao.UserInfoDao; import com.hackerant.userinfo.domain.UserInfo; import android.test.AndroidTestCase; public class TestDB extends AndroidTestCase { // private UserInfoDao dao = new UserInfoDao(getContext()); public void insert(){ for (int i = 0; i < 20; i++) { UserInfoDao dao = new UserInfoDao(getContext()); UserInfo userInfo = new UserInfo("张三" + i , "1506756210" + i); dao.insert(userInfo); } } public void update(){ UserInfoDao dao = new UserInfoDao(getContext()); dao.update(1, "100000000"); } public void find(){ UserInfoDao dao = new UserInfoDao(getContext()); UserInfo userInfo = dao.find(1); System.out.println(userInfo.getUserName()); } public void findAll(){ UserInfoDao dao = new UserInfoDao(getContext()); System.out.println(dao.findAll().size()); } public void delete(){ UserInfoDao dao = new UserInfoDao(getContext()); dao.delete(1); } }
测试代码中包含了增删改查的操作,具体操作流程如下
双击选中方法名(如find),然后右键点击出现对话框,选中run as ,选择Android Juit Test,如果结果出现绿色表示通过,红色表示没通过,需要检查代码,这里就不做演示了。
Ok,说了这么多,也不知道大家明白了没有,我相信如果你有一点语言和数据库基础,我想你对前面的知识学起来肯定不是很难。但如果你觉得吃力,那么建议下面的内容暂时先不要学习,先弄懂前面所说的知识。
下一篇我们将介绍适配器和DDMS的内容,源码也将在下次奉上,谢谢大家
相关文章推荐
- Android系统的编译命令
- Android aidl 使用总结
- Android DownloadManager下载完成事件监听(系列4)
- [Android] 环境配置之Android Studio开发NDK
- android studio下的NDK开发详解
- android全屏与非全屏的切换设置
- Android Studio通过JNI调用NDK程序
- AndroidMainfest启动模式
- ListView卡顿优化过程,并解决与viewpager图片加载冲突的问题
- Android汉字转拼音
- 【Android】Activity右滑返回的实现
- Android DownloadManager下载进度查询(系列3)
- android项目的结构和布局
- 豆浆机改装记(0): 为什么要改装豆浆机!
- 奇虎360 android 安全卫士 root核签名认证分析
- Android Studio获取SHA1和MD5值的方法
- 如何升级到RxAndroid 1.0
- android中用ExpandableListView实现三级扩展列表(附源码)
- 解决Android 弹出软键盘将整个界面上移的问题
- Android属性动画完全解析(下),Interpolator和ViewPropertyAnimator的用法