文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Android中ContentProvider组件如何使用

2023-06-05 00:42

关注

Android中ContentProvider组件如何使用,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

ContentProvider是Android系统中为开发者专门提供的不同应用间进行数据共享的组件,其提供了一套标准的接口用来获取以及操作数据,准许开发者把自己的应用数据根据需求开放给其他应用进行增删改查,而无须担心直接开放数据库权限而带来的安全问题。系统预置了许多ContentProvider用于获取用户数据,例如消息、联系人、日程表等。

具体形式如下图所示:

Android中ContentProvider组件如何使用

使用方式
1 ContentResolver

在ContentProvider的使用过程中,需要借用ContentResolver来控制ContentProvider所暴露处理的接口,作为代理来间接操作ContentProvider以获取数据。

在 Context.java 的源码中如下抽象方法

    public abstract ContentResolver getContentResolver();

所以可以在所有继承Context的类中通过 getContentResovler() 方法获取ContentResolver

ContentResolver contentResolver = getContentResovler();
2 ContentProvider

ContentProvider作为Android四大组件之一,并没有Activity那样复杂的生命周期,只有简单地onCreate过程。

创建一个自定义ContentProvider的方式是继承ContentProvider类并实现其六个抽象方法:

public class MyContentProvider extends ContentProvider {    @Override    public boolean onCreate() {      return false;    }        @Override    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {      return null;    }        @Override    public String getType(@NonNull Uri uri) {      return null;    }        @Override    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {return null;   }    @Override    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {return 0;    }    @Override    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {return 0;    }}

之后,需要在AdnroidManifest.xml中对ContentProvider进行注册

<!-- xxx为上一层包名 --><provider            android:name=".MyContentProvider"            android:authorities="com.xmkh.MyContentProvider"            android:exported="true"/>

name:自定义的ContentProvider的全称类名。

authorities:自定义ContentProvider的唯一标识,外部应用通过该属性值来访问我们的ContentProvider。因此该属性值必须是唯一的,建议在命名时以包名为前缀。

exported:表明是否允许其他应用调用ContentProvider,true表示支持,false表示不支持。默认值根据开发者的属性设置而会有所不同,如果包含 Intent-Filter 则默认值为true,否则为false。

3 Uri

观察MyContentProvider中的几个方法,可以发现除了 onCreate() 方法外,其它五个抽象方法都包含了一个Uri(统一资源标识符)参数,通过这个对象可以来匹配对应的请求。那么从ContentProvider的数据操作方法可以看出都依赖于Uri,而对于Uri有其固定的数据格式,例如:

Android中ContentProvider组件如何使用

比如,ContentProvider中操作的数据可以都是从SQLite数据库中获取的,而数据库中可能存在许多张表,这时候就需要用到Uri来表明是要操作哪个数据库、操作数据库的哪张表了

public class TestContract {    public static final String CONTENT_AUTHORITY = "com.xmkh.contentproviderdemo.MyContentProvider";    public static final Uri BASE_CONTENT_URI = Uri.parse("content://" + CONTENT_AUTHORITY);    public static final String PATH_ARTICLE = "article";    public static final class TestEntry implements BaseColumns {        public static final Uri CONTENT_URI = BASE_CONTENT_URI.buildUpon().appendPath(PATH_ARTICLE).build();        protected static Uri buildUri(long id) {            return ContentUris.withAppendedId(CONTENT_URI, id);        }        protected static final String TABLE_NAME = "article";        public static final String COLUMN_NAME = "name";    }}

从上面代码我们可以看到,我们创建了一个 content://com.xmkh.contentproviderdemo.MyContentProvider/article的uri,并且开了一个静态方法,用以在有新数据产生时根据id生成新的Uri。

那么如何确定一个Uri是要执行哪项操作呢?这里需要用到UriMatcher来帮助ContentProvider匹配Uri,它仅包含了两个方法:

