25. Android开发笔记:内容提供器(二) 创建自己的内容提供器

1.创建自己的内容提供器

1.1 基础知识

如果想要实现跨程序共享数据的功能,官方推荐的方式就是使用内容提供器,可以通过新建一个类去继承ContentProvider的方式来创建一个自己的内容提供器。ContentProvider类中有6个抽象方法,我们在使用子类继承它的时候,需要将这6个方法全部重写。

1.1.1 内容URL

回顾一下,一个标准的内容URI写法是这样的:
content://com.example.app.provider/table1
这就表示调用方期望访问的是com.example.app这个应用的table1表中的数据。
除此之外,我们还可以在这个内容URI的后面加上一个id,如下所示: content://com.example.app.provider/table1/1 这就表示调用方期望访问的是com.example.app这个应用的table1表中id为1的数据。

内容URI的格式主要就只有以上两种,以路径结尾就表示期望访问该表中所有的数据,以id结尾就表示期望访问该表中拥有相应id的数据。我们可以使用通配符的方式来分别匹配这两种格式的内容URI,规则如下。
*:表示匹配任意长度的任意字符。

:表示匹配任意长度的数字。

所以,一个能够匹配任意表的内容URI格式就可以写成:

content://com.example.app.provider/*

而一个能够匹配table1表中任意一行数据的内容URI格式就可以写成:

content://com.example.app.provider/#

1.1.2 UriMatcher

接着,我们再借助UriMatcher这个类就可以轻松地实现匹配内容URI的功能。
当调用UriMatcher的match()方法时,就可以将一个Uri对象传入,返回值是某个能够匹配这个Uri对象所对应的自定义代码,利用这个代码,我们就可以判断出调用方期望访问的是哪张表中的数据了。

郭霖. 第一行代码 Android 第2版 (图灵原创) (Kindle位置4747). 人民邮电出版社. Kindle 版本.

1.1.3 getType()方法

其中方法 getType(): 根据传入的内容URI来返回相应的MIME类型。
它是所有的内容提供器都必须提供的一个方法,用于获取Uri对象所对应的MIME类型。
一个内容URI所对应的MIME字符串主要由3部分组成,Android对这3个部分做了如下格式规定。
必须以 vnd 开头, 如果内容URI以路径结尾,则后接
android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/ 。
最后接上 vnd.. 。 所以,

  • 对于content://com.example.app.provider/table1这个内容URI,它所对应的MIME类型就可以写成:
vnd.android.cursor.dir/vnd.com.example.app.provider.table1 
  • 对于content://com.example.app.provider/table1/1这个内容URI,它所对应的MIME类型就可以写成:
 vnd.android.cursor.item/vnd.com.example.app.provider.table1

2. 示例

2.1 创建内容提供器类

打开之前的工程【DatabaseDemo】,右键包名->New ->Other->Content Provider:
l类名:DatabaseContentProviderauthority 指定为 com.example.databasedemo.provider

  • Exported属性表示是否允许外部程序访问我们的内容提供器,
  • Enabled属性表示是否启用这个内容提供器。将两个属性都勾中,点击Finish完成创建。

修改类DatabaseContentProvider: 实现继承ContentProvider的6个方法

public class DatabaseContentProvider extends ContentProvider {

    public static final int Book_Dir = 0;
    public static final int Book_Item = 1;
    public static final int Gategory_Dir = 2;
    public static final int Gategory_Item = 3;

    public static final String Authority = "com.example.databasedemo.provider";
    private static UriMatcher uriMatcher;

    private MyDatabaseHelper dbHelper;

    static {
        uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        uriMatcher.addURI(Authority, "book", Book_Dir);
        uriMatcher.addURI(Authority, "book/#", Book_Item);
        uriMatcher.addURI(Authority, "gategory", Gategory_Dir);
        uriMatcher.addURI(Authority, "gategory/#", Gategory_Item);
    }

    public DatabaseContentProvider() {
    }

