Android中数据库的学习中,我目前学了两种方式
1. 用基础类SQLiteOpenHelper操作数据库,其增删改查,则通过sql语句。
2. 用ContentProvider 和ContentResovler进行数据库的操作
ContentProvider其实是把SQLiteOpenHelper中操作数据库的方式进行封装。
ContentProvider和ContentResovler 的实现原理,只是个人观念,帮助理解。
一般数据库的操作步骤:
当然了如果不用ContentProvider,也可以编写增删改查的操作)。
2.编写ContentProvider的子类,封装步骤1的数据库操作,统一访问的入口为Uri对象。
3.注册编写ContentProvider的子类。
4.通过ContentResolver对象实现增删改查的操作。
事例代码:
DataBaseConstant.java(主要存放数据库的字段以及访问数据的Uri)
package database;
import android.net.Uri;
import android.provider.BaseColumns;
public class DataBaseConstant {
public static final class Student implements BaseColumns {
public static final String AUTHORITY = "database.provider.student";
public static final String TABLE_NAME = "student";
public static final Uri CONTENT_URI = Uri
.parse("content://" + AUTHORITY + "/" + TABLE_NAME);
public static final String NAME = "name";
public static final String CLASS = "class";
}
}
DataBaseString.java(存放SQLite的语句)
package database;
public class DataBaseString {
public static final String CREATE = "CREATE TABLE IF NOT EXISTS ";
// 设置主键
public static final String _ID_PRIMARY = " _id INTEGER PRIMARY KEY AUTOINCREMENT,";
// 创建student表
public static final String CREATE_STUDENT = CREATE + DataBaseConstant.Student.TABLE_NAME + "("
+ _ID_PRIMARY
+ DataBaseConstant.Student.NAME + " TEXT,"
+ DataBaseConstant.Student.CLASS + " TEXT);";
// 添加
public static final String ADD_STUDENT = "INSERT INTO " + DataBaseConstant.Student.TABLE_NAME
+ "(" + DataBaseConstant.Student.NAME + "," + DataBaseConstant.Student.CLASS
+ ") VALUES";
}
DataBaseHelper.java(继承SQLiteOpenHelper,直接操作数据库)
package database;
import android.content.ContentValues;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DataBaseHelper extends SQLiteOpenHelper {
public DataBaseHelper(Context context) {
// 创建数据库
super(context, "data.db", null, 3);
}
/**
* 该方法只有在数据库不存在时才调用
*/
@Override
public void onCreate(SQLiteDatabase db) {
// 执行SQL语句,创建表
db.execSQL(DataBaseString.CREATE_STUDENT);
}
/**
* 因为SQLiteOpenHelper可是SQLite的辅助类,可以操作数据库 所以我们可以获得数据库,执行SQL语句
*
* @param initialValues
*/
public void add(ContentValues initialValues) {
SQLiteDatabase db = getWritableDatabase();
String s = DataBaseString.ADD_STUDENT;
ContentValues values = (initialValues != null) ? new ContentValues(
initialValues) : new ContentValues();
s = s + "('" + values.getAsString(DataBaseConstant.Student.NAME) + "', '"
+ values.getAsString(DataBaseConstant.Student.CLASS) + "');";
db.execSQL(s);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
DataBaseProvider.java(封装数据库的操作,也就是封装上一个类的实例,将数据暴露出来,也就是数据的增删该查通过Uri进行访问)
在DataBaseProvider中的getType方法到底有没有用呢?答案在下面的链接中
package database;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;
/**
* 将数据库的包装类的增删改查的方法,进行封装
* @author Administrator
*
*/
public class DataBaseProvider extends ContentProvider {
//UriMatcher 功能,存储Uri ,并进行匹配。
private static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
static {
//集合路径匹配,匹配返回码是1
URI_MATCHER.addURI(DataBaseConstant.Student.AUTHORITY, "student", 1);
//个体路径匹配,匹配返回码是2
URI_MATCHER.addURI(DataBaseConstant.Student.AUTHORITY, "student/#", 2);
}
private DataBaseHelper mDataBaseHelper;
@Override
public boolean onCreate() {
mDataBaseHelper = new DataBaseHelper(getContext());
return true;
}
@Override
public String getType(Uri url) {
int match = URI_MATCHER.match(url);
switch (match) {
case 1:
return "vnd.android.cursor.dir/" + "student";
case 2:
return "vnd.android.cursor.item/" + "student";
default:
throw new IllegalArgumentException("Unknown URL");
}
}
@Override
public Uri insert(Uri url, ContentValues initialValues) {
if (URI_MATCHER.match(url) != 1) {
throw new IllegalArgumentException("Cannot insert into URL: " + url);
}
ContentValues values = (initialValues != null) ? new ContentValues(
initialValues) : new ContentValues();
SQLiteDatabase db = mDataBaseHelper.getWritableDatabase();
long rowId = db.insert(DataBaseConstant.Student.TABLE_NAME,
DataBaseConstant.Student.NAME, values);
if (rowId < 0) {
throw new SQLException("Failed to insert row into " + url);
}
//Uri的工具类
Uri noteUri = ContentUris
.withAppendedId(DataBaseConstant.Student.CONTENT_URI, rowId);
getContext().getContentResolver().notifyChange(noteUri, null);
return noteUri;
}
@Override
public int delete(Uri url, String where, String[] whereArgs) {
SQLiteDatabase db = mDataBaseHelper.getWritableDatabase();
int count;
switch (URI_MATCHER.match(url)) {
case 1:
count = db.delete(DataBaseConstant.Student.TABLE_NAME, where, whereArgs);
break;
case 2:
String segment = url.getPathSegments().get(1);
if (TextUtils.isEmpty(where)) {
where = "_id=" + segment;
} else {
where = "_id=" + segment + " AND (" + where + ")";
}
count = db.delete(DataBaseConstant.Student.TABLE_NAME, where, whereArgs);
break;
default:
throw new IllegalArgumentException("Cannot delete from URL: " + url);
}
getContext().getContentResolver().notifyChange(url, null);
return count;
}
@Override
public int update(Uri url, ContentValues values, String where,
String[] whereArgs) {
int count;
long rowId = 0;
int match = URI_MATCHER.match(url);
SQLiteDatabase db = mDataBaseHelper.getWritableDatabase();
switch (match) {
case 1:
count = db.update(DataBaseConstant.Student.TABLE_NAME, values, where,
whereArgs);
break;
case 2:
String segment = url.getPathSegments().get(1);
rowId = Long.parseLong(segment);
count = db.update(DataBaseConstant.Student.TABLE_NAME, values, "_id="
+ rowId, null);
break;
default:
throw new UnsupportedOperationException("Cannot update URL: " + url);
}
getContext().getContentResolver().notifyChange(url, null);
return count;
}
@Override
public Cursor query(Uri url, String[] projectionIn, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder qBuilder = new SQLiteQueryBuilder();
int match = URI_MATCHER.match(url);
switch (match) {
case 1:
qBuilder.setTables(DataBaseConstant.Student.TABLE_NAME);
break;
case 2:
qBuilder.setTables(DataBaseConstant.Student.TABLE_NAME);
qBuilder.appendWhere("_id="
+ url.getPathSegments().get(1));
break;
default:
throw new IllegalArgumentException("Unknown URL " + url);
}
// String orderBy;
// if (TextUtils.isEmpty(sortOrder)) {
// orderBy = DbConstant.LoginInfoConstant.DEFAULT_SORT_ORDER;
// } else {
// orderBy = sortOrder;
// }
SQLiteDatabase db = mDataBaseHelper.getReadableDatabase();
Cursor ret = qBuilder.query(db, projectionIn, selection, selectionArgs,
null, null, null);
if (ret == null) {
} else {
ret.setNotificationUri(getContext().getContentResolver(), url);
}
return ret;
}
}
MainActivity.java(注意:该类中注释的代码,其实是直接操作数据库的代码,并不通过ContentResolver进行访问)
package database;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.text.TextUtils;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import com.example.testandroidui.R;
public class MainActivity extends Activity implements OnClickListener {
private EditText name, cla;
public TextView data;
private Button delete, insert, query;
public ContentResolver cr;
//DataBaseHelper mDataBaseHelper;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.database_main);
//mDataBaseHelper = new DataBaseHelper(this);// 获得数据库辅助对象
cr = getContentResolver();
init();
}
public void init() {
name = (EditText) findViewById(R.id.name);
cla = (EditText) findViewById(R.id.cla);
data = (TextView) findViewById(R.id.data);
delete = (Button) findViewById(R.id.delete);
insert = (Button) findViewById(R.id.insert);
query = (Button) findViewById(R.id.query);
delete.setOnClickListener(this);
insert.setOnClickListener(this);
query.setOnClickListener(this);
// cr注册监听 ,监听数据库变化
cr.registerContentObserver(DataBaseConstant.Student.CONTENT_URI,
true, new DataObserver(new Handler()));
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.delete:
if (!TextUtils.isEmpty(name.getText().toString())
&& !TextUtils.isEmpty(cla.getText().toString())) {
ContentValues values = new ContentValues();
values.put(DataBaseConstant.Student.NAME,
name.getText().toString());
values.put(DataBaseConstant.Student.CLASS,
cla.getText().toString());
cr.delete(DataBaseConstant.Student.CONTENT_URI,
DataBaseConstant.Student.NAME + " = ? AND "
+ DataBaseConstant.Student.CLASS
+ " = ? ",
new String[] {
name.getText().toString(), cla.getText().toString()
});
}
break;
case R.id.insert:
if (!TextUtils.isEmpty(name.getText().toString())
&& !TextUtils.isEmpty(cla.getText().toString())) {
ContentValues values = new ContentValues();
values.put(DataBaseConstant.Student.NAME,
name.getText().toString());
values.put(DataBaseConstant.Student.CLASS,
cla.getText().toString());
cr.insert(DataBaseConstant.Student.CONTENT_URI, values);
// mDataBaseHelper.add(values);//直接通过数据库辅助对象添加数据
}
break;
case R.id.query:
new QueryTextTask().execute();
break;
default:
break;
}
}
/**
* @author Administrator 数据库变化监听
*/
public class DataObserver extends ContentObserver {
public DataObserver(Handler handler) {
super(handler);
}
public void onChange(boolean selfChange) {
// 执行的操作
new QueryTextTask().execute();
}
}
class QueryTextTask extends AsyncTask<Void, Integer, String> {
QueryTextTask() {
}
/**
* 运行在UI线程中,在调用doInBackground()之前执行
*/
@Override
protected void onPreExecute() {
}
/**
* 后台运行的方法,可以运行非UI线程,可以执行耗时的方法
*/
@Override
protected String doInBackground(Void... params) {
Cursor c = cr.query(DataBaseConstant.Student.CONTENT_URI,
new String[] {
DataBaseConstant.Student.NAME, DataBaseConstant.Student.CLASS
}, null, null, null);
String num = "";
while (c.moveToNext()) {
String nameString = c.getString(c.getColumnIndex(DataBaseConstant.Student.NAME));
String classString = c.getString(c.getColumnIndex(DataBaseConstant.Student.CLASS));
num = num + "name:" + nameString + " , class:" + classString + ";";
}
return num;
}
/**
* 运行在ui线程中,在doInBackground()执行完毕后执行
*/
@Override
protected void onPostExecute(String s) {
data.setText(s);
}
}
}
database_main.xml主界面布局文件
<?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="vertical" >
<EditText
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入姓名" />
<EditText
android:id="@+id/cla"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="请输入班级" />
<Button
android:id="@+id/delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="delete" />
<Button
android:id="@+id/query"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="query" />
<Button
android:id="@+id/insert"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="insert" />
<TextView
android:id="@+id/data"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="0.81"
android:hint="数据库" />
</LinearLayout>
ContentProvider在AndroidManifest注册,并将访问路径写入authorities属性中
<provider
android:name="database.DataBaseProvider"
android:authorities="database.provider.student" >
</provider>