DatabaseTest
对数据的可持续存储,除了将数据存到文件中或者利用SharedPreferences存储键值对。也可以用数据库来处理,并且Android系统自身就内置了一个数据库–SQLite,SQLite是一款轻量级的关系型数据库,运算速度块,占用资源少。可以轻松的应对大量且复杂的关系型数据。
ProviderTest
对DatabaseTest提供的内容提供器进行 插入 更新 删除 查询功能
对于这些功能的测试都是通过log打印出来的,对数据库进行插入,更新,删除,查询已经监听数据库的数据内容都是可用的
/**
*可以借助SQLiteOpenHelper类对数据库进行创建和升级
*继承SQLiteOpenHelper需要重写onCreate()和onuPgrade()
*构造函数接收四个参数
*第一个参数是context
*第二个是数据库名
*第三个参数允许在查询数据的时候返回一个自定义的Cursor,一般传入null
*第四个参数表示当前数据库的版本号,可用于对数据库进行升级操作
*/
public class MyDatabaseHelper extends SQLiteOpenHelper {
private Context mContext;
public MyDatabaseHelper(Context context, String name,
SQLiteDatabase.CursorFactory factory, int version) {
super(context, name, factory, version);
mContext = context;
}
@Override
public void onCreate(SQLiteDatabase db) {}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {}
}
/**
*创建数据表
*integer 整型; real 浮点型; text 文本类型; blob 二进制类型
*primary key 设为主键
*autoincreament 自增长
*/
public static final String CREATE_BOOK = "create table Book ("
+ "id integer primary key autoincrement, "
+ "author text, "
+ "price real, "
+ "pages integer, "
+ "name text)";
//然后在onCreate函数里加上
db.execSQL(CREATE_BOOK);
关于数据库的CRUD的操作:
private MyDatabaseHelper databaseHelper;
//创建数据库
databaseHelper = new MyDatabaseHelper(this,"BookStore.db", null, 1);
//获得数据库实例句柄
SQLiteDatabase database = databaseHelper.getWritableDatabase();
//insert data
ContentValues values = new ContentValues();
values.put("name", "The Da Vinci Code");
values.put("author", "Dan Brown");
values.put("pages", "454");
values.put("price", "16.96");
database.insert("Book", null, values);
//update data
ContentValues values = new ContentValues();
values.put("price", 10.99);
database.update("Book", values, "name = ?",new String[]{"The Da Vinci Code"});
//delete data
database.delete("Book", "pages > ?",new String[]{"500"});
//query data
Cursor cursor = database.query("Book", null, null, null, null, null, null);
if(cursor.moveToFirst()) {
do {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d("TAG", name + " " + author +" " + pages + " " + price);
}while (cursor.moveToNext());
}
cursor.close();
当已经用上数据库存放数据的时候,不得不考虑这样一个情况,能不能让几个应用都利用同一个数据库,即把一个数据库当成一个仓库,几个应用就好比供应商,大家都从这个仓库进行拿货存货(读写值)。
这个时候,就可以利用ContentProvider,Android四大组件之一,利用这个类可以实现将一个数据库共享出去,让其他的应用可以对这个数据库进行读写以及监听。
/**
*新建一个DatabaseProvider类,继承ContentProvider
*重写onCreate(), delete(), getType(), insert(), query(), update();
*/
public class DatabaseProvider extends ContentProvider {
//初始化内容提供者的时候会调用。当ContentResolver尝试访问程序中的数据时,会被初始化
@Override
public boolean onCreate() {
return false;
}
/**
*从内容提供器中查询数据
*Uri 确定查询哪张表
*projection 确定查询哪些列
*selection和selectionArgs 约束查询哪些行
*sortOrder 对结果进行排序
*查询的结果存放在Cursor对象中返回
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
return null;
}
/**
*向内容提供器中插入数据
*Uri 确定查询哪张表
*values 存放需要插入的数据
*返回一个用于表示这条新纪录的Uri
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
return 0;
}
/**
*更新内容提供器中已有的数据
*Uri 确定查询哪张表
*values 存放需要插入的数据
*selection和selectionArgs 约束更新哪些行
*受影响的行数将作为返回值返回
*/
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
/**
*从内容提供器中删除 数据
*Uri 确定查询哪张表
*selection和selectionArgs 约束删除哪些行
*被删除的行数将作为返回值返回
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
/**
*根据传入的内容URI来返回相应的MIME类型
*Uri 确定查询哪张表
*/
@Override
public String getType(Uri uri) {
return null;
}
}
package com.example.providertest;
import androidx.appcompat.app.AppCompatActivity;
import android.content.ContentValues;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
private String newId;
//监听回调函数
private ContentObserver changeObserver =
new ContentObserver(new Handler()) {
@Override
public void onChange(boolean selfChange) {
Log.d(TAG, "onChange: ");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册监听,监听book数据表
//需要在DatabaseProvider中重写的crud函数中,添加getContext().getContentResolver().notifyChange(uri,null);
this.getContentResolver().registerContentObserver(
Uri.parse("content://com.example.databasetest.provider/book"),
true, changeObserver);
//插入,更新,删除,查询
//insert data
Button addData = (Button) findViewById(R.id.add_data);
addData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
ContentValues values = new ContentValues();
values.put("name", "A Clash of King");
values.put("author", "George Martin");
values.put("pages", 1040);
values.put("price", 22.85);
Uri newUri = getContentResolver().insert(uri, values);
newId = newUri.getPathSegments().get(1);
Log.d(TAG, "onClick: add"+newId);
}
});
//update data
Button updateData = (Button) findViewById(R.id.update_data);
updateData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
ContentValues values = new ContentValues();
values.put("name", "A Storm of Swords");
values.put("pages", 1216);
values.put("price", 24.05);
getContentResolver().update(uri, values, null, null);
Log.d(TAG, "onClick: update");
}
});
//delete data
Button deleteData = (Button) findViewById(R.id.delete_data);
deleteData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Uri uri = Uri.parse("content://com.example.databasetest.provider/book/" + newId);
getContentResolver().delete(uri, null, null);
Log.d(TAG, "onClick: delete");
}
});
//query data
Button queryData = (Button) findViewById(R.id.query_data);
queryData.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d(TAG, "onClick: query");
Uri uri = Uri.parse("content://com.example.databasetest.provider/book");
Cursor cursor = getContentResolver().query(uri, null, null,
null, null);
if(cursor != null) {
while(cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex("name"));
String author = cursor.getString(cursor.getColumnIndex("author"));
int pages = cursor.getInt(cursor.getColumnIndex("pages"));
double price = cursor.getDouble(cursor.getColumnIndex("price"));
Log.d("TAG", name+author+pages+price);
}
cursor.close();
}
}
});
}
}
Uri格式
标准格式:content://com.example.app.provider/table1
可以在标准格式后面加上id:content://com.example.app.provider/table1/1
标准格式表示访问表中所有的数据,加id的表示访问该表中拥有相应id的数据
利用通配符可以有
*:表示匹配任意长度的任意字符
#:表示匹配任意长度的数字
content://com.example.app.provider/* ===> 匹配任意表的内容URI格式
content://com.example.app.provider/table1/# ===> 匹配table1表中任意一行数据的内容URI格式
利用UriMatcher类可以帮助实现匹配内容Uri的功能。
通过addURI方法将数据表以及数据表中的内容Uri存进去
uriMatcher.addURI(AUTHORITY, "book", BOOK_DIR);
通过UriMatcher.match(uri)判断调用方期望访问的数据内容
Uri格式 --> MIME类型
content://com.example.app.provider/table1 --> vnd.android.cursor.dir/vnd.com.example.app.provider.table1
content://com.example.app.provider/table1/1 --> vnd.android.cursor.item/vnd.com.example.app.provider.table1
DatabaseTest github
ProviderTest github