contenProvider模块知识

大纲

名称ContentProvider(内容提供者)ContentResolver(内容解析者)
作用1. Android中的四大组件之一
2.用于应用程序之间的数据共享
3.将数据的访问方式统一
1.用于从ContentProvider提供的接口中获取数据
2.对ContentProvider提供的数据进行增删改查
关系提供数据,用于数据共享获取数据,进行数据操作

URI的概念

URI是一个标识符,为字符串类型
由scheme、authorites、path三部分组成
content://cn.itcast.sqlite.provider/person
scheme:固定为content,代表访问内容提供者
authorites:节点中的authorites属性
一般为包名.类名
使用场景
1.定义Uri
2.在清单文件中注册ContentProvider

path:程序定义的路径,可根据业务逻辑定义

MIME(多用途互联网邮件扩展类型)

定义:MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型。是设定某种扩展名的文件用一种应用程序来打开的方式类型,当该扩展名文件被访问的时候,浏览器会自动使用指定应用程序来打开。多用于指定一些客户端自定义的文件名,以及一些媒体文件打开方式。它是一个互联网标准,扩展了电子邮件标准,使其能够支持:
例如:左边是文件的具体大类型,右边是具体的文件类型
超文本标记语言文本 .html
text/html
xml文档 .xml
text/xml
XHTML文档 .xhtml
application/xhtml+xml
普通文本 .txt
text/plain

常用的辅助类

UriMatch类

用于注册和匹配给定的URI

方法说明
addURI(String authority, String path, int code)code:表示匹配成功后的返回值
match(Uri uri)匹配Uri

ContentUris

Uri工具类,用于处理Uri尾部的id

方法说明
withAppendId将id添加到Uri的尾部,并将其返还给客户
parseId获取path的数据

ContentObserver

内容观察者,用于ContentProvider提供的数据发生变化时,执行回调更新。
我们在ContentProvider的insert,update,delete等改变之后调用getContext().getContentResolver().notifyChange(uri, null);这样就通知那些监测databases变化的observer了,而你的observer可以在一个service里面注册。

方法说明
registerContentObserve(Uri uri, boolean notifyForDescendants, ContentObserver observer)注册
onChange(boolean selfChange)回调

注意
registerContentObserve()是ContentResolver类中的方法。
onChange(boolean selfChange)是ContentObserver中的方法。

自定义ContentProvider步骤

1.定义一个类,继承自ContentProvider
2.在清单文件中进行声明
3.定义一个类,继承自ContentObserver,实现onChange方法(可选)

代码实现

定义一个类

由于ContentProvider的创建涉及到数据库的建立,故要先写一个SQLiteOpenHelper来创建数据库

DbHelper的oncreate()的sql语句,新建一个数据库,并插入一条数据。

package com.example.contentproviderdemo2.db;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

/**
 * Created by 15426 on 2020/9/27.
 */

public class DbHelper extends SQLiteOpenHelper {
    public DbHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        String sql = "create table person("
                +"id integer primary key autoincrement,"
                +"name varchar(20),"
                +"age integer(5),"
                +"sex integer(2),"
                +"desc varchar(200))";
        String sql2 ="insert into person (name, age, sex, desc) values(?,?,?,?)";


        db.execSQL(sql);
        db.execSQL(sql2,new String[]{
                "barry","23","1","he is a man"
        });

    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

    }
}

实现ContentProvider类,这里最主要的是,写好那些Uri,authority等常量。

package com.example.contentproviderdemo2.provider;

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;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;

import com.example.contentproviderdemo2.db.DbHelper;

/**
 * 自定义ContentProvider来实现Person信息的增删改查
 * ContentProvider的insert,update,delete等改变之后
 * 调用getContext().getContentResolver().notifyChange(uri, null);这里传null,、
 * 是说明不需要指定observer,,要在注册时传入自己定义的observer即可,这里就会自动找到相关的observer.
 * 这样就通知那些监测databases变化的observer了,就会调用onChange()方法了。
 * Created by 15426 on 2020/9/27.
 */

public class PersonProvider extends ContentProvider {
    //所有常量都要用有意义的变量名表示出来。
    private static final String PACKAGE_NAME = "com.example.contentproviderdemo2";
    private static final String DB_NAME ="person.db";
    private static final String TABLE_NAME = "person";
    private static final int DB_VISION = 1;
    //包名+类名
    private static final String AUTHORITY = PACKAGE_NAME +".provider.PersonProvider";
    private static final String CONTENT_TIPE = "vnd.android.cursor.dir/"+AUTHORITY+"."+TABLE_NAME;
    private static final String CONTENT_ITEM_TYPE ="vnd.android.cursor.item/"+AUTHORITY+"."+TABLE_NAME;
    private static final int DIR_CODE= 0;
    private static final int ITEM_CODE =1;


    public static final Uri CONTENT_URI = Uri.parse("content://"+AUTHORITY+"/"+TABLE_NAME);

