ContentProvider是Android的四大组件之一,主要用于跨进程通信

ContentProvider的作用

  1. 使用现有的内容提供者来读取和操作相应程序中的数据
  2. 创建自己的内容提供者给自己程序的数据提供外部访问接口。

统一资源标识符(URI)

就像访问网站需要域名一样,Android中用内容URI给内容提供者中的数据建立了唯一标识符。它主要由三部分组成:协议声明、authority和path。

Android中规定URI以“content:”开头,代表协议声明。
authority表示授权信息,用于对不同应用程序进行区分,为了避免冲突,一般都采用程序包名的方式来命名。
path表示表名,用于对同一应用程序中不同的表进行区分,通常会添加到authority后面。
authorities是内容提供者的地址,通过这个地址可以访问内容提供者,精确的知道访问的是哪一个内容提供者
exported:可以导出数据,获取到数据

Uri后面添加参数来进一步限定访问哪一个数据表,比如下面的Uri是com.ldw.po限定访问的是po表

Uri.parse("content://com.ldw.po/po")

AndroidManifist.xml

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

    <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=".MyProvider"
            android:authorities="com.ldw.mypo"
            android:enabled="true"
            android:exported="true"></provider>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

使用现有的ContentProvider比如读取所有的短信

List<Message> smsList;
public void click1(View v){
        //访问内容提供者
        ContentResolver cr = getContentResolver();
        //根据源代码,查询所有的信息不需要匹配参数,里面还有其他的参数,例如inbox,sent,draft等等
        //短信内容提供者的主机名Uri:sms
        Cursor cursor = cr.query(Uri.parse("content://sms"), new String[]{"address", "date", "body", "type"}, null, null, null);
        while(cursor.moveToNext()){
            String address = cursor.getString(0);
            long date = cursor.getLong(1);
            String body = cursor.getString(2);
            String type = cursor.getString(3);

            Message sms = new Message(address, date, body, type);
            smsList.add(sms);
            System.out.println(address + ";" + date + ";" + body + ";" + type);
        }
    }

ContentResolver类

首先说一个问题,为什么要使用通过ContentResolver类从而与ContentProvider类进行交互,而不直接访问ContentProvider类呢?

一个APP可能会有多个ContentProvider,若需要了解每个ContentProvider的不同实现从而再完成数据交互,
那整个操作过程也太复杂了,耦合高不利于扩展。因此Android单独设计了一个 ContentResolver类对所有的
ContentProvider进行统一管理。

ContentResolver类里常用的就四大方法:增、删、改、查,emmm有种数据库的感觉。其实确实和数据库操作很像。

自定义ContentProvider

1.手动创建数据库MyOpenHelper.java

package com.ldw.a19contpro;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

/**
 * author: ldw
 * created on: 2019/12/28 20:08
 * description:
 */
