android 学习笔记12-内容提供者

1、内容提供者

实际的开发中,一般也比较少开发自定义的内容提供者,一般都是使用
应用的数据库是不允许其他应用访问的
内容提供者的作用就是让别的应用访问到你的私有数据,就是一个java类
自定义内容提供者,继承ContentProvider类,重写增删改查方法,在方法中写增删改查数据库的代码,举例增方法
使用内容提供者可以自己定义访问规则,选择私有数据中哪些共享出去,哪些不共享

注意(特别重要):我们一定要认真配置清单文件xml
<provider android:name="com.example.contentprovider.PersonProvider"//包名.类名
    android:authorities="com.example.person"//可以理解为权限
    android:exported="true">
</provider>

代码演示:
a,内容提供者的xml文件配置
    <provider android:name="com.example.contentprovider.PersonProvider"//包名.类名
        android:authorities="com.example.person"//可以理解为权限
        android:exported="true">
    </provider>
b,内容提供者定义:
    public class PersonProvider extends ContentProvider {//继承ContentProvider,重写里面的方法
        private SQLiteDatabase db;

        //内容提供者创建时调用
        @Override
        public boolean onCreate() {
            MyOpenHelper oh = new MyOpenHelper(getContext());
            db = oh.getWritableDatabase();
            return false;
        }

        //values:其他应用要插的数据
        @Override
        public Uri insert(Uri uri, ContentValues values) {//插入
            db.insert("person", null, values);//这里的values是调用者传进来的数据,因为我们内容提供者自己肯定不会去插数据的
            return uri;
        }

        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {//删除
            int i = 0;
            i = db.delete("person", selection, selectionArgs);
            return i;
        }

        @Override
        public int update(Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {//修改
            int i = db.update("person", values, selection, selectionArgs);
            return i;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
            String[] selectionArgs, String sortOrder) {//查询
            Cursor cursor = null;
            cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder, null);
            return cursor;
        }

    }

c,我们访问者定义
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }

        public void insert(View v){
            //通过内容提供者把数据插入01数据库
            //1.获取contentResolver
            ContentResolver resolver = getContentResolver();
            //2.访问内容提供者,插入数据
            ContentValues values = new ContentValues();
            values.put("name", "张三");
            values.put("phone", 123456);
            values.put("money", 10000);
            //arg0:指定内容提供者的主机名
            resolver.insert(Uri.parse("content://com.example.people"), values);

            values.clear();
            values.put("name", "李四");
            values.put("phone", 12345);
            //arg0:指定内容提供者的主机名
            resolver.insert(Uri.parse("content://com.example.people"), values);
        }

        public void delete(View v){
            ContentResolver resolver = getContentResolver();
            int i = resolver.delete(Uri.parse("content://com.example.people"), "name = ?", new String[]{"张三"});
            System.out.println(i);
        }

        public void update(View v){
            ContentResolver resolver = getContentResolver();
            ContentValues values = new ContentValues();
            values.put("money", 10001);
            int i = resolver.update(Uri.parse("content://com.example.people"), values, "name = ?", new String[]{"张三"});
            System.out.println(i);//更新的记录数
        }

        public void query(View v){
            ContentResolver resolver = getContentResolver();
            Cursor cursor = resolver.query(Uri.parse("content://com.example.people"), null, null, null, null);
            while(cursor.moveToNext()){
                String name = cursor.getString(1);
                String phone = cursor.getString(2);
                String money = cursor.getString(3);
                System.out.println(name + ";" + phone + ";" + money);
            }
        }
    }

这样大体的定义和访问就可以实现了,但是还有一些问题

2、内容提供者-优化

我们发现上面的内容提供者里面的表名都是写死的 db.insert("person", null, values);
如果我们现在有个handsome表,想操作它就不行了

