zoukankan      html  css  js  c++  java
  • 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.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表的内容是正常的.

    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

  • 相关阅读:
    不使用动态sql语句,正确书写case when中的null处理
    VC项目配置详解(转)
    JAXWS 访问SSL 的WebService 老是HTTP transport error: Connection refused错误的解决办法。
    [转]为什么开发人员工作10多年了还会迷茫?没有安全感?
    Tomcat 6.0.24 不兼容的APR版本问题
    WPF滚动条嵌套,响应鼠标滑轮事件的处理
    SqlServer无备份下误删数据恢复
    今天发现竟然有一个粉丝!!!
    好用的开源轻量级DHCP和DNS服务软件“Dual DHCP DNS Server”
    Windows下源码获取
  • 原文地址:https://www.cnblogs.com/amosli/p/3793850.html
Copyright © 2011-2022 走看看