ContentProvider
ContentProvider简介
- ContentProviders是用来管理对结构化数据进行访问的一组接口,这组接口对数据进行封装,并提供了用于定义数据安全的机制。ContentProviders是一个进程使用另一个进程数据的标准接口。
- Android系统本身也通过content providers来管理数据,如音频视频,图像个人信息等。我们可以在Android.provider包的参考文档中看到这些providers列表,在一定条件下,这些providers能够访问任何android应用程序。
- providers最主要的目的是为了让其他应用程序使用provider的客户端对象访问provider。所以,providers和provider客户端共同提供了一个一致的标准数据接口用来处理进程间通信和安全的数据访问。
创建一个ContentProvider
定义ContentProvider继承该类,实现相关方法
- 删除符合指定条件的记录
public int delete(Uri uri,String selection,String[] selectionArgs); - 插入一个新的记录
public Uri insert(Uri uri,ContentValues values); - 查询符合指定条件的记录
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) ; - 更新条例指定条件的记录
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs); - 创建数据储存后端,如数据库,文件,网络接口等,这里主要进行初始工作
public boolean onCreate(); - 基于给定URL,返回该URL表示的MIME类型
public String getType(Uri uri); - 在AndroidMainfest.xml中声明
< provider android:authorities=“com.example.contentproviderapplication.HelloContentProvider”
android:name=".HelloContentProvider"/>
在AndroidMainfest.xml使用< provider>对该ContentProvider进行配置,为了能让其他应用找到该ContentProvider,ContentProvider采用了authorities(主机名/域名)对它进行唯一标识。
UriMatcher和ContentUris工具栏
1、把我们需要匹配的Uri路径通过静态代码条件UriMatcher中
2、ContentUris有两个比较实用的方法
withAppendedld(uri,id)方法:用于为路径加上ID部分
parseld(uri)方法:用于从路径中获取ID部分
访问一个ContentProvider
当外部应用需要对ContentProvider中的数据进行添加,删除,修改和查询操作时,可以使用ContentResolver类来完成,要获取ContentResolver对象,可以使用Activity提供的getContentResolver()方法。
import android.provider.BaseColumns;
public final class PersonMetadata {
public static abstract class Person implements BaseColumns{
public static final String TABLE_NAME = "person";
public static final String NAME = "name";
public static final String AGE = "age";
}
}
package com.example.contentproviderapplication;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.ArrayList;
public class DatabaseAdapter {
private DataBaseHelper dbHelper;
public DatabaseAdapter(Context context){
dbHelper = new DataBaseHelper(context);
}
public void save(Person person){
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(PersonMetadata.Person.NAME,person.getName());
values.put(PersonMetadata.Person.AGE,person.getAge());
db.insert(PersonMetadata.Person.TABLE_NAME,null,values);
db.close();
}
public void delete(int id){
SQLiteDatabase db = dbHelper.getWritableDatabase();
db.delete(PersonMetadata.Person.TABLE_NAME,PersonMetadata.Person._ID+"=?",
new String[]{String.valueOf(id)});
db.close();
}
public void update(Person person){
SQLiteDatabase db = dbHelper.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(PersonMetadata.Person.NAME,person.getName());
values.put(PersonMetadata.Person.AGE,person.getAge());
String where = PersonMetadata.Person._ID+"=?";
String[] args = {String.valueOf(person.getId())};
db.update(PersonMetadata.Person.TABLE_NAME,values,where,args);
db.close();
}
public ArrayList<Person> findAll(){
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor c = db.query(PersonMetadata.Person.TABLE_NAME,null,null,null,null,null,null);
ArrayList<Person> list = new ArrayList<>();
Person person = null;
while (c.moveToNext()){
person = new Person();
person.setId(c.getInt(c.getColumnIndex(PersonMetadata.Person._ID)));
person.setName(c.getString(c.getColumnIndex(PersonMetadata.Person.NAME)));
person.setAge(c.getInt(c.getColumnIndex(PersonMetadata.Person.AGE)));
list.add(person);
}
c.close();
db.close();
return list;
}
public Person findById(int id){
SQLiteDatabase db = dbHelper.getWritableDatabase();
Cursor c = db.query(PersonMetadata.Person.TABLE_NAME,null,PersonMetadata.Person._ID+"=?",new String[]{String.valueOf(id)},null,null,null);
Person person = null;
if (c.moveToNext()){
person = new Person();
person.setId(c.getInt(c.getColumnIndex(PersonMetadata.Person._ID)));
person.setName(c.getString(c.getColumnIndex(PersonMetadata.Person.NAME)));
person.setAge(c.getInt(c.getColumnIndex(PersonMetadata.Person.AGE)));
}
c.close();
db.close();
return person;
}
public static class DataBaseHelper extends SQLiteOpenHelper{
private static final String DB_NAME = "cp.db";
private static final int VERSION = 1;
private static final String CREATE_TABLE = "CREATE TABLE PERSON"+
"(_id INTEGER PRIMARY KEY AUTOINCREMENT,name TEXT,age INT)";
private static final String DROP_TABLE = "DROP TABLE IF EXISTS person";
public DataBaseHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(DROP_TABLE);
db.execSQL(CREATE_TABLE);
}
}
}
package com.example.contentproviderapplication;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
/**
* 自定义ContentProvider
*/
public class HelloContentProvider extends ContentProvider {
private static final String AUTHORITIES = "com.example.contentproviderapplication.HelloContentProvider";
//创建一个URI的匹配器
private static UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int SINGLE_CODE = 2;//返回单个记录单匹配码
private static final int MUTIPLE_CODE = 1;//返回多个记录单匹配码
//text/plain image/jpg
private static final String SINGLE_TYPE = "vnd.android.cursor.item/person";
private static final String MUTIPLE_TYPE = "vnd.android.cursor.dir/person";
static {
//content://com.example.contentproviderapplication.HelloContentProvider/person/
uriMatcher.addURI(AUTHORITIES,"person",MUTIPLE_CODE);
//content://com.example.contentproviderapplication.HelloContentProvider/person/1
uriMatcher.addURI(AUTHORITIES,"person/#",SINGLE_CODE);
}
private DatabaseAdapter.DataBaseHelper dbHelper;
@Override
public boolean onCreate() {
dbHelper = new DatabaseAdapter.DataBaseHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) {
switch (uriMatcher.match(uri)){
case SINGLE_CODE:
SQLiteDatabase db = dbHelper.getReadableDatabase();
long id = ContentUris.parseId(uri);
selection = PersonMetadata.Person._ID + "=?";
selectionArgs = new String[]{String.valueOf(id)};
return db.query(PersonMetadata.Person.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);
case MUTIPLE_CODE:
db = dbHelper.getReadableDatabase();
return db.query(PersonMetadata.Person.TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);
}
return null;
}
@Override
public String getType(Uri uri) {
switch (uriMatcher.match(uri)){
case SINGLE_CODE:
return SINGLE_TYPE;
case MUTIPLE_CODE:
return MUTIPLE_TYPE;
}
return null;
}
//content://com.example.contentproviderapplication.HelloContentProvider/person/4
@Override
public Uri insert(Uri uri,ContentValues values) {
switch (uriMatcher.match(uri)){
case MUTIPLE_CODE:
SQLiteDatabase db = dbHelper.getWritableDatabase();
long id = db.insert(PersonMetadata.Person.TABLE_NAME,null,values);
uri = ContentUris.withAppendedId(uri,id);
db.close();
break;
}
return uri;
}
@Override
public int delete(Uri uri,String selection,String[] selectionArgs) {
switch (uriMatcher.match(uri)){
//content://com.example.contentproviderapplication.HelloContentProvider/person/1
case SINGLE_CODE:
SQLiteDatabase db = dbHelper.getWritableDatabase();
long id = ContentUris.parseId(uri);
selection = PersonMetadata.Person._ID + "=?";
selectionArgs = new String[]{String.valueOf(id)};
int row = db.delete(PersonMetadata.Person.TABLE_NAME,selection,selectionArgs);
db.close();
return row;
case MUTIPLE_CODE:
db = dbHelper.getWritableDatabase();
row = db.delete(PersonMetadata.Person.TABLE_NAME,selection,selectionArgs);
db.close();
return row;
}
return 0;
}
@Override
public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs) {
switch (uriMatcher.match(uri)){
//content://com.example.contentproviderapplication.HelloContentProvider/person/1
case SINGLE_CODE:
SQLiteDatabase db = dbHelper.getWritableDatabase();
long id = ContentUris.parseId(uri);
selection = PersonMetadata.Person._ID + "=?";
selectionArgs = new String[]{String.valueOf(id)};
int row = db.update(PersonMetadata.Person.TABLE_NAME,values,selection,selectionArgs);
db.close();
return row;
case MUTIPLE_CODE:
db = dbHelper.getWritableDatabase();
row = db.update(PersonMetadata.Person.TABLE_NAME,values,selection,selectionArgs);
db.close();
return row;
}
return 0;
}
}
package com.example.contentproviderapplication;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import java.net.URI;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void addClick(View view){
ContentResolver cr = this.getContentResolver();
//content://com.example.contentproviderapplication.HelloContentProvider/person
//content://com.example.contentproviderapplication.HelloContentProvider/person/1
//调用cp的添加方法
Uri uri = Uri.parse("content://com.example.contentproviderapplication.HelloContentProvider/person");
ContentValues values = new ContentValues();
values.put(PersonMetadata.Person.NAME,"yi");
values.put(PersonMetadata.Person.AGE,18);
cr.insert(uri,values);
}
public void deleteClick(View view){
ContentResolver cr = this.getContentResolver();
Uri uri = Uri.parse("content://com.example.contentproviderapplication.HelloContentProvider/person/1");
cr.delete(uri,null,null);
}
public void updateClick(View view){
ContentResolver cr = this.getContentResolver();
Uri uri = Uri.parse("content://com.example.contentproviderapplication.HelloContentProvider/person/1");
ContentValues values = new ContentValues();
values.put(PersonMetadata.Person.NAME,"yi");
values.put(PersonMetadata.Person.AGE,20);
cr.update(uri,values,null,null);
}
public void queryClick(View view){
ContentResolver cr = this.getContentResolver();
Uri uri = Uri.parse("content://com.example.contentproviderapplication.HelloContentProvider/person");
Cursor c = cr.query(uri,null,null,null,null);
while (c.moveToNext()){
System.out.println(c.getInt(c.getColumnIndex(PersonMetadata.Person._ID)));
System.out.println(c.getString(c.getColumnIndex(PersonMetadata.Person.NAME)));
System.out.println(c.getInt(c.getColumnIndex(PersonMetadata.Person.AGE)));
}
c.close();
}
}
Loaders
Loaders API概述
loaders提供了在activity和fragment中异步载入数据以及监视数据源变化的能力。
Loaders的特性如下:
1、支持Activity和Fragment
2、异步下载
3、当数据源改变时能及时通知客户端
4、发生configuration change时自动重新连接
public class MainActivity2 extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor> {
private DatabaseAdapter dbAdapter;
private SimpleCursorAdapter dataAdapter;
private CursorLoader loader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
dbAdapter = new DatabaseAdapter(this);
ListView lv = (ListView)findViewById(R.id.listView);
dataAdapter =
new SimpleCursorAdapter(this,R.layout.list_item,
dbAdapter.list(),new String[]{PersonMetadata.Person._ID,
PersonMetadata.Person.NAME,
PersonMetadata.Person.AGE},
new int[]{R.id.textView_id,
R.id.textView_name,
R.id.textView_age},
SimpleCursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(dataAdapter);
//初始化一个Loader(id,bundler参数,回调接口)
getSupportLoaderManager().initLoader(0,null,this);
}
public void addClick2(View view){
dbAdapter.save(new Person("san",19));
//重启加载器
// getSupportLoaderManager().restartLoader(0,null,this);
loader.commitContentChanged(); //api18可用
// loader.onContentChanged(); //内容发生了变化,通知加载器
}
@Override
public Loader onCreateLoader(int i,Bundle bundle) {
Uri uri = Uri.parse("content://com.example.contentproviderapplication.HelloContentProvider");
//创建一个图标加载器(上下文,CP的URI,要查询的列数组,查询条件,查询条件的值,排序条件)
loader = new CursorLoader(this,uri,null,null,null,null);
return loader;
}
@Override
public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {
dataAdapter.swapCursor(cursor);
}
@Override
public void onLoaderReset(Loader<Cursor> loader) {
dataAdapter.swapCursor(null);
}
}
AsyncTaskLoaders
package com.example.contentproviderapplication;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ListView;
import android.widget.TextView;
import java.util.ArrayList;
public class MainActivity3 extends AppCompatActivity implements LoaderManager.LoaderCallbacks<ArrayList<Person>> {
private MyAdapter myAdapter;
private DatabaseAdapter dbAdapter;
private DataAsyncTaskLoader loader;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main3);
ListView lv = (ListView) findViewById(R.id.listView);
dbAdapter = new DatabaseAdapter(this);
myAdapter = new MyAdapter(this,dbAdapter.findAll());
lv.setAdapter(myAdapter);
getSupportLoaderManager().initLoader(0,null,this);
}
public void addClick(View view){
dbAdapter.save(new Person("vice",20));
loader.onContentChanged();
}
@NonNull
@Override
public Loader<ArrayList<Person>> onCreateLoader(int i, @Nullable Bundle bundle) {
loader = new DataAsyncTaskLoader(this,dbAdapter);
return loader;
}
@Override
public void onLoadFinished(@NonNull Loader<ArrayList<Person>> loader, ArrayList<Person> people) {
myAdapter.setPersons(people);
myAdapter.notifyDataSetChanged();
}
@Override
public void onLoaderReset(@NonNull Loader<ArrayList<Person>> loader) {
myAdapter.setPersons(null);
}
//自定义的Loader类
private static class DataAsyncTaskLoader extends AsyncTaskLoader<ArrayList<Person>>{
private DatabaseAdapter dbAdapter;
private ArrayList<Person> data;
public DataAsyncTaskLoader(Context context,DatabaseAdapter dbAdapter) {
super(context);
this.dbAdapter = dbAdapter;
}
//该方法在后台线程中执行,加载数据
@Override
public ArrayList<Person> loadInBackground() {
System.out.println("loadInBackground");
data = dbAdapter.findAll();
return data;
}
//用于发送结果
@Override
public void deliverResult(@Nullable ArrayList<Person> data) {
if (isReset()){
return;
}
if (isStarted()){
super.deliverResult(data);
}
}
@Override
protected void onStartLoading() {
if (data!=null){
deliverResult(data);
}
if (takeContentChanged()){
forceLoad();//强制加载数据
}
super.onStartLoading();
}
}
private static class MyAdapter extends BaseAdapter{
private ArrayList<Person> persons;
private Context context;
public void setPersons(ArrayList<Person> persons) {
this.persons = persons;
}
public MyAdapter(Context context, ArrayList<Person> persons){
this.context = context;
this.persons = persons;
}
@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) {
ViewHolder vh = null;
if (convertView == null){
convertView = LayoutInflater.from(context).inflate(R.layout.list_item,null);
vh = new ViewHolder();
vh.tv_id = (TextView)convertView.findViewById(R.id.textView_id);
vh.tv_name = (TextView)convertView.findViewById(R.id.textView_name);
vh.tv_age = (TextView)convertView.findViewById(R.id.textView_age);
convertView.setTag(vh);
}else {
vh = (ViewHolder) convertView.getTag();
}
Person p = persons.get(position);
vh.tv_id.setText(String.valueOf(p.getId()));
vh.tv_name.setText(p.getName());
vh.tv_age.setText(String.valueOf(p.getAge()));
return convertView;
}
public static class ViewHolder{
private TextView tv_id;
private TextView tv_name;
private TextView tv_age;
}
}
}