Android学习文档之数据库操作

在项目中,数据库的重要性不言而喻,因为现在几乎所有的东西都是被存储,数据库便是存储数据的一种容器。今天,将由我带领大家一起来学习一下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的内容,源码也将在下次奉上,谢谢大家




  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值