`
onewayonelife
  • 浏览: 259732 次
  • 性别: Icon_minigender_1
  • 来自: 太原
社区版块
存档分类
最新评论

Android学习笔记(十一)

阅读更多

SQLite数据库的CRUD

 

DBActivity

package org.wp.db;

/**
 * 嵌入式关系型数据库
 * SQLite
 * SQLite最大的特点是你可以保存任何类型的数据到任何字段中,无论这列声明的数据类型是什么
 * 但有一种情况例外:定义为INTEGER PRIMARY KEY的字段只能存储64位整数
 * 当向这种字段中保存除整数以外的数据时,将会产生错误
 * 另外, SQLite 在解析CREATE TABLE 语句时,会忽略 CREATE TABLE 语句中跟在字段名后面的数据类型信息
 * 
 * SQLite可以解析大部分标准SQL语句,如:
 * 查询语句:select * from 表名  where 条件子句  group by 分组字句  having ... order by 排序子句
 * 分页SQL与mysql类似,下面SQL语句获取5条记录,跳过前面3条记录
 * select * from Account limit 5 offset 3 或者  select * from Account limit 3,5
 * 插入语句:insert into 表名(字段列表) values(值列表)
 * 更新语句:update 表名 set 字段名 = 值  where 条件子句
 * 删除语句:delete from 表名 where 条件子句
 * 
 */

import org.wp.service.DataBaseOpenHelper;
import android.app.Activity;
import android.database.sqlite.SQLiteDatabase;
import android.os.Bundle;

public class DBActivity extends Activity {
	
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		/**
		 * 第一次调用getWritableDatabase()或getReadableDatabase()方法后
		 * SQLiteOpenHelper会缓存当前的SQLiteDatabase实例
		 * SQLiteDatabase实例正常情况下会维持数据库的打开状态
		 * 所以在你不再需要SQLiteDatabase实例时
		 * 请及时调用close()方法释放资源 ,一旦SQLiteDatabase实例被缓存
		 * 多次调用getWritableDatabase()或getReadableDatabase()方法得到的都是同一实例
		 */

		DataBaseOpenHelper dataBaseOpenHelper = new DataBaseOpenHelper(
				DBActivity.this);
		SQLiteDatabase database = dataBaseOpenHelper.getWritableDatabase();
		database.execSQL("insert into person(name, age) values(?,?)",
				new Object[] { "张三", 9 });
		database.close();
	}
}

 

DataBaseOpenHelper

package org.wp.service;

/**
 * 在Android系统,为我们提供了一个名为SQLiteOpenHelper的类
 * 该类用于对数据库版本进行管理,该类是一个抽象类,必须继承它才能使用
 * 为了实现对数据库版本进行管理,SQLiteOpenHelper类有两种重要的方法
 * 分别是onCreate(SQLiteDatabase db) 和  onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 
 *  
 * 当调用SQLiteOpenHelper的getWritableDatabase()或者getReadableDatabase()方法
 * 获取用于操作数据库的SQLiteDatabase实例的时候
 * 如果数据库不存在,Android系统会自动生成一个数据库,接着调用onCreate()方法
 * onCreate()方法在初次生成数据库时才会被调用
 * 在onCreate()方法里可以生成数据库表结构及添加一些应用使用到的初始化数据
 * onUpgrade()方法在数据库的版本发生变化时会被调用,数据库的版本是由程序员控制的
 * 假设数据库现在的版本是1,由于业务的需要,修改了数据库表的结构,这时候就需要升级软件
 * 升级软件时希望更新用户手机里的数据库表结构,为了实现这一目的,可以把原来的数据库版本设置为2
 * 并且在onUpgrade()方法里面实现表结构的更新
 * 当软件的版本升级次数比较多,这时在onUpgrade()方法里面可以根据原版号和目标版本号进行判断
 * 然后作出相应的表结构及数据更新
 * 
 * getWritableDatabase()和getReadableDatabase()方法都可以获取一个用于操作数据库的SQLiteDatabase实例
 * 但getWritableDatabase()方法以读写方式打开数据库,一旦数据库的磁盘空间满了,数据库就只能读而不能写
 * 倘若使用的是getWritableDatabase()方法就会出错
 * 
 * getReadableDatabase()方法先以读写方式打开数据库,如果数据库的磁盘空间满了,就会打开失败
 * 当打开失败后会继续尝试以只读方式打开数据库
 * 
 */

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DataBaseOpenHelper extends SQLiteOpenHelper {

	// 类没有实例化,是不能用作父类构造器的参数,必须声明为静态
	private static final String DBNAME = "wp";// 数据库名称
	private static final int VERSION = 1;// 数据库版本

	public DataBaseOpenHelper(Context context) {
		// 第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
		super(context, DBNAME, null, VERSION);
	}

	@Override
	public void onCreate(SQLiteDatabase db) {
		db.execSQL("create table person(personid integer primary key autoincrement,name varchar(20),age integer)");
	}

	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		db.execSQL("drop table if exists person");
		onCreate(db);
	}

}

 

PersonService

package org.wp.service;

/**
 * Android 提供了一个名为SQLiteDatabase的类
 * 该类封装了一些操作数据库的API,使用该类可以完成对数据CRUD操作
 */

import java.util.ArrayList;
import java.util.List;
import org.wp.domain.Person;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class PersonService {
	private DataBaseOpenHelper dataBaseOpenHelper;
	private SQLiteDatabase database;

	public PersonService(Context context) {
		dataBaseOpenHelper = new DataBaseOpenHelper(context);
	}

	public void save(Person person) {
		database = dataBaseOpenHelper.getWritableDatabase();
		database.execSQL("insert into person(name,age) values(?,?)",
				new Object[] { person.getName(), person.getAge() });
		// database.close();
	}

	/**
	 * Java1.5 增加了新特性 可变参数 适用于参数个数不确定,类型确定的情况,Java把可变参数当做数组处理。
	 * 
	 * @param ids
	 */
	public void delete(Integer... ids) {
		if (ids.length > 0) {
			StringBuilder sb = new StringBuilder();
			for (Integer id : ids) {
				sb.append('?').append(',');
			}
			sb.deleteCharAt(sb.length() - 1);
			database = dataBaseOpenHelper.getWritableDatabase();
			database.execSQL(
					"delete from person where personid in(" + sb + ")",
					(Object[]) ids);
		}
	}

	public void update(Person person) {
		database = dataBaseOpenHelper.getWritableDatabase();
		database.execSQL("update person set name=?,age=? where personid=?",
				new Object[] { person.getName(), person.getAge(),
						person.getPersonid() });
	}

	public Person find(Integer id) {
		database = dataBaseOpenHelper.getReadableDatabase();
		/**
		 * Cursor是结果集游标,用于对结果集进行随机访问 使用moveToNext()方法可以将游标从当前行移动到下一行
		 * 如果已经移过了结果集的最后一行,返回结果为false,否则为true 
		 * 另外Cursor 还有常用的
		 * moveToPrevious()方法
		 * 用于将游标从当前行移动到上一行,如果已经移过了结果集的第一行,返回值为false,否则为true 
		 * moveToFirst()方法
		 * 用于将游标移动到结果集的第一行,如果结果集为空,返回值为false,否则为true 
		 * moveToLast()方法
		 * 用于将游标移动到结果集的最后一行,如果结果集为空,返回值为false,否则为true
		 */
		Cursor cursor = database.rawQuery(
				"select * from person where personid=?", new String[] { String
						.valueOf(id) });
		if (cursor.moveToNext()) {
			return new Person(cursor.getInt(0), cursor.getString(1), cursor
					.getShort(2));
		}
		return null;
	}

	/**
	 * 
	 * SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset    
	 * LIMIT 子句可以被用于强制 SELECT 语句返回指定的记录数
	 * LIMIT 接受一个或两个数字参数。参数必须是一个整数常量
	 * 如果给定两个参数,第一个参数指定第一个返回记录行的偏移量,第二个参数指定返回记录行的最大数目
	 * 初始记录行的偏移量是 0(而不是 1):
	 * SELECT * FROM table LIMIT 5,10; // 检索记录行 6-15   
	 * 为了检索从某一个偏移量到记录集的结束所有的记录行,可以指定第二个参数为 -1 
	 * SELECT * FROM table LIMIT 95,-1;     // 检索记录行 96-last.   
	 * 如果只给定一个参数,它表示返回最大的记录行数目:   
	 * SELECT * FROM table LIMIT 5; //检索前 5 个记录行   
	 * 换句话说,LIMIT n 等价于 LIMIT 0,n。
	 * 
	 */
	public List<Person> getScrollData(int startResult, int maxResult) {
		List<Person> persons = new ArrayList<Person>();
		database = dataBaseOpenHelper.getWritableDatabase();
		Cursor cursor = database.rawQuery("select * from person limit ?,?",
				new String[] { String.valueOf(startResult),
						String.valueOf(maxResult) });
		while (cursor.moveToNext()) {
			persons.add(new Person(cursor.getInt(0), cursor.getString(1),
					cursor.getShort(2)));
		}
		return persons;
	}

	public long getCount() {
		database = dataBaseOpenHelper.getReadableDatabase();
		Cursor cursor = database.rawQuery("select count(*) from person ", null);
		while (cursor.moveToNext()) {
			return cursor.getLong(0);
		}
		return 0;
	}
}

 

OtherPersonService

package org.wp.service;

/**
 * Insert()方法用于添加数据,各个字段的数据使用ContentValues进行存放
 * ContentValues类似于MAP,相对于MAP,它提供了存取数据对应的
 * put(String key, Xxx value)和getAsXxx(String key)方法 
 * key为字段名称,value为字段值,Xxx指的是各种常用的数据类型
 * 如:String、Integer等
 * long rowid = db.insert("person", null, values);//返回新添记录的行号,与主键id无关
 * 
 */

import java.util.ArrayList;
import java.util.List;
import org.wp.domain.Person;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;

public class OtherPersonService {
	private DataBaseOpenHelper dataBaseOpenHelper;
	private SQLiteDatabase database;

	public OtherPersonService(Context context) {
		dataBaseOpenHelper = new DataBaseOpenHelper(context);
	}

	/**
	 * 
	 * database.insert(table, nullColumnHack, values);
	 * 不管第三个参数是否包含数据,执行Insert()方法必然会添加一条记录 
	 * 如果第三个参数为空,会添加一条除主键之外其他字段值为Null的记录
	 * Insert()方法内部实际上通过构造insert语句完成数据的添加
	 * Insert()方法的第二个参数用于指定空值字段的名称
	 * 如果第三个参数values为Null或者元素个数为0
	 * Insert()方法必然要添加一条除了主键之外其它字段为Null值的记录
	 * 为了满足这条insert语句的语法,insert语句必须给定一个字段名 如:insert into person(name) values(NULL) 
	 * 倘若不给定字段名 ,insert语句就成了这样: insert into person() values()
	 * 显然这不满足标准SQL的语法。对于字段名,建议使用主键之外的字段
	 * 如果使用了INTEGER类型的主键字段,执行类似insert into person(personid) values(NULL)的insert语句后该主键字段值也不会为NULL
	 * 如果第三个参数values不为Null并且元素的个数大于0 ,可以把第二个参数设置为null
	 * 
	 * @param person
	 */
	public void save(Person person) {
		database = dataBaseOpenHelper.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put("name", person.getName());
		values.put("age", person.getAge());
		// 必须添加记录,除了主键之外,其他字段的值都为NULL
		database.insert("person", "name", values);
		// 第二个参数,构造合法的sql语句
		// insert into person(name) values(null);
	}

	public void update(Person person) {
		database = dataBaseOpenHelper.getWritableDatabase();
		ContentValues values = new ContentValues();
		values.put("name", person.getName());
		values.put("age", person.getAge());
		database.update("person", values, "personid=?", new String[] { String
				.valueOf(person.getPersonid()) });
	}

	public Person find(Integer id) {
		database = dataBaseOpenHelper.getReadableDatabase();
		Cursor cursor = database.query("person", new String[] { "personid",
				"name", "age" }, "personid=?", new String[] { String
				.valueOf(id) }, null, null, null);
		if (cursor.moveToNext()) {
			return new Person(cursor.getInt(0), cursor.getString(1), cursor
					.getShort(2));
		}
		return null;
	}

	public void delete(Integer... ids) {
		if (ids.length > 0) {
			String[] strIds = new String[ids.length];
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < ids.length; i++) {
				sb.append('?').append(',');
				strIds[i] = String.valueOf(ids[i]);
			}
			sb.deleteCharAt(sb.length() - 1);
			database = dataBaseOpenHelper.getWritableDatabase();
			database.delete("person", "personid in(" + sb + ")", strIds);
		}
	}

	/**
	 * 
	 * query(table, columns, selection, selectionArgs, groupBy, having, orderBy, limit)方法各参数的含义 
	 * table:表名。相当于select语句from关键字后面的部分。如果是多表联合查询,可以用逗号将两个表名分开
	 * columns:要查询出来的列名。相当于select语句select关键字后面的部分
	 * selection:查询条件子句,相当于select语句where关键字后面的部分,在条件子句允许使用占位符"?"
	 * selectionArgs:对应于selection语句中占位符的值,值在数组中的位置与占位符在语句中的位置必须一致,否则就会有异常
	 * groupBy:相当于select语句group by关键字后面的部分 
	 * having:相当于select语句having关键字后面的部分
	 * orderBy:相当于select语句order by关键字后面的部分,如:personid desc, age asc;
	 * limit:指定偏移量和获取的记录数,相当于select语句limit关键字后面的部分。
	 * 
	 */

	public List<Person> getScrollData(int startResult, int maxResult) {
		List<Person> persons = new ArrayList<Person>();
		database = dataBaseOpenHelper.getWritableDatabase();
		Cursor cursor = database.query("person", new String[] { "personid",
				"name", "age" }, null, null, null, null, "personid desc",
				startResult + "," + maxResult);
		while (cursor.moveToNext()) {
			persons.add(new Person(cursor.getInt(0), cursor.getString(1),
					cursor.getShort(2)));
		}
		return persons;
	}

	public long getCount() {
		database = dataBaseOpenHelper.getReadableDatabase();
		Cursor cursor = database.query("person", new String[] { "count(*)" },
				null, null, null, null, null);
		while (cursor.moveToNext()) {
			return cursor.getLong(0);
		}
		return 0;
	}
}

 

PersonServiceTest

package org.wp.db;

import java.util.List;
import org.wp.domain.Person;
import org.wp.service.OtherPersonService;
import org.wp.service.PersonService;
import android.test.AndroidTestCase;
import android.util.Log;

public class PersonServiceTest extends AndroidTestCase {
	private static final String TAG = "PersonServiceTest";

	public void testSave() throws Exception {
		// PersonService personService = new PersonService(this.getContext());
		OtherPersonService personService = new OtherPersonService(this
				.getContext());
		personService.save(new Person("某某某", (short) 23));
	}

	public void testFind() throws Exception {
		// PersonService personService = new PersonService(this.getContext());
		OtherPersonService personService = new OtherPersonService(this
				.getContext());
		Person person = personService.find(1);
		Log.i(TAG, person.toString());
	}

	public void testUpdate() throws Exception {
		// PersonService personService = new PersonService(this.getContext());
		OtherPersonService personService = new OtherPersonService(this
				.getContext());
		Person person = personService.find(1);
		person.setName("张三");
		person.setAge((short) 11);
		personService.update(person);
		person = personService.find(1);
		Log.i(TAG, person.toString());
	}

	public void testGetCount() throws Exception {
		// PersonService personService = new PersonService(this.getContext());
		OtherPersonService personService = new OtherPersonService(this
				.getContext());
		Log.i(TAG, String.valueOf(personService.getCount()));
	}

	public void testGetScrollData() throws Exception {
		// PersonService personService = new PersonService(this.getContext());
		OtherPersonService personService = new OtherPersonService(this
				.getContext());
		// for (int i = 0; i < 10; i++) {
		// personService.save(new Person("某某某" + i, (short) (i + 1)));
		// }
		List<Person> persons = personService.getScrollData(0, 30);
		for (Person person : persons) {
			Log.i(TAG, person.toString());
		}
	}

	public void testDelete() throws Exception {
		PersonService personService = new PersonService(this.getContext());
		personService.delete(1, 2, 3);
	}

}

 

Person

package org.wp.domain;

public class Person {

	private Integer personid;
	private String name;
	private Short age;

	public Person(Integer personid, String name, Short age) {
		this.personid = personid;
		this.name = name;
		this.age = age;
	}

	public Person(String name, Short age) {
		this.name = name;
		this.age = age;
	}

	public Integer getPersonid() {
		return personid;
	}

	public void setPersonid(Integer personid) {
		this.personid = personid;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Short getAge() {
		return age;
	}

	public void setAge(Short age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "personid=" + personid + ",name=" + name + ",age=" + age;
	}

}

 

main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
 	<Button
 		android:layout_width="wrap_content"
 		android:layout_height="wrap_content"
 		android:text="@string/button"
 		android:id="@+id/button"
 		/>  
</LinearLayout>

 

strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="hello">Hello World, DBActivity!</string>
    <string name="app_name">数据库应用</string>
    <string name="button">操作数据库</string>
</resources>

 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="org.wp.db" android:versionCode="1" android:versionName="1.0">
	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<uses-library android:name="android.test.runner" />
		<activity android:name=".DBActivity" 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>
	<uses-sdk android:minSdkVersion="7" />
	<instrumentation android:name="android.test.InstrumentationTestRunner"
		android:targetPackage="org.wp.db" android:label="Tests for My App" />
</manifest> 

 

 

 

分享到:
评论

相关推荐

    第一行代码 android学习笔记 完整版

    "Android学习笔记" Android学习笔记是Android开发者的必读书籍,书中涵盖了Android系统架构、Activity、Intent、资源管理等多方面的知识。本笔记对应的学习资源《第一行代码》是Android开发者的入门必读书籍,书中...

    Android学习笔记(十)——实现新闻列表

    Android学习笔记(一)——创建第一个Android项目 Android学习笔记(二)android studio基本控件及布局(实现图片查看器) Android学习笔记(三)android studio中CheckBox自定义样式(更换复选框左侧的勾选图像) ...

    Android学习笔记

    ### Android学习笔记 #### 1. Android概述 **1.1 Android的特性** - **应用框架**:Android提供了一个强大的应用框架,使得开发者能够轻松地重用基础组件和服务,简化了应用程序的开发流程。 - **Dalvik虚拟机**...

    Android开发学习笔记

    ### Android开发学习笔记 #### Button按钮的实现与交互 在Android开发中,`Button`控件是最常用的用户界面元素之一,用于触发特定的操作或事件。本文档将详细讲解如何创建并自定义一个简单的按钮,并设置点击事件...

    Android学习笔记.doc Android学习笔记.doc

    【Android学习笔记】 Android平台是谷歌推出的一个开放源代码的移动设备操作系统,它为开发者提供了一个全面的软件包,包括操作系统、中间件和关键应用程序。这个平台的主要目标是促进移动应用的创新和多样性,允许...

    android 学习笔记

    Android学习笔记(1)-永远不变的Hello World Google的Android SDK发布也有一段时间了,一直想研究一下却苦于找不到时间。利用这个周未,开始强迫自己再次进入学习状态,原因很简单:我看好开放的gPhone。 SDK的下载...

    Android开发学习笔记(整理)

    Android开发学习笔记(整理),整理论坛android学习笔记,较完整的讲解了android的内容。包括:view、activity、service、intent、广播机制、http连接、数据sqllite存储、后台线程、各种layout、偏好、本地文件操作、...

    Android 学习笔记

    这篇学习笔记主要涵盖了关于布局的一些基本概念,特别是`fill_parent`和`wrap_content`这两种尺寸指定方式,以及如何通过XML布局文件来精确控制组件的位置。 首先,`fill_parent`和`wrap_content`是Android布局中的...

    java学习细节 android学习笔记

    根据给定的信息,我们可以从Java和Android学习笔记中提取出一系列重要的知识点,下面将逐一进行详细解释。 ### Java基础知识 #### 1. 命令行基础操作 - **`javacmd`**: 这个命令是Java命令行工具的一部分,用于...

    Android学习笔记整理.pdf

    Android学习笔记整理.pdf

    android 学习笔记(全全整理)

    Android学习笔记全全整理,是针对想要深入理解并掌握Android开发技术的学习者们的一份宝贵资源。这份笔记涵盖了从基础到高级的多个方面,旨在帮助读者建立起完整的Android知识体系。以下将详细介绍其中可能包含的...

    ArcGIS for android学习笔记

    本篇学习笔记主要涵盖了ArcGIS for Android的基础配置和核心组件MapVie的使用。 首先,配置ArcGIS for Android项目需要在`Project`级别的`build.gradle`文件中添加Esri的仓库,确保能获取到所需的库。接着,在`...

    Android基础学习笔记

    Android基础学习笔记主要涵盖了一系列关于Android开发的基本概念和关键组件,以下是这些知识点的详细解析: 1. **Activity**: 是Android应用程序的基本单元,它代表用户在屏幕上看到的一个界面。每个Activity都必须...

    android学习笔记(html完整版)目录

    目录,整理论坛android学习笔记,较完整的讲解了android的内容。包括:view、activity、service、intent、广播机制、http连接、数据sqllite存储、后台线程、各种layout、偏好、本地文件操作、apdapter等几乎全部内容...

    android学习笔记.zip

    《Android学习笔记》 在移动应用开发领域,Android操作系统占据着重要的地位,为开发者提供了丰富的API和工具,使得创建各种应用程序变得可能。本压缩包文件包含了一位学习者从第一天到第五天,以及一个特定项目...

    黑马程序员Android学习笔记

    《黑马程序员Android学习笔记》是一份专为初学者设计的详尽教程,旨在帮助那些希望踏入安卓开发领域的人员快速掌握核心知识。这份笔记涵盖了从基础到进阶的多个主题,帮助学习者系统地理解Android应用开发的过程。 ...

Global site tag (gtag.js) - Google Analytics