public class MyOpenHelper extends SQLiteOpenHelper {

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

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table so(_id integer primary key autoincrement, name char(10), money integer(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

2.自定义 ContentProvider 类

这一步主要是通过继承ContentProvider类,来实现自己的ContentProvider的逻辑。
在Android Studio中,可以直接用右键New->Other->Content Provider的方式来创建自定义ContentProvider。

android content 接收 android content协议_android

App1:

Manifist.xml

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

    <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=".MyProvider"
            android:authorities="com.ldw.mypo"
            android:enabled="true"
            android:exported="true"></provider>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

MyOpenHelper.java

package com.ldw.a19contpro;

import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

import androidx.annotation.Nullable;

/**
 * author: ldw
 * created on: 2019/12/28 20:08
 * description:
 */
public class MyOpenHelper extends SQLiteOpenHelper {

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

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {
        sqLiteDatabase.execSQL("create table so(_id integer primary key autoincrement, name char(10), money integer(20))");
    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}

MyProvider.java内容提供者

package com.ldw.a19contpro;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;

public class MyProvider extends ContentProvider {
    private MyOpenHelper my;
    SQLiteDatabase db;
    public MyProvider() {
    }

    @Override
    public int delete(Uri uri, String selection, String[] selectionArgs) {
        // Implement this to handle requests to delete one or more rows.
        int i = db.delete("so", selection, selectionArgs);
        return i;
    }

    @Override
    public String getType(Uri uri) {
        // TODO: Implement this to handle requests for the MIME type of the data
        // at the given URI.
        return null;
    }

    @Override
    public Uri insert(Uri uri, ContentValues values) {
        // TODO: Implement this to handle requests to insert a new row.
        db.insert("so", null, values);
        return uri;
    }

    @Override
    public boolean onCreate() {
        // TODO: Implement this to initialize your content provider on startup.
        my = new MyOpenHelper(getContext(), "so.db", null, 1);
        db = my.getWritableDatabase();
        return false;
    }

    @Override
    public Cursor query(Uri uri, String[] projection, String selection,
                        String[] selectionArgs, String sortOrder) {
        // TODO: Implement this to handle query requests from clients.
        Cursor cursor = db.query("so", projection, selection, selectionArgs, null, null, sortOrder, null);
        return cursor;
    }

    @Override
    public int update(Uri uri, ContentValues values, String selection,
                      String[] selectionArgs) {
        // TODO: Implement this to handle requests to update one or more rows.
        int i = db.update("so", values, selection, selectionArgs);
        return i;
    }
}

MainActivity.java创建数据库

package com.ldw.a19contpro;

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        MyOpenHelper myOpenHelper = new MyOpenHelper(this, "so.db", null, 1);
        myOpenHelper.getWritableDatabase();
    }
}

App2

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical"
    >

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="插入"
        android:onClick="insert"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="删除"
        android:onClick="delete"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="修改"
        android:onClick="update"
        />
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="查询"
        android:onClick="query"
        />
</LinearLayout>

MainActivity.java

package com.ldw.a17contentvisitor;

import androidx.appcompat.app.AppCompatActivity;

import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends AppCompatActivity {

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

    public void insert(View v){
        ContentResolver cr = getContentResolver();
        ContentValues contentValues = new ContentValues();
        contentValues.put("name", "AAA");
        contentValues.put("money", "25000");
        cr.insert(Uri.parse("content://com.ldw.mypo"), contentValues);
        contentValues.put("name", "BBB");
        contentValues.put("money", "15000");
        //Uri前面必须带前缀,是内容提供者的地址
        cr.insert(Uri.parse("content://com.ldw.mypo"), contentValues);
        contentValues.put("name", "CCC");
        contentValues.put("money", "15000");
        //Uri前面必须带前缀,是内容提供者的地址
        cr.insert(Uri.parse("content://com.ldw.mypo"), contentValues);
        contentValues.put("name", "DDD");
        contentValues.put("money", "15000");
        //Uri前面必须带前缀,是内容提供者的地址
        cr.insert(Uri.parse("content://com.ldw.mypo"), contentValues);
    }

    public void delete(View v){
        ContentResolver contentResolver = getContentResolver();
        int i = contentResolver.delete(Uri.parse("content://com.ldw.mypo"), "name = ?", new String[]{"AAA"});
        System.out.println("删除的行是===" + i);
    }

    public void update(View v){
        ContentResolver contentResolver = getContentResolver();
        ContentValues contentValues = new ContentValues();
        contentValues.put("money", "25000");
        int i = contentResolver.update(Uri.parse("content://com.ldw.mypo"), contentValues,"name = ?", new String[]{"CCC"});
        System.out.println("编辑的行是===" + i);
    }

    public void query(View v){
        ContentResolver contentResolver = getContentResolver();
        Cursor cursor = contentResolver.query(Uri.parse("content://com.ldw.mypo"), null, null, null, null);
        while (cursor.moveToNext()) {
            String name = cursor.getString(1);
            String money = cursor.getString(2);
            System.out.println("name===" + name + "; money===" + money);
        }
    }
}