ContentProvider

来源:互联网 发布:猎豹刷票软件 编辑:程序博客网 时间:2024/06/08 06:07

[访问其他应用中的数据——获取数据]

< ContentResolver 的基本用法>

  • 访问内容提供器中的共享数据就必要借助 ContentResolver
    • 可以通过 Context 中的 getContentResolver() 方法获取实例
    • 提供了一些列的 CRUD 操作,类似 SQLiteDatabase。不同的是 CRUD 操作不提供表名,使用 Uri 参数代替
      • URI 权限:对于不同的应用程序做区分。一般采用程序包命名
      • URI 路径:同一程序中的不同的表做区分。
        标准的 URI 格式:content://com.example.app.provider(权限)/table1(路径)
        如果使用表名,系统将无法得知我们访问的是哪个应用程序中的表
    • 使用 Uri.parse() 方法,就可以将内容 URI 字符串解析为 Uri 对象
    Uri uri = Uri.parse("content://com.example.app.provider/table1");

使用 Uri 对象来查询 table1 表中的数据

    Cursor cursor = getContentResolver().query(    uri, //指定某个应用的某张表    projection, //指定查询的列名    selection, //指定 where 的约束条件    selectionArgs, //为 where 中的占位符提供具体的值    sortOrder // 排序方式);

查询完毕,逐条读取数据

    if(cursor != null){    while(cursor.moveToNext()){        String column1 = cursor.getString(cursor.getColumnIndex("column1"));        int column2 = cursor.getInt(cursor.getColumnIndex("column2"));    }    cursor.close();}
ContentValues values = new ContentValues();values.put("column1", "text");values.put("column2", 1);getContentResolver().insert(uri, values);
ContentValues values = new ContentValues();values.put("column1", "");getContentResolver().update(uri, values, "column1 = ? and column2 = ?", new String[]{ "text", "1" });
getContentResolver().delete(uri,"column2 = ?", new String[]{ "1" });

<读取系统联系人>

MainActivity.class

public class MainActivity extends Activity {    ListView contactsView;    ArrayAdapter<String> adapter;    List<String> contacstList = new ArrayList<String>();    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        contactsView = (ListView) findViewById(R.id.contacts_view);        adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contacstList);        contactsView.setAdapter(adapter);        readContacts();    }    private void readContacts() {        Cursor cursor = null;        try{            //查询联系人            cursor = getContentResolver().query(                    ContactsContract.CommonDataKinds.Phone.CONTENT_URI, //获取手机通信录的 Uri                    null,null,null,null            );            while (cursor.moveToNext()) {                //获取联系人姓名                String displayName = cursor.getString(cursor.getColumnIndex(                        ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME                ));                //获取联系人手机                String number = cursor.getString(cursor.getColumnIndex(                        ContactsContract.CommonDataKinds.Phone.NUMBER                ));                contacstList.add(displayName + "\n" + number);            }        }catch (Exception e){            e.printStackTrace();        }finally {            if(cursor != null){                cursor.close();            }        }    }}

AndroidManifest.xml 中获取权限

 <uses-permission android:name="android.permission.READ_CONTACTS" />

[创建自己的内容提供器——提供数据]

  • 之前是如何在自己的程序中访问其他应用的数据。思路:获取该应用程序的 URI,借助 ContentResolver 进行 CRUD 操作
  • 现在来实现将数据提供出去,给其他应用访问,并保证安全性。

<创建内容提供器的步骤>

创建个类继承 ContentProvider 类并重写它的六个抽象方法

public class MyProvider extends ContentProvider {    //初始化内容提供器的时候调用。完成对数据库的创建和升级操作。返回 true 表示初始化成功,false 表示失败。    //ContentResolver 尝试访问本程序中的数据时,内容提供器才会被初始化    @Override    public boolean onCreate() {        return false;    }    //从内容提供器中查询数据    //1、Uri 确定查询哪一张表    //2、projection 确定查询哪些列    //3、selection 和 selectionArgs 参数约束哪些行    //4、sortOrder 对结果进行排序    //查询结果存放在 Cursor 对象中返回    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        return null;    }    //向内容提供器中添加一条数据    //1、URI 参数来确定添加哪一张表    //2、待添加的数据保存在 values 中    //返回一个用于表示这条新记录的 URI    @Override    public Uri insert(Uri uri, ContentValues values) {        return null;    }    //1、URI确定删除哪一张表    //2、selection,selectionArgs 来约束删除哪些行    //被删除的行将作为返回值    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        return 0;    }    //1、URI确定更新哪一张表    //2、新数据保存在 values 中    //3、selection,selectionArgs 来约束更新哪些行    //受影响的行将作为返回值    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        return 0;    }    //根据传入内容的 URI 返回相应的 MIME 类型    @Override    public String getType(Uri uri) {        return null;    }}
  • 每一个方法都有一个 URI参数,此参数是调用ContentResolver 的增删改查方法时传递过来的。而我们需要对 Uri 参数进行解析,从中分析出调用方期望访问的表和数据

