首页 > 代码库 > Android学习---通过内容提供者(ContentProvider)操作另外一个应用私有数据库的内容

Android学习---通过内容提供者(ContentProvider)操作另外一个应用私有数据库的内容

一.什么是ContentProvider?

ContentProvider直译过来就是内容提供者,主要作用就是A应用提供接口给B应用调用数据,和之前介绍的sharedPreference和直接开放文件访问类似,都是共享应用程序数据,不同的是之前的两种文件格式可能完全不同,如可能为xml,txt,sql等等,这里ContentProvider返回的数据格式是统一的,因此应用的更为广泛一点.

二.实例

这里使用的是A应用通过ContentProvider共享数据给B应用.这里A应用用的是前文中的android_db里的person表.B应用是新建的android_content_provider程序.

1.新创建android_content_provider应用程序

 

 

2.访问android_db共享的数据

创建好了应用程序以后,

/android_content_provider/src/com/example/android_content_provider/ContentProvider.java

package com.example.android_content_provider;import android.app.Activity;import android.content.ContentResolver;import android.database.Cursor;import android.net.Uri;import android.os.Bundle;import android.util.Log;public class ContentProvider extends Activity {    private static String tag = "ContentProvider.class";    /**     * Called when the activity is first created.     */    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main);        //内容解析者        ContentResolver contentResolver = getContentResolver();        Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/persons");        Cursor cursor = contentResolver.query(uri, null, null, null, null);        while(cursor.moveToNext()){            String name = cursor.getString(cursor.getColumnIndex("name"));            int age = cursor.getInt(cursor.getColumnIndex("age"));            System.out.println("name:"+name+" age:"+age);            Log.d(tag,"用户名:"+name+" 年龄:"+age);        }    }}

 

3.android_db开放共享数据接口

1)开放一个uri

/android_db/AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"          package="com.amos.android_db"          android:versionCode="1"          android:versionName="1.0">    <instrumentation android:name="android.test.InstrumentationTestRunner"                     android:targetPackage="com.amos.android_db"></instrumentation>    <uses-sdk android:minSdkVersion="7"/>    <application android:label="@string/app_name">        <uses-library android:name="android.test.runner"/>        <activity android:name="MyActivity"                  android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN"/>                <category android:name="android.intent.category.LAUNCHER"/>            </intent-filter>        </activity>        <!--给内容提供者提供定义一个uri,一般建议使用包名+类名,以供其它程序调用 -->        <provider android:authorities="com.amos.android_db.provider.PersonProvider" android:name=".provider.PersonProvider">        </provider>    </application></manifest> 

 

2).定义路径匹配(继承ContentProvider类)

/android_db/src/com/amos/android_db/provider/PersonProvider.java
package com.amos.android_db.provider;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.util.Log;import com.amos.android_db.MyDBHelper;import com.amos.android_db.dao.Person;import com.amos.android_db.dao.PersonDao;import java.util.List;/** * Created by amosli on 14-6-17. */public class PersonProvider extends ContentProvider {    //创建一个路径识别器    //常量UriMatcher.NO_MATCH表示不匹配任何路径的返回码,也就是说如果找不到匹配的类型,返回-1    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    private static final int ALL_PERSON = 1;    private static final int PERSON = 2;    private static final int OTHER = 3;    private static String tag="PersonProvider.class";    static{        //1.指定一个路径的匹配规则        //如果路径满足content://com.amos.android_db.provider.PersonProvider/persons,返回值就是(ALL_PERSON)=1        uriMatcher.addURI("com.amos.android_db.provider.PersonProvider","persons",ALL_PERSON);        //2.如果路径满足content://com.amos.android_db.provider.PersonProvider/person/3,返回值就是(PERSON)=2        //#号为通配符        uriMatcher.addURI("com.amos.android_db.provider.PersonProvider","person/#",PERSON);        //3.如果路径满足content://com.amos.android_db.provider.PersonProvider/other,返回值就是(OTHER)=3        uriMatcher.addURI("com.amos.android_db.provider.PersonProvider","other",OTHER);    }    /**     * 一般是对象第一次被创建时调用的方法     *     * @return     */    @Override    public boolean onCreate() {        return false;    }    /**     * 让别人去调用返回结果     *     * @param uri     * @param projection    选择的列     * @param selection     查询条件     * @param selectionArgs 查询条件的value     * @param sortOrder     排序     * @return     */    @Override    public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {        int result = uriMatcher.match(uri);        switch(result){            //如果路径满足content://com.amos.android_db.provider.PersonProvider/persons,返回值就是(ALL_PERSON)=1            case ALL_PERSON:                PersonDao dao = new PersonDao(this.getContext());                return dao.findAllByCursor();            //2.如果路径满足content://com.amos.android_db.provider.PersonProvider/person/3,返回值就是(PERSON)=2            case PERSON:                long id = ContentUris.parseId(uri);                SQLiteDatabase database = new MyDBHelper(this.getContext()).getReadableDatabase();                if(database.isOpen()){                    database.execSQL("select * person where personid = "+id);                    return database.query("person", null, "personid", new String[]{id + ""}, null, null, null);                    //不要关闭数据库,否则就没有数据了.                }            case OTHER:                Log.d(tag,"我是其他匹配规则!");                break;            default:                throw new RuntimeException("出错了!!");        }        return null;    }    @Override    public String getType(Uri uri) {        return null;    }    @Override    public Uri insert(Uri uri, ContentValues values) {        return null;    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        return 0;    }    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {        return 0;    }}

4.效果图

首先,将android_db部署到avd上,其次,运行android_content_provider项目,最后,查看log输出.

 

5.出现的问题

1).报空指针错误

