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

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

activity.xml




    
    



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




    
    
        
        
    



在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  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();
        //如果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

        
        


运行程序能看到如图所示

android基础学习12——内容提供者ContentProvider的使用_第1张图片






你可能感兴趣的:(新手)