Android basis of ContentProvider

ContentProvider is one of the four components of the Android, primarily for inter-process communication. Today we'll talk about the content of ContentProvider.
Points are as follows:

  • Outline
  • Uniform resource identifier (URI)
  • Using existing ContentProvider
  • Custom ContentProvider
  • to sum up

Outline

Android ContentProvider one of the four components, the main function for data sharing among different applications, it provides a complete set of mechanism that allows an application to access data in another application, but also We can guarantee the security of the data being accessed. Android is currently the standard way to achieve data sharing across applications.
ContentProvider is the underlying implementation of Binder mechanism in Android.

ContentProvider usage can be divided into two forms:

  1. Using existing content providers to read and manipulate data in the corresponding program
  2. Create your own content provider to the data of its own program to provide external access interface.

Uniform resource identifier (URI)

Just need to visit the Web site domain name, like, Android content using data provided by URI in the establishment of a unique identifier to the content. It consists of three parts: the statement of the agreement, authority and path.

Android specified URI with "content:" at the beginning , the agreement on behalf of the statement.
It represents authority authorization information for distinguish between different applications , in order to avoid conflicts, the package is generally by way of the name to name.
path represents the name of the table, for the same application to distinguish different tables , usually appended to authority.

Content URI standard format written as follows:
content://com.example.app.provider/table1

In addition, URI pattern there is a match wildcards * and #. Specific use are as follows:

// *:匹配任意长度的任何有效字符的字符串
// 以下的URI 表示匹配provider的任何内容
content://com.example.app.provider/* 
// #:匹配任意长度的数字字符的字符串
// 以下的URI 表示匹配provider中的table表的所有行
content://com.example.app.provider/table/# 

Using existing ContentProvider

To get the address book as an example:

private void readcontract(){
        Cursor cursor = null;
        try {
            //获取通讯录信息
            cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                    null, null, null, null);
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    //联系人姓名
                    String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
                    //联系人电话
                    String phonenumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    contactList.add(name + "\n" + phonenumber);
                }
                adapter.notifyDataSetChanged();
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            if(cursor != null){
                cursor.close();
            }
        }
    }

In fact, the key point is to use ContentResolver the query () method to query the contact data of the system, after traversing enough information out. (Finally, remember to turn off the cursor prevent memory leaks)
So, in fact, using existing ContentProvider mainly work ContentResolver class.

ContentResolver类

First, let me a question, why use so as to interact with ContentProvider ContentResolver class by class, rather than direct access ContentProvider like it?

The reason is very simple, in general, there may be a more ContentProvider APP, if the need to understand the different implementations of each ContentProvider so then complete data exchange, and that the whole operation is too complicated, high coupling is not conducive to expansion. Therefore designed a single Android ContentResolver class unified management of all ContentProvider.

ContentResolver class common to the four methods: add, delete, change, search, emmm kind of database feeling. In fact, really like and database operations.

// 向ContentProvider 中添加数据
//
public Uri insert(Uri uri, ContentValues values)  

//删除 ContentProvider 中的数据
public int delete(Uri uri, String selection, String[] selectionArgs)

// 更新 ContentProvider 中的数据
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)  

// 查找 ContentProvider 中的数据
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

Custom ContentProvider

1. Create a database helper class

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)";

    private Context mContext;

    public MyDatabaseHelper(@Nullable Context context, @Nullable String name, @Nullable SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
        this.mContext = context;
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(CREATE_BOOK);
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        db.execSQL("drop table if exists Book");
    }
}

This step is nothing to talk about, it is to create a class for the operation of the database, the more basic operations.

2. Custom class ContentProvider

This step is mainly through inheritance ContentProvider class to implement their own logic of ContentProvider.
In Android Studio, you can directly create custom ContentProvider Right New-> Other-> Content Provider way.


17755742-a74659d7f14b169e.png

Specific ContentProvider following categories:

public class MyProvider extends ContentProvider {

    public static final int BOOK_DIR = 0;

    public static final int BOOK_ITEM = 1;

    public static final String AUTHORITY = "com.bupt.testlogin.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);
    }

    public MyProvider() {
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
       return 0;
    }

    @Override
    public String getType(Uri uri) {
       switch (uriMatcher.match(uri)){
           case BOOK_DIR:
               return "vnd.android.cursor.dir/vnd.com.bupt.testlogin.provider.book";
           case BOOK_ITEM:
               return "vnd.android.cursor.item/vnd.com.bupt.testlogin.provider.book";
       }
       return  null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        return null;
    }

    @Override
    public boolean onCreate() {
        dbHelper = new MyDatabaseHelper(getContext(),"BookStore.db",null,4);
        return true;
    }

    @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 boodId = uri.getPathSegments().get(1);
                cursor = db.query("Book",projection,"id = ?",new String[]{boodId},null,null,sortOrder);
                break;
            default:
                break;
        }
        return cursor;
    }

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

这里我首先定义了两个整型常量BOOK_DIR和BOOK_ITEM,表示访问Book表中的所有数据和单条数据。在静态代码块中,创建了UriMatcher实例,并调用addURI方法,将期望匹配的URI格式传递进去(可以用通配符)。UriMatcher的主要作用就是用match方法匹配内容URI,然后返回期望的操作类型。
这里只实现了query()方法用于查询,其他的增、删、改的操作都是差不多的,就不在这里重复了。
先说getType方法,这个方法是所有ContentProvider都必须实现的,根据传入的内容URI来返回相应的MIME类型。用于解析传入的Uri参数,分析出调用方的期望的表和数据。
内容URI所对应的MIME字符串主要由三部分组分,Android对这三个部分做了如下格式规定:

  1. 必须以vnd开头;
  2. 如果内容URI以路径结尾,则后接android.cursor.dir/,如果内容URI以id结尾,则后接android.cursor.item/;
  3. 最后接上vnd.< authority>.< path>。
    这部分不怎么复杂,只要按照格式写就行。

3.注册ContentProvider类

如果是自己新建创建的ContentProvider类,还需要在AndroidManifest.xml文件中添加注册信息。当然了,如果用Android Studio创建,那么系统会自动添加好注册信息

<provider
            android:name=".provider.MyProvider"
            android:authorities="com.bupt.testlogin.provider"
            android:enabled="true"
            android:exported="true" />

至此一个自定义的ContentProvider就实现完成了。

总结

ContentProvider为应用间的数据交互提供了一个安全的环境:允许把自己的应用数据根据需求开放给其他应用 进行 增、删、改、查,而不用担心因为直接开放数据库权限而带来的安全问题。显然,我们不写在UriMatcher中的表,外部是无法访问到的,所有访问均在可控范围内,自然敏感信息就不会外泄。

In addition, other ways of foreign share data, due to different ways of storing data resulting from the different data access methods:
the use of shared files shared way of external data, you need to read and write data files; Sharedpreferences using shared data, you need to use sharedpreferences API read and write data. This obviously reduces the efficiency of development.
The ContentProvider the decoupling of the underlying data storage, so that no matter which way the underlying data storage uses, outside of the data access methods are unified, improve development efficiency.

Thus, the basic usage and knowledge of the four components of Android would have finished summarized.

Guess you like

Origin blog.csdn.net/weixin_34111790/article/details/90772389