Android 自定义 ContentProvider

前几章节我们用的都是 Android 系统提供的 ContentProvider ,其实,我们还可以自定义 ContentProvider

一般情况下,很少需要自己来定义 ContentProvider ,因为很多时候我们并不希望自己应用的数据暴露给其它应用

但即使这样,学习如何 ContentProvider 还是有必要的,多一种数据传输的方式

自定义 ContentProvider

自定义 ContentProvider 的流程一般如下

  1. 在分享数据的 APP 中创建一个类,继承 ContentProvider

  2. 按需实现对应的方法,不需要的直接空实现

    方法 说明
    onCreate() 只执行一次,用于初始化 Provider
    insert() 插入
    delete() 删除
    update() 更新
    query() 查询
    getType() 获得 ContentProvider 数据的 MIME 类型
  3. AndroidManifest.xml 中注册自定义的 ContentProvider

    <provider
        <!-- 全限定类名 -->
        android:name = "cn.twle.android.bean.NameContentProvider" 
        <!-- 用于匹配的 URI -->
        android:authorities = "cn.twle.android.providers.msprovider"
        <!-- 是否共享数据 -->
        android:exported="true">
    </provider>
    
  4. 使用 UriMatcher 完成 Uri 的匹配

    1. 初始化 UriMatcher 对象

      private static UriMatcher matcher = new UriMatcher (UriMatcher.NO_MATCH);
      
    2. 使用静态代码块,通过 addURI() 方法将 uri 添加到 matcher

      static {
          matcher.addURI("cn.twle.android.providers.msprovider","test","1");
      }
      

      前两个参数构成 URI, 第三个参数:匹配后返回的标识码,如果不匹配返回 -1

    3. 在下面需要匹配 Uri 的地方使用 match() 方法

      switch( matcher.match(uri)) {
          case 1:
              break;
          case 2:
              break;
          default:
              break;
      }
      

      当然还可以使用通配符,比如 test/*test/# * 代表所有字符, # 代表数字

  5. 使用 ContentUris 类为 Uri 追加 id, 或者解析 Uri 中的 id

    1. withAppendedId(uri,id) 为路径添加 id 部分

      Uri nameUri = ContentUris.withAppendedId(uri,rowId);
      
    2. parseId(uri) 解析 uri 中的 id

      long nameId = ContentUris.parseId(uri);
      
  6. 然后在另一个工程中,调用 getContentResolver() 方法获得 Resolver 对象,再调用相应的操作方法,比如插入操作

    ContentValues values = new ContentValues();
    values.put("name","测试");
    
    Uri uri = Uri.parse("cn.twle.android.providers.msprovider/test");
    
    resolver.insert(uri,values);
    

范例


  1. 创建一个 空的 Android 项目 cn.twle.android.CustomProvider

  2. MainActivity.java 同一目录下添加一个数据库创建类 DBOpenHelper.java

    package cn.twle.android.customprovider;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    public class DBOpenHelper extends SQLiteOpenHelper {
    
        final String CREATE_SQL = "CREATE TABLE test(_id INTEGER PRIMARY KEY AUTOINCREMENT,name)";
    
        public DBOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory,
                int version) {
            super(context, name, null, 1);
        }
    
        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL(CREATE_SQL);
        }
    
        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            // TODO Auto-generated method stub
    
        }
    
    }
    
  3. MainActivity.java 同一目录下添加一个自定义 ContentProvider 类,实现 onCreate()getType()

    NameContentProvider.java

    package cn.twle.android.customprovider;
    
    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;
    
    public class NameContentProvider extends ContentProvider {
    
        //初始化一些常量
         private static UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);        
         private DBOpenHelper dbOpenHelper;
    
        //为了方便直接使用UriMatcher,这里addURI,下面再调用Matcher进行匹配
    
         static{  
             matcher.addURI("cn.twle.android.providers.msprovider", "test", 1);
         }
    
        @Override
        public boolean onCreate() {
            dbOpenHelper = new DBOpenHelper(this.getContext(), "test.db", null, 1);
            return true;
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            return null;
        }
    
        @Override
        public String getType(Uri uri) {
            return null;
        }
    
        @Override
        public Uri insert(Uri uri, ContentValues values) {
    
            switch(matcher.match(uri))
            {
            //把数据库打开放到里面是想证明uri匹配完成
            case 1:
                SQLiteDatabase db = dbOpenHelper.getReadableDatabase();
                long rowId = db.insert("test", null, values);
                if(rowId > 0)
                {
                    //在前面已有的Uri后面追加ID
                    Uri nameUri = ContentUris.withAppendedId(uri, rowId);
                    //通知数据已经发生改变
                    getContext().getContentResolver().notifyChange(nameUri, null);
                    return nameUri;
                }
            }
            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. 修改 AndroidManifest.xml 中为 ContentProvider 进行注册

    <provider
        android:name="cn.twle.android.customprovider.NameContentProvider"
        android:authorities="cn.twle.android.providers.msprovider"
        android:exported="true" />
    
  5. 修改 activity_main.xml

    这里我们就不创建新项目了,直接用一个 App 完成所有的动作

    <?xml version="1.0" encoding="utf-8" ?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:gravity="center_horizontal" 
        android:orientation="vertical" >
    
        <Button 
            android:text="插入数据"
            android:id="@+id/btn_insert" 
            android:layout_width="wrap_content" 
            android:layout_height="wrap_content" />
    
    </LinearLayout>
    
  6. 修改 MainActivity.java 实现 ContentResolver 的部分,点击按钮插入一条数据

    这里我们就不创建新项目了,直接用一个 App 完成所有的动作

    package cn.twle.android.customprovider;
    
    import android.content.ContentResolver;
    import android.content.ContentValues;
    import android.net.Uri;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.Toast;
    
    public class MainActivity extends AppCompatActivity {
    
        private 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);
    
            //读取contentprovider 数据  
            final ContentResolver resolver = this.getContentResolver();
    
            btn_insert.setOnClickListener(new View.OnClickListener() {
    
                @Override
                public void onClick(View v) {
                     ContentValues values = new ContentValues();
                     values.put("name", "测试");
                     Uri uri = Uri.parse("content://cn.twle.android.providers.msprovider/test");
                    resolver.insert(uri, values);
                    Toast.makeText(getApplicationContext(), "数据插入成功", Toast.LENGTH_SHORT).show();
    
                }
            });
    
        }
    }
    

运行 APP ,点击插入数据,然后打开 file exploer 将 ContentProvider 的 db 数据库取出,用图形查看工具查看即可发现插入数据

参考文档

  1. Android ContentProvider

Android 基础教程

关于   |   FAQ   |   我们的愿景   |   广告投放   |  博客

  简单教程,简单编程 - IT 入门首选站

Copyright © 2013-2022 简单教程 twle.cn All Rights Reserved.