addURI(String authority, String path, int code):用于向UriMatcher对象注册Uri。authtity是在AndroidManifest.xml中注册的ContentProvider的authority属性值;path表示一个路径,可以设置为通配符,#表示任意数字,*表示任意字符;两者组合成一个Uri,而code则代表该Uri对应的标识码

match(Uri uri):匹配传入的Uri。返回addURI()方法中传递的code参数,如果找不到匹配的标识码则返回-1

实战

讲了这么多,相信大家已经有一个初步的了解,为了让我们加深记忆,跟我一起写一个demo吧!

首先,自定义一个ContentProvider,然后向其写入和读取数据,使用SQLite作为ContentProvider的数据存储地址和数据来源,因此需要先建立一个SQLiteOpenHelper,创建一个名为"article.db"的数据库,包含“article”和“author”两张表:

public class DbOpenHelper extends SQLiteOpenHelper {        private static final String DATA_BASE_NAME = "article.db";        private static final int DATE_BASE_VERSION = 1;        public static final String ARTICLE_TABLE_NAME = "article";        public static final String AUTHOR_TABLE_NAME = "author";        private final String CREATE_ARTICLE_TABLE = "create table " + ARTICLE_TABLE_NAME            + "(_id integer primary key autoincrement, articleName text)";        private final String CREATE_AUTHOR_TABLE = "create table " + AUTHOR_TABLE_NAME            + "(_id integer primary key autoincrement, authorName text, sex text)";    public DbOpenHelper(Context context) {        super(context, DATA_BASE_NAME, null, DATE_BASE_VERSION);    }    @Override    public void onCreate(SQLiteDatabase db) {        db.execSQL(CREATE_ARTICLE_TABLE);        db.execSQL(CREATE_AUTHOR_TABLE);    }    @Override    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {    }}

自定义ContentProvider 当中,getTableName(Uri uri)方法用于判定Uri指向的数据库表名 然后在initProviderData()方法中向数据库插入一些原始数据

为了方便大家理解,我们将上述出现的代码进行修改,展示给大家:

public class MyContentProvider extends ContentProvider {        private Context mContext;    private SQLiteDatabase sqLiteDatabase;    public static final String AUTHORITY = "com.xmkh.MyContentProvider";    public static final int ARTICLE_URI_CODE = 0;    public static final int AUTHOR_URI_CODE = 1;    private static final UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);    static {        uriMatcher.addURI(AUTHORITY, DbOpenHelper.ARTICLE_TABLE_NAME, ARTICLE_URI_CODE);        uriMatcher.addURI(AUTHORITY, DbOpenHelper.AUTHOR_TABLE_NAME, AUTHOR_URI_CODE);    }    private String getTableName(Uri uri) {        String tableName = null;        switch (uriMatcher.match(uri)) {            case ARTICLE_URI_CODE:                tableName = DbOpenHelper.ARTICLE_TABLE_NAME;                break;            case AUTHOR_URI_CODE:                tableName = DbOpenHelper.AUTHOR_TABLE_NAME;                break;        }        return tableName;    }    public MyContentProvider() {    }        @Override    public boolean onCreate() {        mContext = getContext();        initArticleProviderData();        return false;    }    //初始化原始数据    private void initArticleProviderData() {        sqLiteDatabase = new DbOpenHelper(mContext).getWritableDatabase();        sqLiteDatabase.beginTransaction();        ContentValues contentValues = new ContentValues();        contentValues.put("articleName", "Android四大组件之Activity");        sqLiteDatabase.insert(DbOpenHelper.ARTICLE_TABLE_NAME, null, contentValues);        contentValues.put("articleName", "Android四大组件之BroadcastReceiver");        sqLiteDatabase.insert(DbOpenHelper.ARTICLE_TABLE_NAME, null, contentValues);        contentValues.put("articleName", "Android四大组件之Service");        sqLiteDatabase.insert(DbOpenHelper.ARTICLE_TABLE_NAME, null, contentValues);        contentValues.clear();        contentValues.put("authorName", "ptt");        contentValues.put("sex", "女");        sqLiteDatabase.insert(DbOpenHelper.AUTHOR_TABLE_NAME, null, contentValues);        contentValues.put("authorName", "HiYoung");        contentValues.put("sex", "男");        sqLiteDatabase.insert(DbOpenHelper.AUTHOR_TABLE_NAME, null, contentValues);        contentValues.put("authorName", "gy");        contentValues.put("sex", "男");        sqLiteDatabase.insert(DbOpenHelper.AUTHOR_TABLE_NAME, null, contentValues);        sqLiteDatabase.setTransactionSuccessful();        sqLiteDatabase.endTransaction();    }        @Override    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection, @Nullable String[] selectionArgs, @Nullable String sortOrder) {        String tableName = getTableName(uri);        if (tableName == null) {            throw new IllegalArgumentException("Unsupported URI:" + uri);        }        return sqLiteDatabase.query(tableName, projection, selection, selectionArgs, null, null, sortOrder, null);    }        @Override    public String getType(@NonNull Uri uri) {        return null;    }        @Override    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {        String tableName = getTableName(uri);        if (tableName == null) {            throw new IllegalArgumentException("Unsupported URI:" + uri);        }        sqLiteDatabase.insert(tableName, null, values);        mContext.getContentResolver().notifyChange(uri, null);        return uri;    }        @Override    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {        String tableName = getTableName(uri);        if (tableName == null) {            throw new IllegalArgumentException("Unsupported URI:" + uri);        }        int count = sqLiteDatabase.delete(tableName, selection, selectionArgs);        if (count > 0) {            mContext.getContentResolver().notifyChange(uri, null);        }        return count;    }        @Override    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {        String tableName = getTableName(uri);        if (tableName == null) {            throw new IllegalArgumentException("Unsupported URI:" + uri);        }        int row = sqLiteDatabase.update(tableName, values, selection, selectionArgs);        if (row > 0) {            mContext.getContentResolver().notifyChange(uri, null);        }        return row;    }}

