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