您的位置:首页 > 移动开发 > Android开发

Android学习文档之数据库操作

2015-10-19 13:22 686 查看
在项目中,数据库的重要性不言而喻,因为现在几乎所有的东西都是被存储,数据库便是存储数据的一种容器。今天,将由我带领大家一起来学习一下Android中的数据库知识。

今天,我们将按照一个完整项目的要求来模拟一种场景:针对用户联系人进行操作,其项目结构大致如下:



大家可以看到,在我们的项目中包含了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的内容,源码也将在下次奉上,谢谢大家
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: