android基础学习12——内容提供者ContentProvider的使用

来源:互联网 发布:淘宝店铺装修图片素材 编辑:程序博客网 时间:2024/05/20 21:18

内容提供者(ContentProvider)是Android系统四大组件之一,用于保存和检索数据,是Android系统中不同应用程序之间共享数据的接口。在Android系统中,应用程序之间是相互独立的,分别运行在自己的进程中,相互之间没有数据交换。若应用程序之间需要共享数据,就需要用到ContentProvider。ContentProvider是不同应用程序之间进行数据交换的标准API,它以Uri的形式对外提供数据,允许其他应用操作本应用数据。其他应用则使用ContentResolver,并根据ContentProvider提供的Uri操作指定数据。接下来通过一个案例“读取联系人信息”使用内容提供者暴露数据。该案例实现了查询自己暴露的数据,并将数据捆绑到ListView控件中的功能。

activity.xml

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:id="@+id/ll_root"    android:layout_width="match_parent"    android:layout_height="match_parent"    tools:context="com.example.lenovo.contentprovider.MainActivity">    <ListView        android:id="@+id/lv"        android:layout_width="match_parent"        android:layout_height="match_parent">    </ListView></LinearLayout>


在layout文件夹下创建一个list_item.xml文件

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="60dip"    android:gravity="center_vertical"    android:orientation="horizontal">    <ImageView        android:layout_width="wrap_content"        android:layout_height="wrap_content"        android:layout_marginLeft="5dip"        android:src="@drawable/default_avatar"/>    <LinearLayout        android:layout_width="fill_parent"        android:layout_height="60dip"        android:layout_marginLeft="20dip"        android:gravity="center_vertical"        android:orientation="vertical">        <TextView            android:id="@+id/tv_name"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="5dip"            android:text="姓名"            android:textColor="#000000"            android:textSize="18sp"/>        <TextView            android:id="@+id/tv_phone"            android:layout_width="wrap_content"            android:layout_height="wrap_content"            android:layout_marginLeft="5dip"            android:layout_marginTop="3dp"            android:text="电话"            android:textColor="#88000000"            android:textSize="16sp" />    </LinearLayout></LinearLayout>


在drawble文件夹下添加一张名为default_avater的图片作为联系人的图片

创建数据库

