Android学习笔记十九.使用ContentProvider实现数据共享(一)

一、Android如何实现数据共享? 

为了在应用程序之间交换数据,Android提供了ContentProvider,ContentProvider是不同应用程序之间进行数据交换的标准API,当一个应用程序需要把自己的数据暴露给其他程序使用时,该应用程序就可通过提供ContentProvider来实现,其他的应用程序就可以通过ContentResolver来操作ContentProvider暴露的数据。一旦某个应用程序通过ContentProvider暴露了自己的数据操作接口,那么不管该应用程序是否启动,其他应用程序都可以通过该接口来操作该应用程序的内部数据,包括增加数据、删除数据、修改数据、查询数据等。

总结:A应用通过ContentProvider暴露自己的数据,B应用通过ContentResolver来操作ContentProvider暴露的数据。

A应用以某种Uri的形式对外提供数据,B应用使用ContentResolver根据A应用提供的Uri获得A应用的authority 属性去访问操作指定的数据。

二、ContentProvider与

ContentResolver简介

1.功能:

(1)ContentProvider是不同应用程序之间进行数据交换的标准API,ContentProvider以某种Uri的形式对外提供数据,运行其他应用访问或修改数据,即其他应用程序使用ContentResolver根据Uri去访问操作指定数据,
UriMatcher类用于帮助解

析URI。在实际应用中,自定义的ContentProvider类除了需要继承ContentProvider之外,还需要同时实现以下方法(均为抽象方法):

- abstract boolean onCreate()

- abstract Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)

-abstract Uri insert(Uri uri, ContentValues values)

- abstract int update(Uri uri, ContentValues values, String selection, String[] selectionArgs)

- abstract int delete(Uri uri, String selection, String[] selectionArgs)

- abstract String getType(Uri uri)

(2)Contentprovider相当于一个"网站",它的作用是暴露可供提供操作的数据。其他应用程序则通过ContentResolver来操作ContentProvider所暴露的数据,即ContentResolver相当于HttpClient。

一般来说,ContentProvider是单实例模式,当多个应用程序通过ContentResolver来操作ContentProvider提供的数据时,ContentResolver调用的数据操作将会委托给同一个ContentProvider处理。


升华笔记1:ContentResolver是如何实现访问、修改Uri对应的ContentProvider中的数据?

从ContentResolver、ContentProvider和Uri的关系来看,Uri是ContentResolver和ContentProvider进行数据交换的标识。

ContentResolver对指定Uri执行CRUD等数据操作,但Uri并不是真正的数据中心,因此这些CRUD操作会委托给该Uri对应的ContentProvider来实现。举个例子:假如B应用通过ContentResolver执行CUUD操作,这些CRUD操作都需要指定Uri参数,Android系统就根据该Uri找到对应的ContentProvider(该ContentProvider属于A应用),ContentProvider复杂实现CRUD方法,完成对底层数据的增、删、改、查等操作,即实现了B应用访问A应用数据的目的。

注释:这里的CRUD操作,指的是当B应用调用ContentResolver的insert()方法是,实际上相当于调用了该Uri对应的ContentProvider(属于A应用)的insert()方法。


2.API

ContentProvider

(1)继承关系

public abstract class

java.lang.Object

? android.content.ContentProvider

(2)构造方法


ContentProvider()

Construct a ContentProvider instance.

(3)常用方法

abstract boolean onCreate():该方法在ContentProvider创建后会被调用,当其他应用程序第一次访问ContentProvider时,

该 ContentProvider会被创建出来,并立即回调该onCreate()方法;

abstract Cursor query(Uri uri, String[] projection, String
selection, String[] selectionArgs, String sortOrder):根据Uri查询出select条件所匹配的全部记录,其中projection就是一个列名列表,表明只选择指定的数据列;

abstract Uri insert(Uri uri, ContentValues values):根据该Uri插入values对应的数据

abstract int update(Uri uri, ContentValues values, String
selection, String[] selectionArgs):根据Uri修改selection条件所匹配的全部记录

abstract int delete(Uri uri, String selection, String[]
selectionArgs):根据Uri删除select条件所匹配的全部记录;

abstract String getType(Uri uri) :该方法用于返回当前Uri所代表的数据的MIME类型。如果该Uri对应数据可能包括多条记录,那么MIME类型字符串应用以vnd.android.cursor.dir/开头。如果该Uri对应的数据只包含一条记录,那么返回MIME类型字符串应该以vnd.android.cursor.item/开头。

ContentResolver

(1)继承关系

public abstract class

java.lang.Object

? android.content.ContentProvider

(2)构造方法(创建ContentResolver对象)


ContentResolver(Context context)

