Android学习笔记七之ContentProvider

Android学习笔记起之ContentProvider

ContentProvicer简介

Content provider,即是内容提供者或者内容提供商。ContentProvider生命周期

  1. 应用安装完成,就会创建完成,手机开机后,第一次被访问时,被创建
  2. 只要创建了,只要手机没关机,就会一直存在,类似于在注册表里注册一样
  3. 手机关机,才会消失
  4. 应用里的数据都可以提供访问.不一定是数据库,在方法里自已定义就可以,但通常是访问数据库

作用

  ContentProvider用于不同进程之间传递数据,这也是官方推荐的方式。

  • 当我们想要在自己的应用中访问别的应用的数据,比如获取手机联系人,手机短信等的时候,就需要用到ContentProvider了
  • 当我们自己的应用,需要把自己的一些数据给其它应用进行操作,我们就可以用到contentprovider了。

简单的说,就是Contentprovider为不同应用之间数据共享提供统一的接口。ContentProvider使用表的形式组织数据,所以提供的方法跟表的操作类似,ContentProvider提供如下的方法:

  • query:查询数据
  • insert:插入数据
  • update:更新数据
  • delete:删除数据
  • getType:得到数据类型
  • onCreate:创建数据时调用的回调函数

使用ContentProvider需要一个uri,例如获取手机联系人的uri:
content://com.android.contacts/data/phones

URI解析如下图所示

使用系统提供的ContentProvider

很多时候我们都是使用系统提供的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的步骤如下:

  • 在想要进行数据分享的APP中,创建一个继承ContentProvider的类
  • 实现对应的方法,按照需要进行重写,方法有onCreate()只执行一次,初始化ContentProvider,insert(),delete(),update(),query(),getType()获取ContentProvider数据的MIME类型
  • 在AndroidManifest.xml文件中注册自定义的ContentProvider,至少需要三个属性,name,用于指定ContentProvider的全限定类名;authorities,用于匹配ContentProvider的uri;exported,用于指定是否共享数据,true,共享,false,不共享。
  • 使用UriMatcher,完成uri的匹配
  • 在另外的应用中调用getContentProvider()方法获取到Resolver对象,再进行对应的操作

下面进行代码实现:

创建一个继承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打开

Android学习笔记七之ContentProvider_第1张图片

这样就可以实现一个简单的自定义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的简单学习就完成了。

你可能感兴趣的:(android,手机,应用)