ContentProvider是Android的四大组件之一,主要用于跨进程通信
ContentProvider的作用
- 使用现有的内容提供者来读取和操作相应程序中的数据
- 创建自己的内容提供者给自己程序的数据提供外部访问接口。
统一资源标识符(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。
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);
}
}
}