  • URI后面可以加 id,以路径结尾表示期望访问该表中的所有数据,以 id 结尾表示期望访问该表中拥有相应 id 的数据

  • 通配符方式匹配 URI

    • *:表示匹配任意长度的任意字符
      • content://com.example.app.provider/*
    • #:表示匹配任意长度的数字
      • content://com.example.app.provider/#
public class MyProvider extends ContentProvider {    public static final int TABLE1_DIR = 0;    public static final int TABLE1_ITEM = 1;    public static final int TABLE2_DIR = 2;    public static final int TABLE2_ITEM = 3;    private static UriMatcher uriMatcher;    static{        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);// 将 uri 传入 uriMatcher        uriMatcher.addURI("com.example.app.provider","table1",TABLE1_DIR);        uriMatcher.addURI("com.example.app.provider","table1/#",TABLE1_ITEM);        uriMatcher.addURI("com.example.app.provider","table2",TABLE2_DIR);        uriMatcher.addURI("com.example.app.provider","table2/#",TABLE2_ITEM);    }    ......    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {// 在 uriMatcher 中逐个匹配 uri,选取调用方期望访问的那一张表        switch (uriMatcher.match(uri)){            case TABLE1_DIR:                // 查询 table1 表中的所有数据                break;            case TABLE1_ITEM:                // 查询 table1 表中的单条数据                break;            case TABLE2_DIR:                // 查询 table2 表中的所有数据                break;            case TABLE2_ITEM:                // 查询 table2 表中的单条数据                break;            default:                break;        }        ......    }    ......

上述代码只是用 query() 作为范例。insert()update()delete() 这个方法类似:1、它们都会携带 Uri 参数 2、利用 UriMatcher 的 match() 方法判断出调用方期望访问的是哪一张表,再对该表中的数据进行相应的操作就可以了。

  • 除此之外还有个 getType() 方法。用于获取 Uri 对象所对应的 MIME 类型。MIME 字符串由三部分构成:

    1. 必须以vnd 开头
    2. 如果内容以 URI 路径结尾,则后接 android.cursor.dir/,如果内容 URI 以 id 结尾,则后接 android.cursor.item/。
    3. 最后接上 vnd.< authority >.< path >

      列如
      URIcontent://com.example.app.provider/table1
      MIMEvnd.android.cursor.dir/vnd.com.example.app.provider.table1

      • 代码示例:
    public String getType(Uri uri) {        switch(uriMatcher.match(uri)){            case TABLE1_DIR:                return "vnd.android.cursor.dir/vnd.com.example.app.provider.table1";            case TABLE1_ITEM:                return "vnd.android.cursor.item/vnd.com.example.app.provider.table1";            case TABLE2_DIR:                return "vnd.android.cursor.dir/vnd.com.example.app.provider.table2";            case TABLE2_ITEM:                return "vnd.android.cursor.item/vnd.com.example.app.provider.table2";            default:                break;        }        return null;    }

[综合实例]

<实现跨程序的数据共享>

