Android學習---經過內容提供者(ContentProvider)操做另一個應用私有數據庫的內容

一.什麼是ContentProvider?

ContentProvider直譯過來就是內容提供者,主要做用就是A應用提供接口給B應用調用數據,和以前介紹的sharedPreference和直接開放文件訪問相似,都是共享應用程序數據,不一樣的是以前的兩種文件格式可能徹底不一樣,如可能爲xml,txt,sql等等,這裏ContentProvider返回的數據格式是統一的,所以應用的更爲普遍一點.java

二.實例

這裏使用的是A應用經過ContentProvider共享數據給B應用.這裏A應用用的是前文中的android_db裏的person表.B應用是新建的android_content_provider程序.android

1.新建立android_content_provider應用程序

 

 

2.訪問android_db共享的數據

建立好了應用程序之後,git

/android_content_provider/src/com/example/android_content_provider/ContentProvider.javagithub

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開放共享數據接口sql

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輸出.app

 

5.出現的問題

1).報空指針錯誤

.....

at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.NullPointerException
at 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表的內容是正常的.ide

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

注意選擇Android--->選擇要查看Log的進程--->點擊上面的雙向箭頭進行切換日誌展現信息.測試

      

 6.擴展

1),查詢,增長,刪除,修改的接口所有實現

上面已經實現了查詢的接口,這裏將實現另外三個接口:this

        //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

相關文章
相關標籤/搜索