SQLite介绍
SQLite 一个非常流行的嵌入式数据库,它支持 SQL 语言,并且只利用很少的内存就有很好的性能。此外它还是开源的,任何人都可以使用它。许多开源项目((Mozilla, PHP, Python)都使用了 SQLite。
SQLite 由以下几个组件组成:SQL 编译器、内核、后端以及附件。SQLite 通过利用虚拟机和虚拟数据库引擎(VDBE),使调试、修改和扩展 SQLite 的内核变得更加方便。
图 1. SQLite内部结构
SQLite 基本上符合 SQL-92 标准,和其他的主要 SQL 数据库没什么区别。它的优点就是高效,Android 运行时环境包含了完整的 SQLite。
SQLite 和其他数据库最大的不同就是对数据类型的支持,创建一个表时,可以在 CREATE TABLE 语句中指定某列的数据类型,但是你可以把任何数据类型放入任何列中。当某个值插入数据库时,SQLite 将检查它的类型。如果该类型与关联的列不匹配,则 SQLite 会尝试将该值转换成该列的类型。如果不能转换,则该值将作为其本身具有的类型存储。比如可以把一个字符串(String)放入 INTEGER 列。SQLite称这为“弱类型”(manifest typing.)。
此外,SQLite 不支持一些标准的 SQL 功能,特别是外键约束(FOREIGN KEY constrains),嵌套 transcaction 和 RIGHT OUTER JOIN 和 FULL OUTER JOIN, 还有一些 ALTER TABLE 功能。
除了上述功能外,SQLite 是一个完整的 SQL 系统,拥有完整的触发器,交易等等。
Android集成了 SQLite 数据库
Android 在运行时(run-time)集成了 SQLite,所以每个 Android 应用程序都可以使用 SQLite 数据库。对于熟悉 SQL 的开发人员来时,在 Android 开发中使用 SQLite 相当简单。但是,由于 JDBC 会消耗太多的系统资源,所以 JDBC 对于手机这种内存受限设备来说并不合适。因此,Android 提供了一些新的 API 来使用 SQLite 数据库,Android开发中,程序员需要学使用这些 API。
数据库存储在 data/< 项目文件夹 >/databases/ 下。
Android开发中使用 SQLite 数据库
Activites 可以通过 Content Provider 或者 Service 访问一个数据库。下面会详细讲解如果创建数据库,添加数据和查询数据库。
Android 不自动提供数据库。在 Android 应用程序中使用 SQLite,必须自己创建数据库,然后创建表、索引,填充数据。Android 提供了 SQLiteOpenHelper 帮助你创建一个数据库,你只要继承 SQLiteOpenHelper 类,就可以轻松的创建数据库。SQLiteOpenHelper类根据开发应用程序的需要,封装了创建和更新数据库使用的逻辑。SQLiteOpenHelper 的子类,至少需要实现三个方法:
1. 构造函数,调用父类 SQLiteOpenHelper 的构造函数。这个方法需要四个参数:上下文环境(例如,一个 Activity),数据库名字,一个可选的游标工厂(通常是 Null),一个代表你正在使用的数据库模型版本的整数。
2. onCreate()方法,它需要一个 SQLiteDatabase 对象作为参数,根据需要对这个对象填充表和初始化数据。
3. onUpgrage()方法,它需要三个参数,一个SQLiteDatabase 对象,一个旧的版本号和一个新的版本号,这样你就可以清楚如何把一个数据库从旧的模型转变到新的模型。
下面示例代码展示了如何继承 SQLiteOpenHelper 创建数据库:
1.编写DBOpenHelper类
<span style="font-size:12px;">package com.kelly.sqlite.service;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DBOpenHelper extends SQLiteOpenHelper {
private static String dbname = "zyj";
private static int version = 1;
public DBOpenHelper(Context context) {
// 第一个参数是应用的上下文
// 第二个参数是应用的数据库名字
// 第三个参数CursorFactory指定在执行查询时获得一个游标实例的工厂类,设置为null,代表使用系统默认的工厂类
// 第四个参数是数据库版本,必须是大于0的int(即非负数)
super(context, dbname, null, version);
}
@Override
public void onOpen(SQLiteDatabase db) {
// TODO Auto-generated method stub
super.onOpen(db);
}
// 在数据库第一次被创建时调用
public void onCreate(SQLiteDatabase db) {
String sql = "create table person( personid integer primary key,name varchar(20),phone varchar(12),amount integer)";
db.execSQL(sql);
}
// onUpgrade()方法在数据库版本每次发生变化时都会把用户手机上的数据库表删除,然后再重新创建。
// 一般在实际项目中是不能这样做的,正确的做法是在更新数据库表结构时,还要考虑用户存放于数据库中的数据不会丢失,从版本几更新到版本几。
public void onUpgrade(SQLiteDatabase arg0, int arg1, int arg2) {
String sql_delete = "drop table if exists person ";
arg0.execSQL(sql_delete);
this.onCreate(arg0);
}
}
</span>
2.Person实体
<span style="font-size:12px;">package com.kelly.sqlite.domain;
public class Person {
private Integer id;
private String name;
private String phone;
private Integer amount;
public Person() {
}
public Person(String name, String phone, Integer amount) {
super();
this.name = name;
this.phone = phone;
this.amount = amount;
}
public Person(Integer id, String name, String phone, Integer amount) {
this.id = id;
this.name = name;
this.phone = phone;
this.amount = amount;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Integer getAmount() {
return amount;
}
public void setAmount(Integer amount) {
this.amount = amount;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", phone=" + phone
+ ", amount=" + amount + "]";
}
}
</span>
3.编写PersonService类
PersonService类主要实现对业务逻辑和数据库的操作。
<span style="font-size:12px;">package com.kelly.sqlite.service;
import java.util.ArrayList;
import java.util.List;
import android.R.integer;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import com.kelly.sqlite.domain.Person;
public class PersonService {
private DBOpenHelper dbOpenHelper;
public PersonService(Context context) {
this.dbOpenHelper = new DBOpenHelper(context);
}
/**
* 添加记录
*
* @param p
*/
public void add(Person p) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
String sql = "insert into person (name,phone,amount) values (?,?,?)";
Object[] bindArgs = new Object[] { p.getName(), p.getPhone(),
p.getAmount() };
db.execSQL(sql, bindArgs);
db.close();
}
/**
* 删除记录
*
* @param id
*/
public void delete(Integer id) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
String sql = "delete from person where personid = ?";
db.execSQL(sql, new Object[] { id });
db.close();
}
/**
* 更新记录
*
* @param p
*/
public void update(Person p) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
String sql = "update person set name = ? , phone = ? ,amount = ? where personid = ?";
Object[] bindArgs = new Object[] { p.getName(), p.getPhone(),
p.getAmount(), p.getId() };
db.execSQL(sql, bindArgs);
db.close();
}
/**
* 查询记录
*
* @param id
* @return
*/
public Person find(Integer id) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
String sql = "select * from person where personid = ?";
Cursor cursor = db.rawQuery(sql, new String[] { id.toString() });
if (cursor.moveToFirst()) {
int pid = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Integer amount = cursor.getInt(cursor.getColumnIndex("amount"));
return new Person(pid, name, phone, amount);
}
cursor.close();
db.close();
return null;
}
/**
* 分页获取记录
*
* @param offset跳过的条数
* @param maxResult要获取的条数
* @return
*/
public List<Person> getScrollData(int offset, int maxResult) {
List<Person> personlist = new ArrayList<Person>();
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
String sql = "select * from person order by personid asc limit ?,?";
String[] selectionArgs = new String[] { String.valueOf(offset),
String.valueOf(maxResult) };
Cursor cursor = db.rawQuery(sql, selectionArgs);
while (cursor.moveToNext()) {
int pid = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Integer amount = cursor.getInt(cursor.getColumnIndex("amount"));
personlist.add(new Person(pid, name, phone, amount));
}
cursor.close();
db.close();
return personlist;
}
/**
* 分页获取记录,提供给SimpleCursorAdapter使用。
*
* @param offset跳过的条数
* @param maxResult要获取的条数
* @return
*/
public Cursor getCursorScrollData(int offset, int maxResult) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
String sql = "select personid as _id,name,phone,amount from person order by personid asc limit ?,?";
String[] selectionArgs = new String[] { String.valueOf(offset),
String.valueOf(maxResult) };
Cursor cursor = db.rawQuery(sql, selectionArgs);
return cursor;
}
/**
* 获取记录总数
*
* @return
*/
public long getCount() {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
String sql = "select count(*) from person ";
Cursor cursor = db.rawQuery(sql, null);
cursor.moveToFirst();
long count = cursor.getLong(0);
cursor.close();
db.close();
return count;
}
}
</span>
下面是使用 insert()、delete()、update()和query()方法实现的业务类
<span style="font-size:12px;">package com.kelly.sqlite.service;
import java.util.ArrayList;
import java.util.List;
import android.R.id;
import android.R.integer;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.UrlQuerySanitizer.ValueSanitizer;
import com.kelly.sqlite.domain.Person;
public class OtherPersonService {
private DBOpenHelper dbOpenHelper;
public OtherPersonService(Context context) {
this.dbOpenHelper = new DBOpenHelper(context);
}
/**
* 添加记录
*
* @param p
*/
public void add(Person p) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", p.getName());
values.put("phone", p.getPhone());
values.put("amount", p.getAmount());
db.insert("person", null, values);
db.close();
}
/**
* 删除记录
*
* @param id
*/
public void delete(Integer id) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
db.delete("person", "personid = ?", new String[] { id.toString() });
db.close();
}
/**
* 更新记录
*
* @param p
*/
public void update(Person p) {
SQLiteDatabase db = dbOpenHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put("name", p.getName());
values.put("phone", p.getPhone());
values.put("amount", p.getAmount());
db.update("person", values, "personid = ?", new String[] { p.getId()
.toString() });
db.close();
}
/**
* 查询记录
*
* @param id
* @return
*/
public Person find(Integer id) {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
Cursor cursor = db.query("person", null, "personid = ?",
new String[] { id.toString() }, null, null, null);
if (cursor.moveToFirst()) {
int pid = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Integer amount = cursor.getInt(cursor.getColumnIndex("amount"));
return new Person(pid, name, phone, amount);
}
cursor.close();
db.close();
return null;
}
/**
* 分页获取记录
*
* @param offset跳过的条数
* @param maxResult要获取的条数
* @return
*/
public List<Person> getScrollData(int offset, int maxResult) {
List<Person> personlist = new ArrayList<Person>();
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
Cursor cursor = db.query("person", null, null, null, null, null,
"personid asc", offset + "," + maxResult);
while (cursor.moveToNext()) {
int pid = cursor.getInt(cursor.getColumnIndex("personid"));
String name = cursor.getString(cursor.getColumnIndex("name"));
String phone = cursor.getString(cursor.getColumnIndex("phone"));
Integer amount = cursor.getInt(cursor.getColumnIndex("amount"));
personlist.add(new Person(pid, name, phone, amount));
}
cursor.close();
db.close();
return personlist;
}
/**
* 获取记录总数
*
* @return
*/
public long getCount() {
SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
Cursor cursor = db.query("person", new String[] { "count (*)" }, null,
null, null, null, null);
cursor.moveToFirst();
long count = cursor.getLong(0);
cursor.close();
db.close();
return count;
}
}
</span>
4.编写测试类
编写一个针对PersonService的测试类,测试PersonService类中的各个方法是否正确。
<span style="font-size:12px;">package com.kelly.sqlite.test;
import java.util.List;
import com.kelly.sqlite.domain.Person;
import com.kelly.sqlite.service.DBOpenHelper;
import com.kelly.sqlite.service.PersonService;
import android.R.integer;
import android.provider.MediaStore.Video;
import android.test.AndroidTestCase;
import android.util.Log;
public class PersonServiceTest extends AndroidTestCase {
private static final String TAG = "PersonServiceTest";
/**
* 创建数据库
*/
public void testCreateDB() {
DBOpenHelper dbOpenHelper = new DBOpenHelper(getContext());
dbOpenHelper.getWritableDatabase();
}
public void testAdd() {
PersonService service = new PersonService(getContext());
for (int i = 0; i < 10; i++) {
Person p = new Person("name" + i, "0000000000" + i, 100);
service.add(p);
}
}
public void testDelete() {
PersonService service = new PersonService(getContext());
service.delete(1);
}
public void testUpdate() {
PersonService service = new PersonService(getContext());
Person person = service.find(1);
person.setName("kellylll001");
service.update(person);
}
public void testFind() {
PersonService service = new PersonService(getContext());
Person person = service.find(1);
Log.i(TAG, person.toString());
}
public void testScrollData() {
PersonService service = new PersonService(getContext());
List<Person> lists = service.getScrollData(0, 10);
for (Person person : lists) {
Log.i(TAG, person.toString());
}
}
public void testCount() {
PersonService service = new PersonService(getContext());
long count = service.getCount();
Log.i(TAG, "======count=====" + String.valueOf(count));
}
}
</span>
启用测试功能,不要忘记在AndroidManifest.xml文件中加入测试环境。为application元素添加一个子元素:<uses-library android:name="android.test.runner"/>,为application元素添加一个兄弟元素:<instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.kelly.sqlite" android:label="Tests for My App" />。
SQLite数据库以单个文件存储,有一个查看SQLite数据库文件的工具——SQLite Developer,我们可以使用它来查看数据库。Android将创建的数据库存放在”/data/data/ com.jbridge.db/databases/person”,我们将它导出然后使用SQLite Developer打开。
5.分页显示数据
我们在PersonService类中,提供了一个获取分页数据的方法。我们将调用它获取的数据,使用ListView组件显示出来。
编辑activity_main.xml:
<span style="font-size:12px;"><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="姓名" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="电话" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="余额" />
</LinearLayout>
<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
</ListView>
</LinearLayout></span>
在layout下添加一个item.xml:
<span style="font-size:12px;"><?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal" >
<TextView
android:id="@+id/name"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="name"
android:textSize="22sp" />
<TextView
android:id="@+id/phone"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="phone"
android:textSize="22sp" />
<TextView
android:id="@+id/amount"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="amount"
android:textSize="22sp" />
</LinearLayout></span>
编辑 MainActivity 类:
<span style="font-size:12px;">package com.kelly.sqlite;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.widget.SimpleCursorAdapter;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.Toast;
import com.kelly.sqlite.domain.Person;
import com.kelly.sqlite.domain.PersonAdapter;
import com.kelly.sqlite.service.PersonService;
public class MainActivity extends Activity {
private ListView listView;
private PersonService service;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
service = new PersonService(this);
listView = (ListView) findViewById(R.id.listview);
listView.setOnItemClickListener(new ItemClickListenerImp());
// show_bySimpleAdapter();
// show_bySimpleCursorAdapter();
show_byMyselfAdapter();
}
private final class ItemClickListenerImp implements OnItemClickListener {
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
ListView lView = (ListView) parent;
Person person = (Person) lView.getItemAtPosition(position);
Toast.makeText(getApplicationContext(), person.getId().toString(),
1).show();
}
}
/**
* 自定义适配器
*/
private void show_byMyselfAdapter() {
List<Person> persons = service.getScrollData(0, 10);
PersonAdapter adapter = new PersonAdapter(this, persons, R.layout.item);
listView.setAdapter(adapter);
}
/**
*
*/
private void show_bySimpleCursorAdapter() {
Cursor c = service.getCursorScrollData(0, 15);
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this,
R.layout.item, c, new String[] { "name", "phone", "amount" },
new int[] { R.id.name, R.id.phone, R.id.amount });
listView.setAdapter(adapter);
}
private void show_bySimpleAdapter() {
List<Person> persons = service.getScrollData(0, 10);
List<HashMap<String, Object>> data = new ArrayList<HashMap<String, Object>>();
for (Person person : persons) {
HashMap<String, Object> item = new HashMap<String, Object>();
item.put("id", person.getId());
item.put("name", person.getName());
item.put("phone", person.getPhone());
item.put("amount", person.getAmount());
data.add(item);
}
SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.item,
new String[] { "name", "phone", "amount" }, new int[] {
R.id.name, R.id.phone, R.id.amount });
listView.setAdapter(adapter);
}
}
</span>
自定义适配器 PersonAdapter
<span style="font-size:12px;">package com.kelly.sqlite.domain;
import java.util.List;
import com.kelly.sqlite.R;
import com.kelly.sqlite.R.id;
import android.R.integer;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class PersonAdapter extends BaseAdapter {
private List<Person> persons;// 要绑定的数据
private int resouce;// 绑定条目界面
private LayoutInflater inflater;
public PersonAdapter() {
}
public PersonAdapter(Context context, List<Person> persons, int resouce) {
this.persons = persons;
this.resouce = resouce;
inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
@Override
public int getCount() {
return persons.size();
}
@Override
public Object getItem(int position) {
return persons.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView nameview = null;
TextView phoneview = null;
TextView amountview = null;
if (convertView == null)// 当前是第一页
{
convertView = inflater.inflate(resouce, null);// 生成条目界面对象
nameview = (TextView) convertView.findViewById(R.id.name);
phoneview = (TextView) convertView.findViewById(R.id.phone);
amountview = (TextView) convertView.findViewById(R.id.amount);
ViewCache cache = new ViewCache();
cache.nameview = nameview;
cache.phoneview = phoneview;
cache.amountview = amountview;
convertView.setTag(cache);
} else {
ViewCache cache = (ViewCache) convertView.getTag();
nameview = cache.nameview;
phoneview = cache.phoneview;
amountview = cache.amountview;
}
Person p = persons.get(position);
// 实现数据绑定
nameview.setText(p.getName());
phoneview.setText(p.getPhone());
amountview.setText(p.getAmount().toString());
return convertView;
}
private final class ViewCache {
public TextView nameview;
public TextView phoneview;
public TextView amountview;
}
}
</span>
代码下载地址:
<span style="font-size:12px;">http://download.csdn.net/detail/leokelly001/8115047</span>
参考文章:
http://www.ibm.com/developerworks/cn/opensource/os-cn-sqlite
http://justsee.iteye.com/blog/932591