  • 程序对外开放内容

MyProvider.java

public class MyProvider extends ContentProvider {    public static final int BOOK_DIR = 0;    public static final int BOOK_ITEM = 1;    public static final int CATEGORY_DIR = 2;    public static final int CATEGORY_ITEM = 3;    public static final String AUTHORITY = "com.czx.sunorig.myapplication";    private MyDatabaseHelper dbHelper;    private static UriMatcher uriMatcher;    static{        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);        uriMatcher.addURI(AUTHORITY,"book",BOOK_DIR);        uriMatcher.addURI(AUTHORITY,"book/#",BOOK_ITEM);        uriMatcher.addURI(AUTHORITY,"category",CATEGORY_DIR);        uriMatcher.addURI(AUTHORITY,"category/#",CATEGORY_ITEM);    }    //初始化内容提供器的时候调用。完成对数据库的创建和升级操作。返回 true 表示初始化成功,false 表示失败。    //ContentResolver 尝试访问本程序中的数据时,内容提供器才会被初始化    @Override    public boolean onCreate() {        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, 2);        return true;    }    //从内容提供器中查询数据    //1、Uri 确定查询哪一张表    //2、projection 确定查询哪些列    //3、selection 和 selectionArgs 参数约束哪些行    //4、sortOrder 对结果进行排序    //查询结果存放在 Cursor 对象中返回    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        SQLiteDatabase db = dbHelper.getReadableDatabase();        Cursor cursor = null;        switch (uriMatcher.match(uri)){            case BOOK_DIR:                // 查询 book 表中的所有数据                cursor = db.query("book", projection, selection, selectionArgs, null, null, sortOrder);                break;            case BOOK_ITEM:                // 查询 book 表中的单条数据                // getPathSegments() 方法将 URI 权限之后的部分以 “/” 符号进行分隔,并把分割结果放入一个字符串列表中,列表第0个位置是路径,第1个位置是 id                String bookId = uri.getPathSegments().get(1);                cursor = db.query("book", projection, "id = ?", new String[]{ bookId }, null, null, sortOrder);                break;            case CATEGORY_DIR:                // 查询 category 表中的所有数据                cursor = db.query("category", projection, selection, selectionArgs, null, null, sortOrder);                break;            case CATEGORY_ITEM:                // 查询 category 表中的单条数据                String categoryId = uri.getPathSegments().get(1);                cursor = db.query("category", projection, "id = ?", new String[]{ categoryId }, null, null, sortOrder);                break;            default:                break;        }        return cursor;    }    //向内容提供器中添加一条数据    //1、URI 参数来确定添加哪一张表    //2、待添加的数据保存在 values 中    //返回一个用于表示这条新记录的 URI    @Override    public Uri insert(Uri uri, ContentValues values) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        Uri uriReturn = null;        switch (uriMatcher.match(uri)){            case BOOK_DIR:            case BOOK_ITEM:                long newBookId = db.insert("book", null, values); //返回新添记录的行号,与主键id无关                uriReturn = Uri.parse("content://" + AUTHORITY + "/book/" + newBookId);                break;            case CATEGORY_DIR:            case CATEGORY_ITEM:                long newCategoryId = db.insert("Category", null, values);                uriReturn = Uri.parse("content://" + AUTHORITY + "/category/" + newCategoryId);                break;            default:                break;        }        return uriReturn;    }    //1、URI确定更新哪一张表    //2、新数据保存在 values 中    //3、selection,selectionArgs 来约束更新哪些行    //受影响的行将作为返回值    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        int updatedRows = 0;        switch (uriMatcher.match(uri)){            case BOOK_DIR:                updatedRows = db.update("book", values, selection, selectionArgs);                break;            case BOOK_ITEM:                String bookId = uri.getPathSegments().get(1);                updatedRows = db.update("Book", values, "id = ?", new String[]{ bookId });            case CATEGORY_DIR:                updatedRows = db.update("category", values, selection, selectionArgs);                break;            case CATEGORY_ITEM:                String categoryId = uri.getPathSegments().get(1);                updatedRows = db.update("Book", values, "id = ?", new String[]{ categoryId });            default:                break;        }        return updatedRows;    }    //1、URI确定删除哪一张表    //2、selection,selectionArgs 来约束删除哪些行    //被删除的行将作为返回值    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        SQLiteDatabase db = dbHelper.getWritableDatabase();        int deleteRows = 0;        switch (uriMatcher.match(uri)){            case BOOK_DIR:                deleteRows = db.delete("book", selection, selectionArgs);                break;            case BOOK_ITEM:                String bookId = uri.getPathSegments().get(1);                deleteRows = db.delete("book", "id = ?", new String[]{ bookId });                break;            case CATEGORY_DIR:                deleteRows = db.delete("category", selection, selectionArgs);                break;            case CATEGORY_ITEM:                String categoryId = uri.getPathSegments().get(1);                deleteRows = db.delete("category", "id = ?", new String[]{ categoryId });                break;        }        return deleteRows;    }    //根据传入内容的 URI 返回相应的 MIME 类型    @Override    public String getType(Uri uri) {        switch(uriMatcher.match(uri)){            case BOOK_DIR:                return "vnd.android.cursor.dir/vnd." + AUTHORITY + ".book";            case BOOK_ITEM:                return "vnd.android.cursor.item/vnd." + AUTHORITY + ".book";            case CATEGORY_DIR:                return "vnd.android.cursor.dir/vnd." + AUTHORITY + ".category";            case CATEGORY_ITEM:                return "vnd.android.cursor.item/vnd." + AUTHORITY + ".category";            default:                break;        }        return null;    }}

MyDatabaseHelper.java

public class MyDatabaseHelper extends SQLiteOpenHelper {    public static final String CREATE_BOOK = "create table book("            + "id integer primary key autoincrement,"            + "author text,"            + "price real,"            + "pages integer,"            + "name text)";    public static final String CREATE_CATEGORY = "create table category("            + "id integer primary key autoincrement,"            + "book_id integer)";    public MyDatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {        super(context, name, factory, version);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_BOOK);        db.execSQL(CREATE_CATEGORY);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

AndroidManifest.xml