此外,Content提供了getContentResolver()方法来获取一个ContentResolver对象。也就是说,Activity、Service等组件都可通过getContentResolver()方法获取ContentResolver对象,这样我们再调用ContenResolver的如下方法就可以操作暴露的数据了。

ContentResolver contentResolver=getContentResolver();

(3)常用方法

final int delete(Uri
url, String where, String[] selectionArgs):删除Uri对应的ContentProvider中where提交匹配的数据;

final String
getType(Uri url):获取给定Content URL的MIME类型;

final Uri insert(Uri
url, ContentValues values):向Uri对应的ContentProvider中插入values对应的数据;

Parameters:
url The URL of the table to insert into.
values The initial values for the newly inserted row. The key is the column name for the field. Passing an empty ContentValues will create an empty row.
Returns:
the URL of the newly created row.

final Cursor
query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):查询Uri对应的ContentProvider中where提交匹配的数据;

Parameters:

uri The URI, using the content:// scheme, for the content to retrieve.
projection A list of which columns to return. Passing null will return all columns, which is inefficient.
selection A filter declaring which rows to return, formatted as an SQL WHERE clause (excluding the WHERE itself). Passing null will return all rows for the given URI.
selectionArgs You may include ?s in selection, which will be replaced by the values from selectionArgs, in the order that they appear in the selection. The values will be bound
as Strings.
sortOrder How to order the rows, formatted as an SQL ORDER BY clause (excluding the ORDER BY itself). Passing null will use the default sort order, which may be unordered.
Returns:
A Cursor object, which is positioned before the first entry, or null

final void registerContentObserver(Uri
uri, boolean notifyForDescendents, ContentObserver observer):注册一个观察类,当暴露的URI对应的ContentProvider中的数据发生变化时调用该方法

final
int update(Uri uri, ContentValues values, String where, String[] selectionArgs):更新Uri对应的ContentProvider中where提交匹配的数据;

ContentValues

This class is used to store a set of values that the ContentResolver can process.

(1)继承关系

java.lang.Object

? android.content.ContentValues

(2)构造函数


ContentValues()

Creates an empty set of values using the default initial size


ContentValues(int
size)

Creates an empty set of values using the given initial size


ContentValues(ContentValues from)

Creates a set of values copied from the given set

(3)常用方法

void
put(String key, Byte value) :添加键值对值到set集合

Set<Entry<String, Object>>
valueSet() :返回set集合中所有的键对象和值对象

int size() :返回set集合中值的数量

Cursor接口

(1)功能概述:该接口主要用于随机读写从数据库查询返回的set集合形式的结果。Cursor的实现不需要同步,所有当我们使用Cursor接口时,多线程使用Cursor时只需要注意自身同步即可。

(2)常用方法:

abstract
void close() :关闭Cursor,释放所有资源

abstract
void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) :获取需要的列文本并将其存储到提供的buffer数组中

abstract
int getPosition() :返回set集合中cursor游标当前的行位置

abstract
boolean isNull(int columnIndex) :当指定的列为null时返回为true

abstract
boolean move(int offset) :把当前游标位置向前或向后移动offset数量

abstract
boolean moveToNext() :将游标移动到下一行

三、ContentProvider与

ContentResolver

开发思路

1.ContentProvider开发思路(A应用提供ContentResolver接口)

(1)定义一个ContentProvider子类。该子类需要继承Android提供的ContentProvider基类,并且需要实现query()、insert()、update()和delete()(抽象方法)等方法;

(2)配置ContentProvider。在该ContentProvider供其他应用调用之前,需要向Android系统注册ContentProvider,即在A应用的工程文件AndroidManifest.xml文件中注册这ContentProvider(类似于注册Activity),且注册ContentProvider时需要为它绑定一个Uri;

<provider android:name=".FirsttProvider"                
                                       //指定该ContentProvider的实现类的类名

android:authorities="com.example.Android.ContentProvider_1"
       //指定该ContentProvider对应的Uri(相当于为该ContentProvider分配一个域名)

android:exported="true"/>                                              
                 //指定该ContentProvider是否允许其他应用调用("true"为允许)


升华笔记2:

注释1:ContentProvider子类实现的query()、insert()、update()和delete()方法,并不是给A应用本身调用,而是提供给其他应用来调用。

注释2:由于可以有多个应用程序通过ContentProvider暴露自己数据,android:authorities的作用在于方便其他应用程序访问、删除指定应用程序数据。

注释3:传递参数-ContentResolver调用方法时的参数,将会传递给Uri对应的ContentProvider的query()、insert()、update()和delete()方法;

返回值   -ContentResolver调用方法时的返回值,即为Uri对应的ContentProvider的query()、insert()、update()和delete()方法的返回值;


2.ContentResolver开发思路(B应用访问、修改A应用的数据)