我们要操作那张表就把表名放到uri里面传过去就行了 
resolver.insert(Uri.parse("content://com.example.people/person"), values);
那在提供者就去判断下是哪张表,我们可以使用一个API UriMatcher
在内容提供者里面添加:
    //创建uri匹配器
    UriMatcher um = new UriMatcher(UriMatcher.NO_MATCH);//UriMatcher.NO_MATCH -1 , 如果都不匹配的话就返回-1
    {
        //添加匹配规则
        //arg0:主机名
        //arg1:路径
        //arg2:匹配码,这个是自己定义的,如果匹配成功了,就返回这个匹配码
        um.addURI("com.example.people", "person", 1);//content://com.example.people/person
        um.addURI("com.example.people", "handsome", 2);//content://com.example.people/handsome
        um.addURI("com.example.people", "person/#", 3);//content://com.example.people/person/10
    }

uri里面还可以携带数字,一般用于查询的条件
取出数字的API:int id = (int) ContentUris.parseId(uri);

mimetype的数据是自己定义的,方便其它同事辨认是那个数据,比如说是person数据

优化后的代码:
    public class PersonProvider extends ContentProvider {
        private SQLiteDatabase db;
        //创建uri匹配器
        UriMatcher um = new UriMatcher(UriMatcher.NO_MATCH);
        {
            //添加匹配规则
            //arg0:主机名
            //arg1:路径
            //arg2:匹配码
            um.addURI("com.example.people", "person", 1);//content://com.example.people/person
            um.addURI("com.example.people", "handsome", 2);//content://com.example.people/handsome
            //*代表所有的字符,#号代表所有的数字
            um.addURI("com.example.people", "person/#", 3);//content://com.example.people/person/10
        }

        //内容提供者创建时调用
        @Override
        public boolean onCreate() {
            MyOpenHelper oh = new MyOpenHelper(getContext());
            db = oh.getWritableDatabase();
            return false;
        }

        //values:其他应用要插的数据
        //注意这里修改了,里面不再写死表的名称,可以判断到底使用的是哪个表
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            if(um.match(uri) == 1){
                db.insert("person", null, values);
                //数据库改变了,内容提供者发出通知
                //arg0:通知发到哪个uri上,注册在这个uri上的内容观察者都可以收到通知
                getContext().getContentResolver().notifyChange(uri, null);
            }
            else if(um.match(uri) == 2){
                db.insert("handsome", null, values);
                getContext().getContentResolver().notifyChange(uri, null);
            }
            else{
                throw new IllegalArgumentException("uri传错");
            }
            return uri;
        }

        //上面修改了,下面的和上面的类似修改就好了
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
            int i = 0;
            if(um.match(uri) == 1){
                i = db.delete("person", selection, selectionArgs);
            }
            else if(um.match(uri) == 2){
                i = db.delete("handsome", selection, selectionArgs);
            }
            else{
                throw new IllegalArgumentException("uri又传错");
            }

            return i;
        }

        @Override
        public int update(Uri uri, ContentValues values, String selection,
                String[] selectionArgs) {
            int i = db.update("person", values, selection, selectionArgs);
            return i;
        }

        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            Cursor cursor = null;
            if(um.match(uri) == 1){
                cursor = db.query("person", projection, selection, selectionArgs, null, null, sortOrder, null);
            }
            else if(um.match(uri) == 2){
                cursor = db.query("handsome", projection, selection, selectionArgs, null, null, sortOrder, null);
            }
            else if(um.match(uri) == 3){
                //取出uri末尾携带的数字
                long id = ContentUris.parseId(uri);
                //查询一条数据,使用主键查询
                cursor = db.query("person", projection, "_id = ?", new String[]{"" + id}, null, null, sortOrder, null);
            }
            return cursor;
        }

        //返回通过指定uri获取的数据的mimetype,
        @Override
        public String getType(Uri uri) {
            if(um.match(uri) == 1){
                return "vnd.android.cursor.dir/person";//也可以定义ab/c,但是为了规范还是规范定义好了
            }
            else if(um.match(uri) == 2){
                return "vnd.android.cursor.dir/handsome";
            }
            else if(um.match(uri) == 3){
                return "vnd.android.cursor.item/person";
            }
            return null;
        }
    }