.....at dalvik.system.NativeStart.main(Native Method)Caused by: java.lang.NullPointerExceptionat com.example.android_content_provider.ContentProvider.onCreate(ContentProvider.java:21)at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1611).....

这种问题很有可能是路径名称不对,注意提供的接口名称保持一致;并且保证获取数据的接口是正常的,即android_db里获取person表的内容是正常的.

2).intelij中的logcat中看不到log

注意选择Android--->选择要查看Log的进程--->点击上面的双向箭头进行切换日志展示信息.

      

 6.扩展

1),查询,增加,删除,修改的接口全部实现

上面已经实现了查询的接口,这里将实现另外三个接口:

        //4.插入数据,如果路径满足content://com.amos.android_db.provider.PersonProvider/insert,返回值就是(INSERT)=4        uriMatcher.addURI("com.amos.android_db.provider.PersonProvider", "insert", INSERT);        //5.删除数据,如果路径满足content://com.amos.android_db.provider.PersonProvider/delete,返回值就是(DELETE)=5        uriMatcher.addURI("com.amos.android_db.provider.PersonProvider", "delete", DELETE);        //6.更新数据,如果路径满足content://com.amos.android_db.provider.PersonProvider/update,返回值就是(UPDATE)=6        uriMatcher.addURI("com.amos.android_db.provider.PersonProvider", "update", UPDATE);

对应的实现:

 @Override    public Uri insert(Uri uri, ContentValues values) {        //content://com.amos.android_db.provider.PersonProvider/insert        int result = uriMatcher.match(uri);        switch (result) {            case INSERT:                SQLiteDatabase database = myDBHelper.getWritableDatabase();                if (database.isOpen()) {                    database.insert("person", null, values);                }                return uri;            default:                throw new RuntimeException("无法识别该URI,出错了!!");        }    }    @Override    public int delete(Uri uri, String selection, String[] selectionArgs) {        //删除操作        //content://com.amos.android_db.provider.PersonProvider/delete        int result = uriMatcher.match(uri);        switch (result) {            case DELETE:                SQLiteDatabase database = myDBHelper.getWritableDatabase();                return database.delete("person", selection, selectionArgs);            default:                throw new RuntimeException("无法识别该URI,出错了!!");        }    }    @Override    public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {       //更新操作        //content://com.amos.android_db.provider.PersonProvider/update        int result = uriMatcher.match(uri);        switch (result) {            case UPDATE:                SQLiteDatabase database = myDBHelper.getWritableDatabase();                return database.update("person", values, selection, selectionArgs);            default:                throw new RuntimeException("无法识别该URI,出错了!!");        }    }

//返回值的类型

   @Override    public String getType(Uri uri) {        int result = uriMatcher.match(uri);        switch (result){            case ALL_PERSON:                return "List<Person>";            case PERSON:                return "Person";            default:return null;        }    }

 

2)测试 

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><manifest xmlns:android="http://schemas.android.com/apk/res/android"          package="com.example.ContentProviderTest"          android:versionCode="1"          android:versionName="1.0">    <uses-sdk android:minSdkVersion="7"/>    <instrumentation android:name="android.test.InstrumentationTestRunner" android:targetPackage="com.example.ContentProviderTest"/>    <application android:label="@string/app_name">        <uses-library android:name="android.test.runner"/>        <activity android:name="MyActivity"                  android:label="@string/app_name">            <intent-filter>                <action android:name="android.intent.action.MAIN"/>                <category android:name="android.intent.category.LAUNCHER"/>            </intent-filter>        </activity>    </application></manifest> 

加入加粗的两行,配置好测试的环境.

 

/ContentProviderTest/src/com/example/ContentProviderTest/test/TestCase.java

package com.example.ContentProviderTest.test;import android.content.ContentResolver;import android.content.ContentValues;import android.net.Uri;import android.test.AndroidTestCase;/** * Created by amosli on 14-6-19. */public class TestCase extends AndroidTestCase {    public void testInsert(){            ContentResolver contentResolver = getContext().getContentResolver();            Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/insert");            ContentValues values = new ContentValues();            values.put("name", "bill");            values.put("age", 18);            contentResolver.insert(uri, values);    }    public void testDelete(){        ContentResolver contentResolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/delete");        contentResolver.delete(uri,"name=?",new String[]{"amos96"});    }    public void testUpdate(){        ContentResolver contentResolver = getContext().getContentResolver();        Uri uri = Uri.parse("content://com.amos.android_db.provider.PersonProvider/update");        ContentValues contentValues = new ContentValues();        contentValues.put("name","jack");        contentValues.put("age",30);        contentResolver.update(uri,contentValues,"name=?",new String[]{"amos97"});    }}

3)效果图:

插入数据(insert方法),bill

删除数据(delete方法),amos96 

更新数据(update方法 ),amos97

 

 

本文源码:

https://github.com/amosli/android_basic/tree/android_db

https://github.com/amosli/android_basic/tree/content_provoider

https://github.com/amosli/android_basic/tree/android_contentProviderTest