(1)获取ContentResolver实例对象。

(2)通过实例对象调用ContentResolver的query()、insert()、update()和delete()方法。即指定Uri对应ContentProvider的query()、insert()、update()和delete()方法将要完成的功能。

四、实战源码

1.开发ContentProvider

(1)FirstProvider.java

package com.example.android_contentprovider_1;
import android.content.ContentProvider;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
public class FirstProvider extends ContentProvider {
 //1.第一次创建该ContentProvider时调用该方法
 @Override
 public boolean onCreate() {
  System.out.println("====onCreate方法被调用=====");
  return false;
 }
 //2.实现查询方法,该方法应该返回查询得到的Cursor
 @Override
 public Cursor query(Uri uri, String[] projection, String where,
   String[] selectionArgs, String sortOrder) {
  System.out.println("====query方法被调用=====");
  System.out.println("where参数为:"+where);
  return null;
 }
 //3.该方法的返回值代表了该ContentProvider所提供数据的MIME类型
 @Override
 public String getType(Uri uri) {
  return null;
 }
 //4.实现插入的方法,该方法应该返回新插入的记录的Uri
 @Override
 public Uri insert(Uri uri, ContentValues values) {
  System.out.println(uri+"====insert被调用=====");
  System.out.println("values参数为:"+values);
  return null;
 }
 //5.实现删除方法,该方法应该返回被删除的记录条数
 @Override
 public int delete(Uri uri, String where, String[] selectionArgs) {
  System.out.println(uri+"====delete方法被调用=====");
  System.out.println("where参数为:"+where);
  return 0;
 }
 //6.实现更新方法,该方法应该返回被更新的记录条数
 @Override
 public int update(Uri uri, ContentValues values, String selection,
   String[] selectionArgs) {
  System.out.println(uri+"====update方法被调用=====");
  System.out.println("values参数为:"+values);
  return 0;
 }
}

(2)AndroidManifest.xml(部分)

<application

android:icon="@drawable/ic_launcher">

<!--注册一个ContentProvider -->

<provider

android:name=".FirstProvider"

android:authorities="com.example.android_contentprovider_1"

android:exported="true"/>

</application>

</manifest>

2.使用ContentResolver调用方法

FirstResolver.java

package com.example.android_contentresolver_2;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;
public class FirstResolver extends Activity {
 ContentResolver contentResolver;
 Uri uri=Uri.parse("content://com.example.android_contentprovider_1");	//解析一个uri用以获取对应的ContentProvider
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.main);
 //1.获取系统的ContentResolver对象
  contentResolver=getContentResolver();
 }
 //2.调用ContentResolver的query()方法
 public void query(View source)
 {
  Cursor c=contentResolver.query(uri, null, "query_where", null, null);//实际返回的是该Uri对应的ContentProvider的query()的返回值
  Toast.makeText(this, "远程ContentProvider返回的Cursor为"+c, Toast.LENGTH_SHORT).show();
 }
 //3.调用ContentResolver的insert()方法
 public void insert(View source)
 {
  ContentValues values=new ContentValues();
  values.put("name", "jiangdongguo");
  Uri newUri=contentResolver.insert(uri, values);	//将键值对插入到uri对应的ContentProvider共享数据中
  Toast.makeText(this, "远程ContentProvider新插入记录的Uri为:"+newUri, Toast.LENGTH_SHORT).show();
 }
 //4.调用ContentResolver()的update()方法
 public void update(View source)
 {
  ContentValues values=new ContentValues();
  values.put("name", "zhongxian");
  int count=contentResolver.update(uri, values, "update_where", null);
  Toast.makeText(this, "远程ContentProvider更新记录数为:"+count, Toast.LENGTH_SHORT).show();
 }
 //5.调用ContentResoler的delete()方法
 public void delete(View source)
 {
  int count=contentResolver.delete(uri, "delete_where", null);//实际返回的是该ContentProvider的delete()的返回值
  Toast.makeText(this, "远程ContentProvider删除记录数为:"+count, Toast.LENGTH_SHORT).show();
 }

}

注释:布局界面为4个按钮,每个按钮需要定义android:onClick="delete"属性。

(1)ContentProvider不同于Activity存在复杂的声明周期,ContentProvider只有一个onCreate()生命周期方法,当其他应用通过ContentResolver第一次访问该ContentProvider时,onCreate()方法将会被回调,onCreate方法只会被调用一次。

(2)其他应用通过ContentResolver调用query()、insert()、delete()、update()方法,实际上是调用ContentProvider提供的query()、insert()、delete()、update()方法来操作ContentProvider暴露的数据;

(3)开发ContentProvider时所实现的query()、insert()、delete()、update()方法的第一个参数为Uri参数,该参数由ContentResolver调用这些方法时传入。