温馨提示:使用内容提供者的好处,为什么不直接把数据库公开呢。我们主要考虑数据的安全性,如果公开了,那么数据可以被任意访问,我们定义了内容提供者
    就可以控制访问的规则,需要共享哪个表,或者哪个字段都可以的。

3、应用-读取系统短信

代码演示:
    public class MainActivity extends Activity {
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
        }

        public void click1(View v){//点击按钮进行查询
            ContentResolver resolver = getContentResolver();//获取一个ContentResolver
            //定义我们需要查询的字段,不是所有的字段我们都要
            Cursor cursor = resolver.query(Uri.parse("content://sms"), new String[]{"address", "date", "type", "body"}, null, null, null);
            while(cursor.moveToNext()){//获取每条短信记录,这里我们用 0,1,2,3 代替,其实也可以用名称查出索引值的
                String address = cursor.getString(0);
                long date = cursor.getLong(1);
                int type = cursor.getInt(2);
                String body = cursor.getString(3);
                System.out.println(address + ";" + date + ";" + type + ";" + body);
            }
        }
    }

这样不行,因为还需要权限,非常重要的
<uses-permission android:name="android.permission.READ_SMS"/>

4、插入系统短信

代码演示:
public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    public void click(View v){
        Thread t = new Thread(){
            @Override
            public void run() {
                try {
                    sleep(10000);//等一会10s界面就会显示来的短信
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                ContentResolver resolver = getContentResolver();
                ContentValues values = new ContentValues();
                values.put("address", 95555);
                values.put("date", System.currentTimeMillis());
                values.put("type", 1);
                values.put("body", "您尾号为XXXX的招行储蓄卡收到转账1,000,000");
                resolver.insert(Uri.parse("content://sms"), values);
            }
        };
        t.start();
    }
}

5、获取联系人

代码演示:
MainActivity.java
public class MainActivity extends Activity {

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

    public void click(View v){
        ContentResolver resolver = getContentResolver();

        Cursor cursor = resolver.query(Uri.parse("content://com.android.contacts/raw_contacts"), new String[]{"contact_id"}, 
                null, null, null);
        while(cursor.moveToNext()){
            String contactId = cursor.getString(0);
            //使用联系人id作为where条件去查询data表,查询出属于该联系人的信息
            Cursor cursorData = resolver.query(Uri.parse("content://com.android.contacts/data"), new String[]{"data1", "mimetype"}, "raw_contact_id = ?", 
                    new String[]{contactId}, null);

            Contact contact = new Contact();
            while(cursorData.moveToNext()){
                String data1 = cursorData.getString(0);
                String mimetype = cursorData.getString(1);

                if("vnd.android.cursor.item/email_v2".equals(mimetype)){
                    contact.setEmail(data1);
                }
                else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
                    contact.setPhone(data1);
                }
                else if("vnd.android.cursor.item/name".equals(mimetype)){
                    contact.setName(data1);
                }
            }
            System.out.println(contact.toString());
        }
    }
}

Contact.java
public class Contact {

    private String name;
    private String phone;
    private String email;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    @Override
    public String toString() {
        return "Contact [name=" + name + ", phone=" + phone + ", email="
                + email + "]";
    }
}

6、插入联系人

先查询raw\_contacts表,确定新的联系人的id应该是多少
把确定的联系人id插入raw\_contacts表
    cv.put("contact_id", _id);
    cr.insert(Uri.parse("content://com.android.contacts/raw_contacts"), cv);

在data表插入数据
    插3个字段:data1、mimetype、raw\_contact_id

        cv = new ContentValues();
        cv.put("data1", "张三");
        cv.put("mimetype", "vnd.android.cursor.item/name");
        cv.put("raw_contact_id", _id);
        cr.insert(Uri.parse("content://com.android.contacts/data"), cv);

        cv = new ContentValues();
        cv.put("data1", "123456");
        cv.put("mimetype", "vnd.android.cursor.item/phone_v2");
        cv.put("raw_contact_id", _id);
        cr.insert(Uri.parse("content://com.android.contacts/data"), cv);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值