    private DbHelper dbHelper;//null
    private static UriMatcher matcher;//null
    static {
        matcher = new UriMatcher(UriMatcher.NO_MATCH);
        matcher.addURI(AUTHORITY,TABLE_NAME,DIR_CODE);
        matcher.addURI(AUTHORITY,TABLE_NAME+"/#",ITEM_CODE);
    }

    /**
     * 初始化提供其,在这里完成对数据库的创建和升级
     * @return true表示创建或升级成功。
     */
    @Override
    public boolean onCreate() {
        dbHelper = new DbHelper(getContext(),DB_NAME,null,DB_VISION);

        return true;
    }

    @Nullable
    @Override
    public Cursor query(@NonNull Uri uri, @Nullable String[] projection,
                        @Nullable String selection, @Nullable String[] selectionArgs,
                        @Nullable String sortOrder) {
        //获取数据库
        SQLiteDatabase db = dbHelper.getReadableDatabase();
        //先对不同的uri进行处理,最后在统一的查询
        selection = handlerSelection(uri, selection);
        if(selection.equal(null)){
        	retrun null;
        }
        Cursor cursor= db.query(TABLE_NAME,projection,selection,selectionArgs,null,null,sortOrder);

        return cursor;
    }

    private String handlerSelection(@NonNull Uri uri, @Nullable String selection) {
        switch (matcher.match(uri)){
            case DIR_CODE://集合不需要做任何处理
                break;
            case ITEM_CODE://单条记录需要处理尾部的id,并且和现有的查询条件进行拼接
                long id = ContentUris.parseId(uri);
                if (TextUtils.isEmpty(selection)){
                    selection = "id ="+ id;
                }else {
                    selection += "and id ="+id;
                }
                break;
            default:
           	 return null;
        }
        return selection;
    }

    /**
     * 获取Uri对象的类型
     * @param uri
     * @return
     */
    @Nullable
    @Override
    public String getType(@NonNull Uri uri) {
        switch (matcher.match(uri)){
            case DIR_CODE:
                return CONTENT_TIPE;
            case ITEM_CODE:
                return CONTENT_ITEM_TYPE;
        }
        return null;
    }

    @Nullable
    @Override
    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        long newID = db.insert(TABLE_NAME,null,values);
        //直接将id后缀到uri之中
        Uri newUri =  ContentUris.withAppendedId(CONTENT_URI,newID);
        if (newUri !=null){
            getContext().getContentResolver().notifyChange(newUri,null);
            return newUri;
        }
        return null;
    }

    @Override
    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        selection = handlerSelection(uri,selection);
        int result =  db.delete(TABLE_NAME,selection,selectionArgs);
        if (result >0){
            getContext().getContentResolver().notifyChange(uri,null);
            return result;

        }
        return 0;

    }

    @Override
    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        selection = handlerSelection(uri,selection);
        int result =  db.update(TABLE_NAME,values,selection,selectionArgs);
        if (result >0){
            getContext().getContentResolver().notifyChange(uri,null);
            return result;

        }
        return 0;

    }
}

实现数据的自动更新

要在三个类中进行逻辑编写。
1.ContentResolver 的数据修改,其实是调用ContentProvider的insert, updete, delete,函数。
故可以根据这三个函数的返回结果,来判断是否发出给obeserver发出通知。
getContext().getContentResolver().notifyChange(uri, null);这样就通知那些监测databases变化的observer了。
insert函数

long newID = db.insert(TABLE_NAME,null,values);
//直接将id后缀到uri之中
Uri newUri =  ContentUris.withAppendedId(CONTENT_URI,newID);
if (newUri !=null){
    getContext().getContentResolver().notifyChange(newUri,null);
    return newUri;
}
}

obeserver收到通知,会调用onChange
在observer类中,通常是进行异步传递机制。
由于obeserver类的构造需要一个handler形参。

package com.example.contentproviderdemo2.observer;

import android.database.ContentObserver;
import android.os.Handler;
import android.os.Message;

/**
 * Created by 15426 on 2020/9/28.
 */

public class PersonObserver extends ContentObserver {
    private Handler mHandler;//null
    private static final int MESSAGE_WHAT = 100;
    /**
     * Creates a content observer.
     *handler是用来运行onChange()
     * @param handler The handler to run {@link #onChange} on, or null if none.
     */
    public PersonObserver(Handler handler) {
        super(handler);
        mHandler = handler;
    }

    @Override
    public void onChange(boolean selfChange) {
        super.onChange(selfChange);
        //最简单的消息传递机制
        Message message = Message.obtain();
        message.what = MESSAGE_WHAT;
        mHandler.sendMessage(message);
    }
}

由于obeserver类的构造需要一个handler形参。
故在显示活动类中,写一个handler 字段,并且进行注册.
MainActivity.java

private static final int MESSAGE_WHAT = 100;
private Handler observerHandler = new Handler(){
    @Override
    public void handleMessage(Message msg) {
        switch (msg.what){
            case MESSAGE_WHAT:
                initData();
                break;
        }
    }
};
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();
    //需要对ContentObserver进行注册
    resolver = getContentResolver();
    obsever = new PersonObserver(observerHandler);
    resolver.registerContentObserver(PersonProvider.CONTENT_URI,true,obsever);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值