效果演示:

参考:http://wear.techbrood.com/reference/android/content/ContentProvider.html

时间: 2025-01-06 23:03:16

Android学习笔记十九.使用ContentProvider实现数据共享(一)的相关文章

Android学习笔记二十一.使用ContentProvider实现数据共享(四).操作系统(联系人)的ContentProvider

Android系统本身提供了大量的ContentProvider,例如联系人信息.系统的多媒体信息等,我们开发的应用程序主要是通过ContentResolver来调用系统的ContentProvider提供的query().insert().update()和delete()方法来获取Android内部的数据. 一.如何使用ContentResolver操作系统ContentProvider暴露的内部数据? 1.调用Activity的getContentResolver()获取ContentRe

angular学习笔记(十九)

本篇主要介绍angular使用指令修改DOM: 使用angular指令可以自己扩展html语法,还可以做很多自定义的事情.在后面会专门讲解这一块的知识,这一篇只是起到了解入门的作用. 与控制器,过滤器,服务,一样,可以通过模块实例的directive的方法来创建指令: var someModule = angular.module('SomeModule',[]); someModule.directive('directiveName',function(){ return { link: f

Android学习笔记(九)——更复杂的进度对话框

显示操作进度的对话框 1.使用上一篇创建的同一项目,在activity_main.xml文件中添加一个Button: <Button android:id="@+id/btn_dialog3" android:layout_width="fill_parent" android:layout_height="wrap_content" android:onClick="onClick3" android:text=&qu

Android学习笔记(九)——布局和控件的自定义

//此系列博文是<第一行Android代码>的学习笔记,如有错漏,欢迎指正! View是 Android中一种最基本的 UI组件,它可以在屏幕上绘制一块矩形区域,并能响应这块区域的各种事件,因此,我们使用的各种控件其实就是在 View的基础之上又添加了各自特有的功能.而ViewGroup 则是一种特殊的 View,它可以包含很多的子 View和子 ViewGroup,是一个用于放置控件和布局的容器.系统默认的所有控件都是直接或间接继承自 View 的,所用的所有布局都是直接或间接继承自 Vie

Android学习笔记十四.深入理解fragment(二) 之《图书详情》实战

深入理解fragment(二) 之<图书详情>实战 通过上一篇博文<深入理解fragment一>,我们学习了Android-Fragment的核心知识点.现在在此基础上,利用Fragment技术开发一款适用于大屏幕手机/平板的查找图书详情的应用软件.该项目主要在于两方面,一是Activity.Fragment的源码实现:二是,布局界面资源文件的实现. 1.res/../BookListFragment.java: 自定义类,继承于ListFragment,无需实现OnCreateV

Android学习笔记十五.深入理解fragment(三) 之《兼容多分辨率的应用》实战

深入理解fragment(三) 之<兼容多分辨率的应用>实战 在上一篇博文中介绍了如何使用Android Fragment开发适用于大屏幕应用,现在我们在上一个应用的基础上继续学习如何使用Fragment开发兼容多分辨率的应用. 1.建立/res/values-large/refs.xml引用资源文件 为了开发兼顾屏幕分辨率的应用,我们需要建立一个引用资源文件,专门用于定义各种引用项.refs.xml引用资源文件中定义了一项引用,其作用就是标明activity_book_list实际引用(@)

Android学习(十二) ContentProvider

一.ContentProvider简介       当应用继承ContentProvider类,并重写该类用于提供数据和存储数据的方法,就可以向其他应用共享其数据.虽然使用其他方法也可以对外共享数据,但数据访问方式会因数据存储的方式而不同,如:采用文件方式对外共享数据,需要进行文件操作读写数据:采用sharedpreferences共享数据,需要使用sharedpreferences API读写数据.而使用ContentProvider共享数据的好处是统一了数据访问方式. 二.如何实现Conte

Android学习笔记(九)

Android中的四种基本布局 1.LinearLayout LinearLayout称为线性布局,是一种常用的布局.修改activity_main.xml中的代码,如下所示: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_

[傅里叶变换及其应用学习笔记] 十九. 采样定理在音乐上的应用

采样定理在音乐上的应用 人可以听到20~20000Hz的声音,上限为20000Hz,即$\frac{p}{2} = 20000$,$p=40000$.那么采样率至少要为40000.CD的采样率采用44100(44.1kHz),据传,在采集模拟信号时采用44100,是因为这些采集的机器以该采样率设置时最为正常,而并非出于理论上的考虑. 在采样时,若采用低于40000的采样率,就会造成声音的高频部分混叠(alias),也有人把这个说成是“低频混叠了变为高频部分,而高频的部分被混叠为低频部分”,实际上