    @Override
    public boolean onCreate() {
        //获取 SQLiteOpenHelper 实例,以便操作数据库
        dbHelper = new MyDatabaseHelper(getContext(), "BookStore.db", null, MainActivity.DataBaseVersion);
        return true;
    }

    @Override
    public String getType(Uri uri) {
        //Implement this to handle requests for the MIME type of the data
        // at the given URI.
        switch (uriMatcher.match(uri)) {
            case Book_Dir:
                return "vnd.android.cursor.dir/vnd.com.example.app.provider.book";
            case Book_Item:
                return "vnd.android.cursor.item/vnd.com.example.app.provider.book";
            case Gategory_Dir:
                return "vnd.android.cursor.dir/vnd.com.example.app.provider.gategory";
            case Gategory_Item:
                return "vnd.android.cursor.item/vnd.com.example.app.provider.gategory";
        }
        return null;
    }

    /**
     * 查询
     */
    @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:
                cursor = db.query("Book", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case Book_Item:
                String bookId = uri.getPathSegments().get(1); //获取Id
                cursor = db.query("Book", projection, "id=?", new String[]{ bookId}, null, null, sortOrder);
                break;
            case Gategory_Dir:
                cursor = db.query("category", projection, selection, selectionArgs, null, null, sortOrder);
                break;
            case Gategory_Item:
                String categoryId = uri.getPathSegments().get(1); //获取Id
                cursor = db.query("category", projection, "id=?", new String[]{ categoryId}, null, null, sortOrder);
                break;
        }

        return cursor;
    }


    @Override
    public Uri insert(Uri uri, ContentValues values) {
        SQLiteDatabase db = dbHelper.getWritableDatabase();
        Uri retunUrl = null;

        switch (uriMatcher.match(uri)) {
            case Book_Dir:
            case Book_Item:
                long newbookId = db.insert("Book", null, values);
                retunUrl = Uri.parse("content://" + Authority + "/book/" + newbookId);
                break;

            case Gategory_Dir:
            case Gategory_Item:
                long newGategoryId = db.insert("Book", null, values);
                retunUrl = Uri.parse("content://" + Authority + "/gategory/" + newGategoryId);
                break;
        }

        return  retunUrl;
    }


    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {

        SQLiteDatabase db = dbHelper.getWritableDatabase();
        int updateRows = 0; //影响的行数

        switch (uriMatcher.match(uri)) {
            case Book_Dir:
                updateRows = db.update("book", values, selection, selectionArgs);
                break;
            case Book_Item:
                String bookId =  uri.getPathSegments().get(1);
                updateRows = db.update("book", values, "id=?", new String[]{ bookId});
                break;
            case Gategory_Dir:
                updateRows = db.update("gategory", values, selection, selectionArgs);
                break;
            case Gategory_Item:
                String gategoryId =  uri.getPathSegments().get(1);
                updateRows = db.update("gategory", values, "id=?", new String[]{ gategoryId});
                break;
        }
        return  updateRows;
    }

    @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 Gategory_Dir:
                deleteRows = db.delete("gategory", selection, selectionArgs);
                break;
            case Gategory_Item:
                String gategoryId =  uri.getPathSegments().get(1);
                deleteRows = db.delete("gategory", "id=?", new String[]{ gategoryId});
                break;
        }
        return  deleteRows;
    }

}

2.2 注册内容提供器

Android Studio 自动在AndroidManifest.xml自动添加:provider标签,对内容提供器进行了注册

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.databasedemo">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        
        <provider
            android:name=".DatabaseContentProvider"
            android:authorities="com.example.databasedemo.provider"
            android:enabled="true"
            android:exported="true"></provider>
        
        ......
        

2.3 外部程序使用该内容提供器

新建一个项目【UsingOutsideContentProvider】

在创建4个按钮,分别用于增、删、改、查

  • activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button android:id="@+id/btn_insert"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="添加数据"/>

    <Button android:id="@+id/btn_query"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="查询数据"/>

    <Button android:id="@+id/btn_update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="更新数据"/>

    <Button android:id="@+id/btn_delete"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:textAllCaps="false"
        android:text="删除数据"/>

