【Android】第十二周、内容提供者(ContentProvider)

文章目录

    • 内容提供者简介
    • 内容提供者的创建
    • 访问内容提供者
    • 内容观察者的使用
    • 案例:检测数据的猫

内容提供者简介

内容提供者(ContentProvider)是Android系统四大组件之一,它是不同应用程序之间进行数据共享的标准API,通过ContentResolver类可以访问ContentProvider中共享的数据。
ContentProvider的工作原理如下:

【Android】第十二周、内容提供者(ContentProvider)_第1张图片

ContentResolver提供一系列增删改查的方法对数据进行操作,并且这些方法以Uri的形式对外提供数据。
Uri为内容提供者中的数据建立了唯一标识符。它主要由三部分组成,scheme、authorities和path。
【Android】第十二周、内容提供者(ContentProvider)_第2张图片

内容提供者的创建

在程序包名处点击右键选择【New】—【Other】—【Content Provider】选项
输入内容提供者的Class Name(名称)和URI Authorities(唯一标识,通常使用包名)

内容提供者创建完成后,Android Studio会自动在AndroidManifest.xml中对内容提供者进行注册。

    <application ......>
        ......	
        <provider
            android:name=".MyContentProvider"
            android:authorities="cn.itcast.mycontentprovider"
            android:enabled="true"
            android:exported="true" >
       </provider>
    </application>

访问内容提供者

【Android】第十二周、内容提供者(ContentProvider)_第3张图片

内容观察者的使用

内容观察者(ContentObserver)是用来观察指定Uri所代表的数据的,当ContentObserver观察到指定Uri代表的数据发生变化时,就会触发onChange()方法,在该方法中使用ContentResovler可以查询到变化的数据。

要使用ContentObserver观察数据变化,就必须在ContentProviderdelete()insert()update()方法中调用ContentResolvernotifyChange()方法。

ContentObserver的两个常用方法:

public void ContentObserver(Handler handler) : ContentObserver的派生类都需要调用该构造方法。参数可以是主线程Handler,也可以是任何Handler对象(Handler将在第9章讲解)。


public void onChange(boolean selfChange) : 当观察的Uri代表的数据发生变化时,会触发该方法。在该方法中使用ContentResovler可以查询到变化的数据。

【Android】第十二周、内容提供者(ContentProvider)_第4张图片

【Android】第十二周、内容提供者(ContentProvider)_第5张图片

ContentResolver resolver = getContentResolver();
    Uri uri = Uri.parse("content://aaa.bbb.ccc");
    resolver.registerContentObserver(uri, true, new MyObserver(new Handler()));

    private class MyObserver extends ContentObserver{
        public MyObserver(Handler handler) {
            super(handler);
        }
        public void onChange(boolean selfChange) {
            super.onChange(selfChange);
            Uri uri = Uri.parse("content://aaa.bbb.ccc");//会监测该Uri的数据变化情况
            ContentResolver resolver = getContentResolver();
            Cursor cursor = resolver.query(uri, new String[] { "address", "date", "type", "body" }, null, null, null);
           // ......
            cursor.close();
        }
    }

案例:检测数据的猫

【Android】第十二周、内容提供者(ContentProvider)_第6张图片
PersonDBOpenHelper 类:创建数据库和表

public class PersonDBOpenHelper extends SQLiteOpenHelper {

    //构造方法,调用此方法新建一个person.db的数据库并返回一个数据库帮助类的对象
    public PersonDBOpenHelper(Context context) {
        super(context, "person.db", null, 1);
    }
    @Override
    public void onCreate(SQLiteDatabase db) {
        //创建该数据库的同时新建一个info表,表中有_id,name这两个字段
        db.execSQL("create table info (_id integer primary key autoincrement, name varchar(20))");
    }
    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
    }

}

PersonProvider:内容提供者,向外部提供对数据库表info表的增删改查

public class PersonProvider extends ContentProvider {

    //定义一个uri路径的匹配器,如果路径匹配不成功返回 -1
    private static UriMatcher mUriMatcher = new UriMatcher(-1);
    //匹配路径成功时的返回码
    private static final int SUCCESS = 1;
    //数据库操作类的对象
    private PersonDBOpenHelper helper;
    //添加路径匹配器的规则
    static {
        mUriMatcher.addURI("com.example.week13_01.contentobserverdb", "info", SUCCESS);
    }



    public PersonProvider() {
    }