        <provider            android:authorities="com.czx.sunorig.myapplication"            android:name="com.czx.sunorig.myapplication.MyProvider"            android:exported="true">        </provider>
  • 另一个程序访问内容:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {    private Button add_data;    private Button query_data;    private Button update_data;    private Button delete_data;    private String newId;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        add_data = (Button) findViewById(R.id.add_data);        query_data = (Button) findViewById(R.id.query_data);        update_data = (Button) findViewById(R.id.update_data);        delete_data = (Button) findViewById(R.id.delete_data);        add_data.setOnClickListener(this);        query_data.setOnClickListener(this);        update_data.setOnClickListener(this);        delete_data.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch (v.getId()){            case R.id.add_data:                addData();                break;            case R.id.query_data:                queryData();                break;            case R.id.update_data:                updateData();                break;            case R.id.delete_data:                deleteData();                break;            default:                break;        }    }    private void queryData() {        Uri uri = Uri.parse("content://com.czx.sunorig.myapplication/book");        Cursor cursor = getContentResolver().query(uri, null, null, null, null);        if(cursor != null){            while(cursor.moveToNext()){                String name = cursor.getString(cursor.getColumnIndex("name"));                String author = cursor.getString(cursor.getColumnIndex("author"));                int pages = cursor.getInt(cursor.getColumnIndex("pages"));                double price = cursor.getDouble(cursor.getColumnIndex("price"));                Log.d("MainActivity", "book name is " + name);                Log.d("MainActivity", "book author is " + author);                Log.d("MainActivity", "book pages is " + pages);                Log.d("MainActivity", "book price is " + price);            }            cursor.close();        }    }    private void addData() {        Uri uri = Uri.parse("content://com.czx.sunorig.myapplication/book");        ContentValues values = new ContentValues();        values.put("name","A Clash of Kings");        values.put("author", "George Martin");        values.put("pages", 1040);        values.put("price", 22.85);        Uri newUri = getContentResolver().insert(uri, values);        newId = newUri.getPathSegments().get(1);    }    private void updateData() {        Uri uri = Uri.parse("content://com.czx.sunorig.myapplication/book");        ContentValues values = new ContentValues();        values.put("name", "A Storm of Swords");        values.put("pages", 1216);        values.put("price", 24.05);        getContentResolver().update(uri, values, null, null);    }    private void deleteData() {        Uri uri = Uri.parse("content://com.czx.sunorig.myapplication/book" + newId);        getContentResolver().delete(uri, null, null);    }}
0 0
原创粉丝点击