</LinearLayout>
  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    private String newBookId;

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

        //添加数据
        Button btn_insert = findViewById(R.id.btn_insert);
        btn_insert.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ContentResolver contentResolver = getContentResolver();
                Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");

                ContentValues values = new ContentValues();
                values.put("name", "waibuchengxu");
                values.put("author", "lao wai");
                values.put("pages", 30);
                values.put("price", 6.40);

                Uri newUri = contentResolver.insert(uri, values);
                newBookId = newUri.getPathSegments().get(1);
                Log.d("contentProvider-data", "newBookId: " + newBookId);

                values.clear();
                values.put("name", "waibuchengxu-2");
                values.put("author", "lao wai");
                values.put("pages", 30);
                values.put("price", 6.40);

                Uri newUri2 = contentResolver.insert(uri, values);
                String newId2 = newUri2.getPathSegments().get(1);
                Log.d("contentProvider-data", "newId2: " + newId2);
            }
        });

        //查询数据
        Button btn_query = findViewById(R.id.btn_query);
        btn_query.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {

                ContentResolver contentResolver = getContentResolver();
                Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
                //Cursor cursor = contentResolver.query(uri, new String[]{ "name", "price","author"}, "author=?", new String[]{"lao wai"},null);
                Cursor cursor = contentResolver.query(uri, new String[]{ "id, name", "price", "author"}, null, null,null);

                int index=0;
                if ( cursor != null){
                    while (cursor.moveToNext()) {
                        String id = cursor.getString(cursor.getColumnIndex("id"));
                        String name = cursor.getString(cursor.getColumnIndex("name"));
                        String price = cursor.getString(cursor.getColumnIndex("price"));
                        String author = cursor.getString(cursor.getColumnIndex("author"));

                        String msg = (++index)+". id:" + id +" | name:" + name + " | author:" + author+ " | price:" + price;

                        Toast.makeText(MainActivity.this, msg, Toast.LENGTH_SHORT).show();
                        Log.d("contentProvider-data", msg);
                    }
                }

                cursor.close(); //记得关闭指针
            }
        });

        //更新数据
        Button btn_update = findViewById(R.id.btn_update);
        btn_update.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ContentResolver contentResolver = getContentResolver();
                Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");

                ContentValues values = new ContentValues();
                values.put("price", 100);  //只更新标明的字段,其它字段值不会被修改
                int updateRows = contentResolver.update(uri, values, "author=?", new String[]{"lao wai"});

                Log.d("contentProvider-data", "影响行数:"+updateRows );
            }
        });

        //删除数据
        Button btn_delete = findViewById(R.id.btn_delete);
        btn_delete.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ContentResolver contentResolver = getContentResolver();
                Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
                int deleteRows = contentResolver.delete(uri, "name=?", new String[]{"waibuchengxu-2"});
                Log.d("contentProvider-data", "book/  影响行数:"+ deleteRows );

                Log.d("contentProvider-data", "newBookId: " + newBookId);
                Uri uriItem = Uri.parse("content://com.example.databasedemo.provider/book/" + newBookId);
                int deleteItemRows = contentResolver.delete(uriItem, null, null);

                Log.d("contentProvider-data", "book/id:影响行数:"+ deleteItemRows );
            }
        });

    }
}

2.3.1使用要点

  • 获取ContentResolverContentResolver contentResolver = getContentResolver();

  • 创建Uri:

    • 面向全表:Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/");
    • 面向某行:Uri uri = Uri.parse("content://com.example.databasedemo.provider/book/id");
  • 增:Uri newUri = contentResolver.insert(uri,...);

  • 删:int rows =contentResolver.delete(uri,...);

  • 改:int rows = contentResolver.update(uri,...);

  • 查: Cursor cursor = contentResolver.query(uri,...);

原文地址:https://www.cnblogs.com/easy5weikai/p/12592606.html