Content provider,即是内容提供者或者内容提供商。ContentProvider生命周期
ContentProvider用于不同进程之间传递数据,这也是官方推荐的方式。
简单的说,就是Contentprovider为不同应用之间数据共享提供统一的接口。ContentProvider使用表的形式组织数据,所以提供的方法跟表的操作类似,ContentProvider提供如下的方法:
使用ContentProvider需要一个uri,例如获取手机联系人的uri:
content://com.android.contacts/data/phones
URI解析如下图所示
很多时候我们都是使用系统提供的ContentProvider,使用ContentResolver来读取其他应用的信息,例如读取系统APP,短信,联系人, 手机相册等!例如,我们读取手机联系人
package com.example.contentprovider;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.provider.ContactsContract;
import android.support.v7.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);
getContacts();
}
private void getContacts() {
ContentResolver contentResolver = this.getContentResolver();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
System.out.println("------>>" + uri);
Cursor cursor = contentResolver.query(uri, null, null, null, null);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String number = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println("-----------------------------------");
System.out.println("联系人:" + name);
System.out.println("电话号码:" + number);
}
cursor.close();
}
}
获取手机联系人需要用到系统权限,所以需要在AndroidManifest.xml文件中注册:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
运行效果截图
这样就可以实现简单的读取手机联系人的效果,下面介绍自定义ContentProvider.
自定义ContentProvider的步骤如下:
下面进行代码实现:
创建一个继承ContentProvider的类
package com.example.contentprovider;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.support.annotation.Nullable;
/**
* Created by Devin on 2016/6/17.
*/
public class MYContentProvicer extends ContentProvider {
private static UriMatcher mUriMatcher;
private static final String AUTHORITIES = "com.example.contentprovider";
private static final int PERSON = 1;
private SQLiteDatabaseOpenHelper mOpenHelper;
/**
* 利用静态代码块初始化UriMatcher
* 在UriMatcher中包含了多个Uri,每个Uri代表一种操作
* 当调用UriMatcher.match(Uri uri)方法时就会返回该uri对应的code;
*/
static {
mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
mUriMatcher.addURI(AUTHORITIES, "test", PERSON);
}
/**
* 初始化方法,只执行一次,完成对ContentProvider的初始化
*
* @return
*/
@Override
public boolean onCreate() {
mOpenHelper = new SQLiteDatabaseOpenHelper(this.getContext());
return true;
}
/**
* 查询方法
*
* @param uri
* @param strings
* @param s
* @param strings1
* @param s1
* @return
*/
@Nullable
@Override
public Cursor query(Uri uri, String[] strings, String s, String[] strings1, String s1) {
return null;
}
/**
* 获取ContentProvider的MIME类型
*
* @param uri
* @return
*/
@Nullable
@Override
public String getType(Uri uri) {
return null;
}
/**
* 插入数据方法
*
* @param uri
* @param contentValues
* @return
*/
@Nullable
@Override
public Uri insert(Uri uri, ContentValues contentValues) {
switch (mUriMatcher.match(uri)) {
case PERSON:
SQLiteDatabase mDataBase = mOpenHelper.getReadableDatabase();
long rowId = mDataBase.insert("test", null, contentValues);
if (rowId >= 1) {
//通知数据已经发生改变
getContext().getContentResolver().notifyChange(uri, null);
return ContentUris.withAppendedId(uri, rowId);
}
break;
}
return null;
}
/**
* 删除数据的方法
*
* @param uri
* @param s
* @param strings
* @return
*/
@Override
public int delete(Uri uri, String s, String[] strings) {
return 0;
}
/**
* 更新数据的方法
*
* @param uri
* @param contentValues
* @param s
* @param strings
* @return
*/
@Override
public int update(Uri uri, ContentValues contentValues, String s, String[] strings) {
return 0;
}
}
SQliteDatabaseHelper
package com.example.contentprovider;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
/**
* Created by Devin on 2016/6/17.
*/
public class SQLiteDatabaseOpenHelper extends SQLiteOpenHelper {
private static final String DATABASENAME = "test1";//数据库名称
private static final int DATABASEVERSION = 1;//数据库版本
private String sql = "CREATE TABLE test(id INTEGER PRIMARY KEY AUTOINCREMENT,name varchar(20),phone varchar(50),salary Integer(12))";
public SQLiteDatabaseOpenHelper(Context context) {
super(context, DATABASENAME, null, DATABASEVERSION);
}
@Override
public void onCreate(SQLiteDatabase sqLiteDatabase) {
sqLiteDatabase.execSQL(sql);
}
/**
* 数据库版本版本发生变化时的方法
*
* @param sqLiteDatabase
* @param i
* @param i1
*/
@Override
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
}
}
在AndroidManifest.xml文件中注册
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.contentprovider">
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<provider
android:name=".MYContentProvicer"
android:authorities="com.example.contentprovider"
android:exported="true"></provider>
</application>
</manifest>
新建一个project,在应用中调用getContentResolver()方法获取ContentResolver,然后实现对ContentProvider的操作
package com.example.client;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
Button btn_insert;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn_insert = (Button) findViewById(R.id.btn_insert);
final ContentResolver resolver = this.getContentResolver();
btn_insert.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
ContentValues values = new ContentValues();
values.put("name", "张三");
values.put("phone", "15677822442");
values.put("salary", 8000);
Uri uri = Uri.parse("content://com.example.contentprovider/test");
resolver.insert(uri, values);
Toast.makeText(getApplicationContext(), "恭喜你,数据插入成功", Toast.LENGTH_SHORT).show();
}
});
}
}
最后实现效果如下:
插入数据之后,在File Explorer中将数据表导出,用SQLite Expert Personal 4打开
这样就可以实现一个简单的自定义ContentProvider,将自己应用的数据共享出去,不过这种做法比较少见,因为自己的应用数据很少有向其他应用共享的。
通过注册一个观察者,观察ContentProvider的数据变化
/**
* 自定义一个类,继承ContentObserver,重写onChange方法,观察ContentProvider数据发生变化
*/
private class MYContentObserver extends ContentObserver {
public MYContentObserver(Handler handler) {
super(handler);
}
@Override
public void onChange(boolean selfChange) {
System.out.println("MYContentObserver正在观察ContentProvider数据变化");
long lastTime = 0;
if (System.currentTimeMillis() - lastTime > 2000) {
ContentResolver resolver = getContentResolver();
Uri uri = Uri.parse("content://com.example.contentprovider/test");
lastTime = System.currentTimeMillis();
} else {
System.out.println("时间间隔过短,忽略此次更新");
}
}
@Override
public boolean deliverSelfNotifications() {
return true;
}
}
在onCreate方法中注册观察者
Uri uri = Uri.parse("content://com.example.contentprovider/test");
mContentObserver = new MYContentObserver(new Handler());
getApplicationContext().getContentResolver().registerContentObserver(uri, true, mContentObserver);
在onDestroy方法中取消注册观察者
@Override
protected void onDestroy() {
super.onDestroy();
if (mContentObserver != null) {
getApplicationContext().getContentResolver().unregisterContentObserver(mContentObserver);
}
}
至此,ContentProvider的简单学习就完成了。