ContentProvider创建好切记一定要在AndroidManifest.xml中注册!(前文已经提到了如何注册,我就不再复述啦~)

然后分别操作article和author两张表,向其插入一条数据后Log输出所有的数据

public class MainActivity extends AppCompatActivity {      private final String TAG = "MainActivity";    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        Uri articleUri = Uri.parse("content://com.xmkh.MyContentProvider/article");        ContentValues contentValues = new ContentValues();        contentValues.put("articleName", "Android四大组件之ContentProvider");        getContentResolver().insert(articleUri, contentValues);        Cursor articleCursor = getContentResolver().query(articleUri, new String[]{"_id", "articleName"}, null, null, null);        if (articleCursor != null) {            while (articleCursor.moveToNext()) {                Log.e(TAG, "ID:" + articleCursor.getInt(articleCursor.getColumnIndex("_id"))                        + "  ArticleName:" + articleCursor.getString(articleCursor.getColumnIndex("articleName")));            }            articleCursor.close();        }        Uri authorUri = Uri.parse("content://com.xmkh.MyContentProvider/author");        contentValues.clear();        contentValues.put("authorName", "Austen");        contentValues.put("sex", "男");        getContentResolver().insert(authorUri, contentValues);        Cursor authorCursor = getContentResolver().query(authorUri, new String[]{"_id", "authorName", "sex"}, null, null, null);        if (authorCursor != null) {            while (authorCursor.moveToNext()) {                Log.e(TAG, "ID:" + authorCursor.getInt(authorCursor.getColumnIndex("_id"))                        + "  AuthorName:" + authorCursor.getString(authorCursor.getColumnIndex("authorName"))                        + "  Sex:" + authorCursor.getString(authorCursor.getColumnIndex("sex")));            }            authorCursor.close();        }    }}

得到的输出结果是:

Android中ContentProvider组件如何使用

关于Android中ContentProvider组件如何使用问题的解答就分享到这里了,希望以上内容可以对大家有一定的帮助,如果你还有很多疑惑没有解开,可以关注编程网行业资讯频道了解更多相关知识。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