package com.example.lenovo.contentprovider;import android.content.Context;import android.database.sqlite.SQLiteDatabase;import android.database.sqlite.SQLiteOpenHelper;import android.util.Log;/** * Created by lenovo on 2017/6/8. */public class PersonSQLiteOpenHelper extends SQLiteOpenHelper {    private static final String TAG="PersonSQLiteOpenHelper";    //数据库的构造方法,用来定义数据库的名称、数据库查询的结果集、数据库的版本    public PersonSQLiteOpenHelper(Context context){    super(context,"person.db",null,3);    }    //数据库第一次被创建的时候调用的方法    public void onCreate(SQLiteDatabase db){        //初始化数据库的表结构        db.execSQL("create table person(id integer primary key autoincrement,name varchar(20),number varchar(20))");    }    //当数据库的版本号发生变化的时候(增加的时候)调用    public void onUpgrade(SQLiteDatabase db,int oldVersion,int newVersion){        Log.i(TAG,"数据库的版本变化了......");    }}
创建Person类,用于封装id、name和number属性

package com.example.lenovo.contentprovider;/** * Created by lenovo on 2017/6/8. */public class Person {    private int id;    private String name;    private String number;    public Person() {    }    public String toString() {        return "Person [id=" + id + ", name=" + name + ", number=" + number                + "]";    }    public Person(int id, String name, String number) {        this.id = id;        this.name = name;        this.number = number;    }    public int getId() {        return id;    }    public void setId(int id) {        this.id = id;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getNumber() {        return number;    }    public void setNumber(String number) {        this.number = number;    }}
创建内容提供者

创建PersonDBProvider类继承ContentProvider,用于实现暴露数据库程序的功能

package com.example.lenovo.contentprovider;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;/** * Created by lenovo on 2017/6/8. */public class PersonDBProvider extends ContentProvider {    // 定义一个uri的匹配器 用于匹配uri 如果路径不满足条件 返回 -1    private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);    private static final int INSERT = 1;    //添加数据匹配Uri路径成功时返回码    private static final int DELETE = 2;    //删除数据匹配Uri路径成功时返回码    private static final int UPDATE = 3;    //更改数据匹配Uri路径成功时返回码    private static final int QUERY = 4;     //查询数据匹配Uri路径成功时返回码    private static final int QUERYONE = 5; //查询一条数据匹配Uri路径成功时返回码    //数据库操作类的对象    private PersonSQLiteOpenHelper helper;    static {        // 添加一组匹配规则.        matcher.addURI("com.example.lenovo.db.personprovider", "insert", INSERT);        matcher.addURI("com.example.lenovo.db.personprovider", "delete", DELETE);        matcher.addURI("com.example.lenovo.db.personprovider", "update", UPDATE);        matcher.addURI("com.example.lenovo.db.personprovider", "query", QUERY);        //这里的“#”号为通配符凡是符合”query/”皆返回QUERYONE的返回码        matcher.addURI("com.example.lenovo.contentprovider.personprovider", "query/#", QUERYONE);    }    //当内容提供者被创建的时候 调用 适合 数据的初始化    public boolean onCreate() {        helper = new PersonSQLiteOpenHelper(getContext());        return false;    }    //查询数据操作    public Cursor query(Uri uri, String[] projection, String selection,                        String[] selectionArgs, String sortOrder) {        if (matcher.match(uri) == QUERY) { //匹配查询的Uri路径            //匹配成功 ,返回查询的结果集            SQLiteDatabase db = helper.getReadableDatabase();            //调用数据库操作的查询数据的方法            Cursor cursor = db.query("person", projection, selection,                    selectionArgs, null, null, sortOrder);            return cursor;        } else if (matcher.match(uri) == QUERYONE) {            //匹配成功,根据id查询数据            long id = ContentUris.parseId(uri);            SQLiteDatabase db = helper.getReadableDatabase();            Cursor cursor = db.query("person", projection, "id=?",                    new String[]{id+""}, null, null, sortOrder);            return cursor;        } else {            throw new IllegalArgumentException("路径不匹配,不能执行查询操作");        }    }    //获取当前Uri的数据类型    public String getType(Uri uri) {        if (matcher.match(uri) == QUERY) {            // 返回查询的结果集            return "vnd.android.cursor.dir/person";        } else if (matcher.match(uri) == QUERYONE) {            return "vnd.android.cursor.item/person";        }        return null;    }    //添加数据    public Uri insert(Uri uri, ContentValues values) {        if (matcher.match(uri) == INSERT) {            //匹配成功 返回查询的结果集            SQLiteDatabase db = helper.getWritableDatabase();            db.insert("person", null, values);        } else {            throw new IllegalArgumentException("路径不匹配,不能执行插入操作");        }        return null;    }    //删除数据    public int delete(Uri uri, String selection, String[] selectionArgs) {        if (matcher.match(uri) == DELETE) {            //匹配成功 返回查询的结果集            SQLiteDatabase db = helper.getWritableDatabase();            db.delete("person", selection, selectionArgs);        } else {            throw new IllegalArgumentException("路径不匹配,不能执行删除操作");        }        return 0;    }    //更新数据    public int update(Uri uri, ContentValues values, String selection,                      String[] selectionArgs) {        if (matcher.match(uri) == UPDATE) {            //匹配成功 返回查询的结果集            SQLiteDatabase db = helper.getWritableDatabase();            db.update("person", values, selection, selectionArgs);        } else {            throw new IllegalArgumentException("路径不匹配,不能执行修改操作");        }        return 0;    }}
从上述代码中可以看出,在暴露数据的增、删、改、查方法之前,首先需要添加一组用于请求数据操作的Uri,然后在相应的增删改查方法中匹配Uri,匹配成功才能对数据进行操作。

创建数据库逻辑操作类

package com.example.lenovo.contentprovider;import android.content.ContentValues;import android.content.Context;import android.database.sqlite.SQLiteDatabase;/** * Created by lenovo on 2017/6/8. */public class PersonDao2 {    private PersonSQLiteOpenHelper helper;    //在构造方法里面完成helper的初始化    public PersonDao2(Context context){        helper=new PersonSQLiteOpenHelper(context);    }    //添加一条记录到数据库    public long add(String name,String number,int money){        SQLiteDatabase db=helper.getWritableDatabase();        ContentValues values=new ContentValues();        values.put("name",name);        values.put("number",number);        long id=db.insert("person",null,values);        db.close();        return id;    }}

MainActivity

package com.example.lenovo.contentprovider;import android.support.v7.app.AppCompatActivity;import android.os.Bundle;import java.util.ArrayList;import java.util.List;import java.util.Random;import android.content.ContentResolver;import android.database.Cursor;import android.net.Uri;import android.os.Handler;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ListView;import android.widget.TextView;public class MainActivity extends AppCompatActivity {    private ListView lv;    private List<Person>  persons ;    //创建一个Handler对象用于线程间通信    private Handler handler = new Handler(){        public void handleMessage(android.os.Message msg) {            switch (msg.what) {                case 100://接收到数据查询完毕的消息                    //UI线程适配ListView                    lv.setAdapter(new MyAdapter());                    break;            }        };    };    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        lv = (ListView) findViewById(R.id.lv);        //由于添加数据、查询数据是比较耗时的,因此需要在子线程中做这两个操作        new Thread(){            public void run() {                //添加数据                AddData();                //获取persons集合                getPersons();                //如果查询到数据 则向UI线程发送消息                if(persons.size() > 0){                    handler.sendEmptyMessage(100);                }            };        }.start();    }    //往person表中插入10条数据    public void AddData(){        PersonDao2 dao = new PersonDao2(this);        long number = 885900000l;        Random random = new Random();        for(int i=0;i<10;i++){            dao.add("wangwu"+i, Long.toString(number+i), random.nextInt(5000));        }    }    //利用ContentResolver对象查询本应用程序使用ContentProvider暴露的数据    private void getPersons() {        //首先要获取查询的uri        String url = "content://com.example.lenovo.db.personprovider/query";        Uri uri = Uri.parse(url);        //获取ContentResolver对象 这个对象的使用后面会详细讲解        ContentResolver contentResolver = getContentResolver();        //利用ContentResolver对象查询数据得到一个Cursor对象        Cursor cursor = contentResolver.query(uri, null, null, null, null);        persons = new ArrayList<Person>();        //如果cursor为空立即结束该方法        if(cursor == null){            return;        }        while(cursor.moveToNext()){            int id = cursor.getInt(cursor.getColumnIndex("id"));            String name = cursor.getString(cursor.getColumnIndex("name"));            String number = cursor.getString(cursor.getColumnIndex("number"));            Person p = new Person(id, name, number);            persons.add(p);        }        cursor.close();    }    //适配器    private class MyAdapter extends BaseAdapter{        private static final String TAG = "MyAdapter";        // 控制listview里面总共有多个条目        public int getCount() {            return persons.size(); //条目个数 == 集合的size        }        public Object getItem(int position) {            return persons.get(position);        }        public long getItemId(int position) {            return 0;        }        public View getView(int position, View convertView, ViewGroup parent) {            //得到某个位置对应的person对象            Person person = persons.get(position);            View view = View.inflate(MainActivity.this, R.layout.list_item, null);            //一定要在view对象里面寻找孩子的id            //姓名            TextView tv_name = (TextView) view.findViewById(R.id.tv_name);            tv_name.setText("姓名:"+person.getName());            //电话            TextView tv_phone = (TextView) view.findViewById(R.id.tv_phone);            tv_phone.setText("电话:"+person.getNumber());            return view;        }    }}
上述代码使用ContentResolver查询本程序使用ContentProvider暴露的数据。

需要注意的是,当执行耗时操作时,应创建一个子线程将耗时操作放在子线程中,然后使用handler实现子线程与UI线程的通信。
在清单文件中注册PersonDBProvider

        <provider            android:authorities="com.example.lenovo.db.personprovider"            android:name="com.example.lenovo.contentprovider.PersonDBProvider">        </provider>


运行程序能看到如图所示







原创粉丝点击