    @Override
    public boolean onCreate() {
        helper = new PersonDBOpenHelper(getContext());
        return false;
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getWritableDatabase();
            int count = db.delete("info", selection, selectionArgs);
            //提示数据库的内容变化了
            if (count > 0) {
                getContext().getContentResolver().notifyChange(uri, null);
            }
            db.close();
            return count;
        } else {
            throw new IllegalArgumentException("路径不正确,我是不会让你随便删除数据的!");
        }
    }

    @Override
    public String getType(Uri uri) {
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getReadableDatabase();
            long rowId = db.insert("info", null, values);
            if (rowId > 0) {
                Uri insertedUri = ContentUris.withAppendedId(uri, rowId);
                //提示数据库的内容变化了
                getContext().getContentResolver().notifyChange(insertedUri, null);
                return insertedUri;
            }
            db.close();
            return uri;
        } else {
            throw new IllegalArgumentException("路径不正确,我是不会给你插入数据的!");
        }
    }


    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        //匹配查询路径
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS){
            SQLiteDatabase db = helper.getReadableDatabase();
            return db.query("info", projection, selection, selectionArgs, null, null, sortOrder);
        }else{
            throw new IllegalArgumentException("路径不正确,我是不会给你提供数据的!");
        }

    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        int code = mUriMatcher.match(uri);
        if (code == SUCCESS) {
            SQLiteDatabase db = helper.getWritableDatabase();
            int count = db.update("info", values, selection, selectionArgs);
            //提示数据库的内容变化了
            if (count > 0) {
                getContext().getContentResolver().notifyChange(uri, null);
            }
            db.close();
            return count;
        } else {
            throw new IllegalArgumentException("路径不正确,我是不会让你更新数据的!");
        }
    }
}

resolver : 内容消费者,调用内容

public class MainActivity extends AppCompatActivity implements View.OnClickListener {
    private ContentResolver resolver;
    private Uri uri;
    private ContentValues values;
    private Button btnInsert;
    private Button btnUpdate;
    private Button btnDelete;
    private Button btnSelect;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();//初始化界面
        createDB();//创建数据库
    }
    private void initView() {
        btnInsert = (Button) findViewById(R.id.btn_insert);
        btnUpdate = (Button) findViewById(R.id.btn_update);
        btnDelete = (Button) findViewById(R.id.btn_delete);
        btnSelect = (Button) findViewById(R.id.btn_select);
        btnInsert.setOnClickListener(this);
        btnUpdate.setOnClickListener(this);
        btnDelete.setOnClickListener(this);
        btnSelect.setOnClickListener(this);
    }
    private void createDB() {
        //创建数据库并向info表中添加3条数据
        PersonDBOpenHelper helper = new PersonDBOpenHelper(this);
        SQLiteDatabase db = helper.getWritableDatabase();
        for (int i = 0; i < 3; i++) {
            ContentValues values = new ContentValues();
            values.put("name", "itcast" + i);
            db.insert("info", null, values);
        }
        db.close();
    }
    @Override
    public void onClick(View v) {
        //得到一个内容提供者的解析对象
        resolver = getContentResolver();
        //新加一个uri路径,参数是string类型的
        uri = Uri.parse("content://com.example.week13_01.contentobserverdb/info");
        //新建一个ContentValues对象,该对象以key-values的形式来添加记录到数据库表中
        values = new ContentValues();
        switch (v.getId()) {
            case R.id.btn_insert:
                Random random = new Random();
                values.put("name", "add_itcast" + random.nextInt(10));
                Uri newuri = resolver.insert(uri, values);
                Toast.makeText(this, "添加成功", Toast.LENGTH_SHORT).show();
                Log.i("数据库应用:", "添加");
                break;
            case R.id.btn_delete:
                //返回删除数据的条目数
                int deleteCount = resolver.delete(uri, "name=?",
                        new String[]{"itcast0"});
                Toast.makeText(this, "成功删除了" + deleteCount + "行",
                        Toast.LENGTH_SHORT).show();
                Log.i("数据库应用:", "删除");
                break;
            case R.id.btn_select:
                List<Map<String, String>> data = new ArrayList<Map<String, String>>();
                //返回查询结果,是一个指向结果集的游标
                Cursor cursor = resolver.query(uri, new String[]{"_id", "name"},
                        null, null, null);
                //遍历结果集中的数据,将每一条遍历的结果存储在一个List的集合中
                while (cursor.moveToNext()) {
                    Map<String, String> map = new HashMap<String, String>();
                    map.put("_id", cursor.getString(0));
                    map.put("name", cursor.getString(1));
                    data.add(map);
                }
                //关闭游标,释放资源
                cursor.close();
                Log.i("数据库应用:", "查询结果:" + data.toString());
                break;
            case R.id.btn_update:
                //将数据库info表中name为itcast1的这条记录更改为name是update_itcast
                values.put("name", "update_itcast");
                int updateCount = resolver.update(uri, values, "name=?",
                        new String[]{"itcast1"});
                Toast.makeText(this, "成功更新了" + updateCount + "行",
                        Toast.LENGTH_SHORT).show();
                Log.i("数据库应用:", "更新");
                break;
        }
    }
}

新建一个模块:monitor,检测者

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // 该uri路径指向数据库应用中的数据库info表
        Uri uri = Uri.parse("content://cn.itcast.contentobserverdb/info");
        //注册内容观察者,参数uri指向要监测的数据库info表,
        //参数true定义了监测的范围,最后一个参数是一个内容观察者对象
        getContentResolver().registerContentObserver(uri, true,
                new MyObserver(new Handler()));
    }

    private class MyObserver extends ContentObserver {
        public MyObserver(Handler handler) {//handler 是一个消息处理器。
            super(handler);
        }
        @Override
        //当info表中的数据发生变化时则执行该方法
        public void onChange(boolean selfChange) {
            Log.i("监测数据变化", "有人动了你的数据库!");
            super.onChange(selfChange);
        }
    }
}

你可能感兴趣的:(其他)