四大组件之ContentProvider(二)-轻轻松松自定义ContentProvider

第3节 自定义ContentProvider

自定义一个ContentProvider,需要

  1. 继承ContentProvider类重新创建一个类,并实现其中的一些方法;
  2. 在应用的AndroidManifest.xml文件中,声明这个新添加的组件;

但在这之前,我们要来设计一下外部访问它采用的地址。

3.1 地址设计

Urischeme字段是固定的,使用content:

authority定义成程序的包名com.anddle.mycontentprovider

path就像是网站内部的分类,依据网站的逻辑进行划分。

假设我们的ContentProvider提供书籍book和文件file两种内容的查询操作。而每种类型都可以进行单一数据的操作和多条数据的操作。

例如,

  • 操作所有书的信息:content://com.anddle.mycontentprovider/books;
  • 操作某本特定书的信息:content://com.anddle.mycontentprovider/books/8
  • 操作所有文件的信息:content://com.anddle.mycontentprovider/files
  • 操作某个特定文件的信息:content://com.anddle.mycontentprovider/files/3

所以,在对这些地址代表的对象进行增删改查的时候,就需要分析出它们针对的对象。

3.2 创建ContentProvider子类

  1. 继承ContentProvider类,会要求我们实现getType() insert() delete() update() query() onCreate()等接口,

    public class MyContentProvider extends ContentProvider {
    
        @Override
        public boolean onCreate() {
    
            return true;
        }
    
        @Override
        public String getType(Uri uri) {
    
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public Uri insert(Uri uri, ContentValues values) {
    
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public int delete(Uri uri, String selection, String[] selectionArgs) {
    
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public int update(Uri uri, ContentValues values, String selection,
                          String[] selectionArgs) {
    
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                            String[] selectionArgs, String sortOrder) {
    
            throw new UnsupportedOperationException("Not yet implemented");
        }
    
    }
  2. 定义提供给其他组件使用的“网络地址”URI,这里我们把它们定义成content://com.anddle.mycontentprovider/books content://com.anddle.mycontentprovider/files
    private static final String SCHEME = "content://";
    
    private static final String PATH_BOOKS = "/books";
    private static final String PATH_FILES = "/files";
    
    public static final String AUTHORITY = "com.anddle.mycontentprovider";
    
    //"content://com.anddle.mycontentprovider/books"
    public static final Uri CONTENT_BOOKS_URI = Uri.parse(SCHEME + AUTHORITY + PATH_BOOKS);
    
    //"content://com.anddle.mycontentprovider/files"
    public static final Uri CONTENT_FILES_URI = Uri.parse(SCHEME + AUTHORITY + PATH_FILES);
  3. 定义解析地址的匹配器,
    private static final int BOOKS = 0;
    private static final int BOOK = 1;
    private static final int FILES = 2;
    private static final int FILE = 3;
    
    private static final UriMatcher sUriMatcher;
    
    static {
    
        sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    
        sUriMatcher.addURI(AUTHORITY, PATH_BOOKS, BOOKS);
        sUriMatcher.addURI(AUTHORITY, PATH_BOOKS+"/#", BOOK);
    
        sUriMatcher.addURI(AUTHORITY, PATH_FILES, FILES);
        sUriMatcher.addURI(AUTHORITY, PATH_FILES+"/#", FILE);
    
    }

    UriMatcher可以对传入的字符串进行匹配检测,如果匹配成功,会返回一个对应的值,例如,

    int type = sUriMatcher.match("content://com.anddle.mycontentprovider/files");
    //type就等于FILES的值2

    type就等于FILES的值2。利用这个方法,我们就可以区分出Uri访问ContentProvider时,到底希望操作什么样的数据。

    创建匹配器的时候,加入sUriMatcher.addURI("content://com.anddle.mycontentprovider","files/#", FILE);这种带有”#”的关键字段,表示如下这种匹配方式,即匹配任何数字

    content://com.anddle.mycontentprovider/files/0
    content://com.anddle.mycontentprovider/files/1
    content://com.anddle.mycontentprovider/files/3

    创建匹配器的时候,加入sUriMatcher.addURI("content://com.anddle.mycontentprovider","files/*", FILE);这种带有”#”的关键字段,表示如下这种匹配方式,即匹配任何字符

    content://com.anddle.mycontentprovider/files/how-to-program
    content://com.anddle.mycontentprovider/files/bible
    content://com.anddle.mycontentprovider/files/101story
  4. 在回调函数中,根据Uri,做对应的操作,
    @Override
    public Uri insert(Uri uri, ContentValues values) {
    
       Uri result = null;?
    
       switch (sUriMatcher.match(uri)) {
    
           case BOOKS: {
                //从ContentValues中取出数据,保存起来;返回保存数据的Uri地址,例如
                //content://com.anddle.mycontentprovider/books
           }
           break;
    
           case BOOK: {
                //从ContentValues中取出数据,保存起来;返回保存数据的Uri地址,例如
                //content://com.anddle.mycontentprovider/books/8
           }
           break;
    
           case FILES: {
                //从ContentValues中取出数据,保存起来;返回保存数据的Uri地址,例如
                //content://com.anddle.mycontentprovider/files
           }
           break;
    
           case FILE: {
                //从ContentValues中取出数据,保存起来;返回保存数据的Uri地址,例如
                //content://com.anddle.mycontentprovider/files/8
           }
           break;
    
           default:
               throw new IllegalArgumentException("Unknown URI " + uri);
       }
    
       return result;
    }

    这里就要实现对数据增删改查的真正操作。

    ContentProvider中,可以使用很多方式对数据进行保存、修改,例如SQL数据库。不过我们暂时不去实现,把它放到下一个章节专门介绍。

    其他delete() update() query()实现的函数做类似处理。

  5. 对于getType(), 需要为每一种类型的Uri返回一种数据类型-MIME type,告诉调用者,当前这种Uri可以处理什么类型的数据。

    它的格式型如type\subtype,有很多知名的MIME type类型,例如application/pdf image/jpeg等等,可以在网上查找到公开的MIME type类型有哪些。也可以自定义自己应用支持的特殊MIME type类型。

    这里我们就返回一个空值,

    @Override
    public String getType(Uri uri) {
    
       return null;
    }

至此,一个ContentProvider的就完成了。不过它现在还没有添加上真正可以存储数据的功能。

/*******************************************************************/

版权声明

本教程只在CSDN和安豆网发布,其他网站出现本教程均为盗链。

/*******************************************************************/

3.3 声明ContentProvider

千万不要忘记,在应用的AndroidManifest.xml文件中,声明新添加的ContentProvider

<provider
    android:name=".MyContentProvider"
    android:authorities="com.anddle.mycontentprovider"
    android:enabled="true"
    android:exported="true" />

这里的android:authorities属性值,就要填写定义MyContentProvider时,代码中的那个,

public static final String AUTHORITY = "com.anddle.mycontentprovider";

android:exported属性如何设置成true,说明这个ContentProvider可以被其他应用使用(就像一个公共网站,可以被任何人访问),如果设置成false,说明它只能被自己所在的应用使用(就像一个内部网站,只能在公司内部访问)。

3.4 使用自定义ContentProvider

无论是使用应用自己的ContentProvider还是使用其他应用提供的,它们的使用方式都和使用系统提供的ContentProvider一样,

  1. 添加一条数据数据:通过ContentResolver获取访问ContentProvider的入口,使用ContentValues添加要插入的数据;

    ContentResolver cr = getContentResolver();
    ContentValues cv = new ContentValues();
    cv.put("数据字段名称", "数据内容");
    Uri uri = cr.insert("content://com.anddle.mycontentprovider/books", cv)

    通常会返回指向刚成功插入的这条数据的Uri(内容就如content://com.anddle.mycontentprovider/books/8)。

  2. 删除一条数据:通过ContentResolver获取访问ContentProvider的入口,使用Uri删除指定的数据;
    String where = null;
    String [] keywords = null;
    ContentResolver cr = getContentResolver();
    cr.delete("content://com.anddle.mycontentprovider/books/8", where, keywords);
  3. 修改一条数据:通过ContentResolver获取访问ContentProvider的入口,使用Uri更新指定的数据,要修改的数据放在ContentValues当中;
    String where = null;
    String [] keywords = null;
    ContentResolver cr = getContentResolver();
    ContentValues cv = new ContentValues();
    cv.put("数据字段名称", "新数据内容",where,keywords);
    cr.update("content://com.anddle.mycontentprovider/books", cv, where, keywords)
  4. 查询某一类的数据(或者特定某条数据),
    Uri uri = MyContentProvider.CONTENT_BOOKS_URI;
    
    String[] searchKey = null;
    String where = null;
    String [] keywords = null;
    String sortOrder = null;
    
    ContentResolver resolver = getContentResolver();
    Cursor cursor = resolver.query(
                        uri,
                        searchKey,
                        where,
                        keywords,
                        sortOrder);
    
    if(cursor != null)
    {
        while(cursor.moveToNext())
        {
            ......
        }
    
        cursor.close();
    }

注意,在删改查的操作中,还会使用诸如where sortOrder keywords searcgKey这样的参数,它们是辅助ContentProvider查询特定数据时用的。

虽然Uri已经能定位到某条具体的数据了,但是大部分的ContentProvider都是通过SQL数据库来实现的真正存储,因此,在设计这些接口的时候就保留了SQL语言的一些用法,让使用者也能像直接操作SQL数据库那样灵活方便的使用ContentProvider

假如ContentProvider不用SQL实现数据存储功能,而采用别的存储机制,那么这些额外的参数就可以派上别的用场或者完全用不着。

时间: 2024-12-10 05:10:57

四大组件之ContentProvider(二)-轻轻松松自定义ContentProvider的相关文章

四大组件之BroadcastReceiver(一)-自定义“收音机”与发送“广播”

第1节 Broadcast Receiver概述 很多时候,我们希望一个应用程序在它没有运行起来的时候,也能感知系统状态的某些变化,如果条件合适,就让这个应用就运行起来. 比如,一个拦截骚扰电话的应用,平时它可能并不需要运行起来,它只关心有电话来的时候,看看这个号码是不是骚扰电话的号码,如果是就给用户发出一个提示,如果不是,那就和它没有关系,啥也不做. 为了实现这类功能,安卓系统引入了四大组件之一的BroadcastReceiver,设计了一套广播与接收的机制, 任何应用或者安卓系统的自身组件可

四大组件之Activity(二)

人生是一场旅行,在乎的不是目的地,是沿途的风景以及看风景的心情. 本讲内容:Activity用法 一.活动被回收了怎么办? 当一个活动进入了停止状态,是有可能被系统回收的.如果一个应用有一个活动A,用户在活动A启动活动B,活动A就进入了停止状态,这个时候由于系统内存不足,将活动A回收掉,如果用户按下Back键返回活动A,这里不会执行onRestart()方法,而是执行活动A的onCreate()方法重新创建一次.但是如果活动A是可能存在临时数据和状态的,譬如:活动A中有一个文本框,现在你输入了一

四大组件之BroadcastReceiver(二)-使用权限和常用的系统广播

第4节 Broadcast的使用权限 为广播设置权限要考虑两方面的问题. 作为广播的发送者,希望限制广播的接收者,只让特定的应用组件接收到发出的广播: 作为广播的接收者,不希望任何组件都能模仿它关心的广播,因此希望在接受广播的时候能检查一下这条广播的发送者是否具有发送这条广播的资格: 无论是上面哪种情况,解决方法都试一样的:为发送者和接收者都设置一个相同的权限,只有它们的权限匹配上了,广播机制才能产生效果. 4.1 限制接收者 假设组件A要发布广播, 在AndroidManifest.xml文件

深入理解Android四大组件之一ContentProvider

ContentProvider作为Android四大组件之一,平时写自己的ContentProvider比较少,但是用到ContentProvider地方还是有的,比如去获取通讯录信息,这其实就间接的使用到了通讯录程序的ContentProvider组件. 先简单说一下ContentProvider组件.后面重点分析源码了解ContentProvider运行的过程. ContentProvider可以实现在应用程序之间共享数据. Android为常见的一些数据提供了默认的ContentProvi

自定义ContentProvider以及ContentObserver的使用完整详细示例

示例说明: 该示例中一共包含两个工程.其中一个工程完成了自定义ContentProvider,另外一个工程用于测试该自定义ContentProvider且在该工程中使用了ContentObserver监听自定义ContentProvider的数据变化 以下代码为工程TestContentProvider ContentProviderTest如下: package cn.testcontentprovider; import android.content.ContentProvider; im

android四大组件--ContentProvider详解

一.相关ContentProvider概念解析: 1.ContentProvider简介 在Android官方指出的Android的数据存储方式总共有五种,分别是:Shared Preferences.网络存储.文件存储.外储存储.SQLite.但是我们知道一般这些存储都只是在单独的一个应用程序之中达到一个数据的共享,有时候我们需要操作其他应用程序的一些数据,例如我们需要操作系统里的媒体库.通讯录等,这时我们就可能通过ContentProvider来满足我们的需求了. 2.为什么要选择Conte

android四大组件--ContentProvider具体解释

一.相关ContentProvider概念解析: 1.ContentProvider简单介绍 在Android官方指出的Android的数据存储方式总共同拥有五种,各自是:Shared Preferences.网络存储.文件存储.外储存储.SQLite.可是我们知道一般这些存储都仅仅是在单独的一个应用程序之中达到一个数据的共享,有时候我们须要操作其它应用程序的一些数据,比如我们须要操作系统里的媒体库.通讯录等,这时我们就可能通过ContentProvider来满足我们的需求了. 2.为什么要选择

Android四大组件——ContentProvider

ContentProvider数据提供者 用与程序与程序之间的数据传递. ContentProvider提供了其他程序调用该程序内部数据的调用方法. /* * 用来定义其他程序调用该程序数据时 * 可以进行的操作. */ public class MyContentProvider extends ContentProvider { @Override//在ContentProvider创建后被调用 public boolean onCreate() { // TODO Auto-generat

Android四大组件之内容提供者--ContentProvider

Android四大组件之内容提供者--ContentProvider 1,什么是ContentProvider ContentProvider将应用中的数据对其它应用进行共享, 提供增删改查的方法 ContentProvider统一了数据的访问方式,不必针对不同数据类型采取不同的访问策略 ContentProvider将数据封装,只暴露出我们希望提供给其它程序的数据 ContentProvider中可以注册观察者, 监听数据的变化 2,怎么创建 2.1定义类继承ContentProvider,