安卓核心技术中级——ContentProvider组件与Loaders

ContentProvider

ContentProvider简介

  1. ContentProviders是用来管理对结构化数据进行访问的一组接口,这组接口对数据进行封装,并提供了用于定义数据安全的机制。ContentProviders是一个进程使用另一个进程数据的标准接口。
  2. Android系统本身也通过content providers来管理数据,如音频视频,图像个人信息等。我们可以在Android.provider包的参考文档中看到这些providers列表,在一定条件下,这些providers能够访问任何android应用程序。
  3. providers最主要的目的是为了让其他应用程序使用provider的客户端对象访问provider。所以,providers和provider客户端共同提供了一个一致的标准数据接口用来处理进程间通信和安全的数据访问。

创建一个ContentProvider

定义ContentProvider继承该类,实现相关方法

  1. 删除符合指定条件的记录
    public int delete(Uri uri,String selection,String[] selectionArgs);
  2. 插入一个新的记录
    public Uri insert(Uri uri,ContentValues values);
  3. 查询符合指定条件的记录
    public Cursor query(Uri uri,String[] projection,String selection,String[] selectionArgs,String sortOrder) ;
  4. 更新条例指定条件的记录
    public int update(Uri uri,ContentValues values,String selection,String[] selectionArgs);
  5. 创建数据储存后端,如数据库,文件,网络接口等,这里主要进行初始工作
    public boolean onCreate();
  6. 基于给定URL,返回该URL表示的MIME类型
    public String getType(Uri uri);
  7. 在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;
        }
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值