`

Android之Content provider 详解

 
阅读更多

Android是如何实现应用程序之间数据共享的?一个应用程序可以将自己的数据完全暴露出去,外界更本看不到,也不用看到这个应用程序暴露的数据是如何存储的,或者是使用数据库还是使用文件,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和这个程序里的数据打交道,例如:添加(insert)、删除(delete)、查询(query)、修改(update),当然需要一定的权限才可以。

如何将应用程序的数据暴露出去? Android提供了ContentProvider,一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Content providers是以类似数据库中表的方式将数据暴露。Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。要想使应用程序的数据公开化,可通过2种方法:创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Content provider的权限,对于Content Provider,最重要的就是数据模型(data model) 和 URI。

1.数据模型
    Content Provider 将其存储的数据以数据表的形式提供给访问者,在数据表中每一行为一条记录,每一列为具有特定类型和意义的数据。每一条数据记录都包括一个 "_ID" 数值字段,改字段唯一标识一条数据。 

2.URI
    URI,每一个Content Provider 都对外提供一个能够唯一标识自己数据集(data set)的公开URI, 如果一个Content Provider管理多个数据集,其将会为每个数据集分配一个独立的URI。所有的Content Provider 的URI 都以"content://" 开头,其中"content:"是用来标识数据是由Content Provider管理的 schema。

      在几乎所有的Content Provider 的操作中都会用到URI,因此一般来讲,如果是自己开发的Content Provider,最好将URI定义为常量,这样在简化开发的同时也提高了代码的可维护性。

      首先来介绍如何访问Content Provider中的数据,访问 Content Provider中的数据主要通过ContentResolver对象,ContentResolver类提供了成员方法可以用来对Content Provider 中的数据进行查询、插入、修改和删除等操作。 以查询为例,查询一个 Content Provider 需要掌握如下的信息。

      唯一标识Content Provider 的URI
      需要访问的数据字段名称。
      该数据字段的数据类型

  提示: 如果需要访问特定的某条数据记录,只需该记录的ID 即可。

    查询Content Provider的方法有两个:ContentResolver的query() 和 Activity 对象的 managedQuery(),二者接收的参数均相同,返回的都是Cursor 对象,唯一不同的是 使用managedQuery 方法可以让Activity 来管理 Cursor 的生命周期。

    被管理的Cursor 会在 Activity进入暂停状态的时候调用自己的 deactivate 方法自行卸载,而在Activity回到运行状态时会调用自己的requery 方法重新查询生成的Cursor对象。如果一个未被管理的Cursor对象想被Activity管理,可以调用Activity的 startManagingCursor方法来实现。

 

Android应用程序可以使用文件或SqlLite数据库来存储数据。Content Provider提供了一种多应用间数据共享的方式,比如:联系人信息可以被多个应用程序访问。Content Provider是个实现了一组用于提供其他应用程序存取数据的标准方法的类。

应用程序可以在Content Provider中执行如下操作:
查询数据

修改数据

添加数据

删除数据

如何通过一套标准及统一的接口获取其他应用程序暴露的数据?Android提供了ContentResolver,外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据。

当前篇主要说明,如何获取其它应用程序共享的数据,比如获取Android 手机电话薄中的信息。

什么是URI?

在学习如何获取ContentResolver前,有个名词是必须了解的:URI。URI是网络资源的定义,在Android中赋予其更广阔的含义,先看个例子,如下:
URI

将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;
B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的   类名。这个标识在<provider> 元素的 authorities属性中说明:
<provider name=”.TransportationProvider”  authorities=”com.example.transportationprovider”  . . .  >
C:路径,Content Provider使用这些路径来确定当前需要生什么类型的数据,URI中可能不包括路径,也可能包括多个;
D:如果URI中包含,表示需要获取的记录的ID;如果没有ID,就表示返回全部;
由于URI通常比较长,而且有时候容易出错,切难以理解。所以,在Android当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串,例如:People.CONTENT_URI

ContentResolver 介绍说明

看完这些介绍,大家一定就明白了,ContentResolver是通过URI来查询ContentProvider中提供的数据。除了URI以外,还必须知道需要获取的数据段的名称,以及此数据段的数据类型。如果你需要获取一个特定的记录,你就必须知道当前记录的ID,也就是URI中D部分。

前面也提到了Content providers是以类似数据库中表的方式将数据暴露出去,那么ContentResolver也将采用类似数据库的操作来从Content providers中获取数据。现在简要介绍ContentResolver的主要接口,如下:

 

返回值 函数声明
final Uri insert (Uri url, ContentValues values)Inserts a row into a table at the given URL.
final int delete (Uri url, String where, String[] selectionArgs)Deletes row(s) specified by a content URI.
final Cursor query (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)Query the given URI, returning a Cursor over the result set.
final int update (Uri uri, ContentValues values, String where, String[] selectionArgs)Update row(s) in a content URI.

 

下面利用实例做进一步说明:

1:NotePad

package com.yarin.android.Examples_06_07;

import android.net.Uri;
import android.provider.BaseColumns;

public class NotePad
{
	//ContentProvider的uri
	public static final String	AUTHORITY	= "com.google.provider.NotePad";

	private NotePad(){}

	// 定义基本字段
	public static final class Notes implements BaseColumns
	{
		private Notes(){}

		public static final Uri		CONTENT_URI			= Uri.parse("content://" + AUTHORITY + "/notes");

		// 新的MIME类型-多个
		public static final String	CONTENT_TYPE		= "vnd.android.cursor.dir/vnd.google.note";

		// 新的MIME类型-单个
		public static final String	CONTENT_ITEM_TYPE	= "vnd.android.cursor.item/vnd.google.note";

		public static final String	DEFAULT_SORT_ORDER	= "modified DESC";

		//字段
		public static final String	TITLE				= "title";
		public static final String	NOTE				= "note";
		public static final String	CREATEDDATE		= "created";
		public static final String	MODIFIEDDATE		= "modified";
	}
}

 

2:NotePadProvider

package com.yarin.android.Examples_06_07;

import java.util.HashMap;

import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.text.TextUtils;

import com.yarin.android.Examples_06_07.NotePad.Notes;

public class NotePadProvider extends ContentProvider
{
	private static final String				TAG					= "NotePadProvider";
	// 数据库名
	private static final String				DATABASE_NAME		= "note_pad.db";
	private static final int				DATABASE_VERSION	= 2;
	// 表名
	private static final String				NOTES_TABLE_NAME	= "notes";
	private static HashMap<String, String>	sNotesProjectionMap;
	private static final int				NOTES				= 1;
	private static final int				NOTE_ID				= 2;
	private static final UriMatcher			sUriMatcher;
	private DatabaseHelper	mOpenHelper;
	//创建表SQL语句
	private static final String				CREATE_TABLE="CREATE TABLE " 
														+ NOTES_TABLE_NAME 
														+ " (" + Notes._ID 
														+ " INTEGER PRIMARY KEY," 
														+ Notes.TITLE 
														+ " TEXT," 
														+ Notes.NOTE 
														+ " TEXT,"
														+ Notes.CREATEDDATE 
														+ " INTEGER," 
														+ Notes.MODIFIEDDATE 
														+ " INTEGER" + ");";
	
	static
	{
		sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
		sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
		sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);

		sNotesProjectionMap = new HashMap<String, String>();
		sNotesProjectionMap.put(Notes._ID, Notes._ID);
		sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
		sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
		sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
		sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);
	}
	private static class DatabaseHelper extends SQLiteOpenHelper
	{
		//构造函数-创建数据库
		DatabaseHelper(Context context)
		{
			super(context, DATABASE_NAME, null, DATABASE_VERSION);
		}
		//创建表
		@Override
		public void onCreate(SQLiteDatabase db)
		{
			db.execSQL(CREATE_TABLE);
		}
		//更新数据库
		@Override
		public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
		{
			db.execSQL("DROP TABLE IF EXISTS notes");
			onCreate(db);
		}
	}
	@Override
	public boolean onCreate()
	{
		mOpenHelper = new DatabaseHelper(getContext());
		return true;
	}
	@Override
	//查询操作
	public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
	{
		SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
		switch (sUriMatcher.match(uri))
		{
			case NOTES:
				qb.setTables(NOTES_TABLE_NAME);
				qb.setProjectionMap(sNotesProjectionMap);
				break;

			case NOTE_ID:
				qb.setTables(NOTES_TABLE_NAME);
				qb.setProjectionMap(sNotesProjectionMap);
				qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
				break;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		String orderBy;
		if (TextUtils.isEmpty(sortOrder))
		{
			orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
		}
		else
		{
			orderBy = sortOrder;
		}
		SQLiteDatabase db = mOpenHelper.getReadableDatabase();
		Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
		c.setNotificationUri(getContext().getContentResolver(), uri);
		return c;
	}
	@Override
	// 如果有自定义类型,必须实现该方法
	public String getType(Uri uri)
	{
		switch (sUriMatcher.match(uri))
		{
			case NOTES:
				return Notes.CONTENT_TYPE;

			case NOTE_ID:
				return Notes.CONTENT_ITEM_TYPE;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
	}
	@Override
	//插入数据库
	public Uri insert(Uri uri, ContentValues initialValues)
	{
		if (sUriMatcher.match(uri) != NOTES)
		{
			throw new IllegalArgumentException("Unknown URI " + uri);
		}
		ContentValues values;
		if (initialValues != null)
		{
			values = new ContentValues(initialValues);
		}
		else
		{
			values = new ContentValues();
		}
		Long now = Long.valueOf(System.currentTimeMillis());

		if (values.containsKey(NotePad.Notes.CREATEDDATE) == false)
		{
			values.put(NotePad.Notes.CREATEDDATE, now);
		}
		if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false)
		{
			values.put(NotePad.Notes.MODIFIEDDATE, now);
		}
		if (values.containsKey(NotePad.Notes.TITLE) == false)
		{
			Resources r = Resources.getSystem();
			values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
		}
		if (values.containsKey(NotePad.Notes.NOTE) == false)
		{
			values.put(NotePad.Notes.NOTE, "");
		}
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
		if (rowId > 0)
		{
			Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
			getContext().getContentResolver().notifyChange(noteUri, null);
			return noteUri;
		}
		throw new SQLException("Failed to insert row into " + uri);
	}
	@Override
	//删除数据
	public int delete(Uri uri, String where, String[] whereArgs)
	{
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri))
		{
			case NOTES:
				count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
				break;

			case NOTE_ID:
				String noteId = uri.getPathSegments().get(1);
				count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
				break;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
	@Override
	//更新数据
	public int update(Uri uri, ContentValues values, String where, String[] whereArgs)
	{
		SQLiteDatabase db = mOpenHelper.getWritableDatabase();
		int count;
		switch (sUriMatcher.match(uri))
		{
			case NOTES:
				count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
				break;

			case NOTE_ID:
				String noteId = uri.getPathSegments().get(1);
				count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
				break;

			default:
				throw new IllegalArgumentException("Unknown URI " + uri);
		}
		getContext().getContentResolver().notifyChange(uri, null);
		return count;
	}
}

 

3:Activity01

package com.yarin.android.Examples_06_07;

import android.app.Activity;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.view.Gravity;
import android.widget.Toast;

public class Activity01 extends Activity
{
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		
		/* 插入数据 */
		ContentValues values = new ContentValues();
        values.put(NotePad.Notes.TITLE, "title1");
        values.put(NotePad.Notes.NOTE, "NOTENOTE1");
		getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);

		values.clear();
        values.put(NotePad.Notes.TITLE, "title2");
        values.put(NotePad.Notes.NOTE, "NOTENOTE2");
		getContentResolver().insert(NotePad.Notes.CONTENT_URI, values);
		
		/* 显示 */
		displayNote();
	}
	
	private void displayNote()
	{
		String columns[] = new String[] { NotePad.Notes._ID, 
										  NotePad.Notes.TITLE, 
										  NotePad.Notes.NOTE, 
										  NotePad.Notes.CREATEDDATE, 
										  NotePad.Notes.MODIFIEDDATE };
		Uri myUri = NotePad.Notes.CONTENT_URI;
		Cursor cur = managedQuery(myUri, columns, null, null, null);
		if (cur.moveToFirst())
		{
			String id = null;
			String title = null;
			do
			{
				id = cur.getString(cur.getColumnIndex(NotePad.Notes._ID));
				title = cur.getString(cur.getColumnIndex(NotePad.Notes.TITLE));
				Toast toast=Toast.makeText(this, "TITLE:"+id + "NOTE:" + title, Toast.LENGTH_LONG);
				toast.setGravity(Gravity.TOP|Gravity.CENTER, 0, 40);
				toast.show();
			}
			while (cur.moveToNext());
		}
	}

}

 

4:AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.yarin.android.Examples_06_07" android:versionCode="1" android:versionName="1.0">
<application android:icon="@drawable/icon" android:label="@string/app_name">
<provider android:name="NotePadProvider" android:authorities="com.google.provider.NotePad"/>
<activity android:name=".Activity01" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<data android:mimeType="vnd.android.cursor.dir/vnd.google.note"/>
</intent-filter>
<intent-filter>
<data android:mimeType="vnd.android.cursor.item/vnd.google.note"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="5"/>
</manifest>

 

 部分内容摘自:http://java-admin.iteye.com/blog/803394

分享到:
评论

相关推荐

    Android Content Provider详解及示例代码

    Android:Content Provider的使用。 1、Content Provider 简介 2、使用现成的Content Provider 3、定义自己的Content Provider 一、Content Provider 简介 我们说Android应用程序的四个核心组件是:Activity、...

    Android中使用Content Provider组件访问通讯录中的联系人和添加联系人案例详解

    在Android系统中,Content Provider是四大组件之一,它扮演着数据共享的角色,使得不同应用程序间可以安全地共享数据。本文将深入探讨如何使用Content Provider组件来访问和操作Android设备上的通讯录,特别是针对...

    Android内容提供者(Content provider)

    **Android内容提供者(Content Provider)详解** 在Android系统中,数据共享是应用程序间交互的重要方式,而Android内容提供者(Content Provider)正是实现这一功能的关键组件。Content Provider作为Android四大...

    android MediaProvider和MediaScanner详解

    MediaProvider是Android系统中用于管理媒体文件的Content Provider,而MediaScanner则是与之协同工作的一个后台服务,它负责扫描媒体文件并更新系统数据库。 首先,从AndroidManifest.xml文件的分析可知,...

    《android系统应用开发详解》

    3. **数据存储**:Android支持多种数据存储方式,包括Shared Preferences、SQLite数据库、文件系统和Content Provider。书中将深入讨论这些存储方式的适用场景、优缺点及使用方法。 4. **网络通信**:Android应用...

    android四大组件详解

    Android四大组件详解 Android 应用程序由一些零散的有联系的组件组成,通过一个工程 manifest 绑定在一起。在 manifest 中,描述了每一个组件以及组件的作用,其中有 6 个组件,它们是 Android 应用程序的基石: ...

    四大组件 Activity Service content provider broadcast receiver

    ### 四大组件详解:Activity、Service、Content Provider与Broadcast Receiver #### 一、Activity **定义:** Activity是Android应用程序中的四大基本组件之一,它代表一个屏幕界面,用户可以直接与其进行交互。每...

    《Android应用开发详解》源码_文档讲解

    第8章 Android广播事件处理 Broadcast Receiver 第9章 Android中的数据存取 第10章 Content Provider 第11章 Android中的多媒体应用 第12章 Android中的图形图像 第13章 Android中的互联网应用 第14章 Android中的...

    Android应用开发详解.pdf

    根据提供的标题“Android应用开发详解.pdf”以及描述“Android应用开发详解.pdf”,我们可以推断这份文档主要涵盖了关于Android平台上的应用程序开发的相关知识和技术。虽然提供的部分内容似乎并不包含具体的信息,...

    基于Android FileProvider 属性配置详解及FileProvider多节点问题

    基于Android FileProvider 属性配置详解及FileProvider多节点问题 Android FileProvider 是 Android 7.0 及更高版本中用于文件共享的组件,主要用于解决 Android 7.0 及更高版本中私有存储的限制问题。在 Android ...

    android应用开发详解 【郭宏志】 pdf

    根据提供的信息,“Android应用开发详解”这本书被描述为非常适合初学者的一本书籍,也是某位读者接触到的第一本关于Android开发的书籍。从标题和描述中我们可以推断出这本书主要介绍了Android应用开发的基础知识...

    Android入门到精通详解 (带目录)

    对于数据存储,Android提供了多种方式,包括Shared Preferences、SQLite数据库、文件系统和Content Provider。理解这些存储机制的优缺点,以及在何种场景下选择哪种方式,是提升应用性能的关键。 此外,你还会接触...

    Android应用开发详解

    《Android应用开发详解》 作者:郭宏志 编著 内容简介 本书分为三个部分,包括基础篇、技术篇和应用篇。由浅入深地讲述了Android应用开发的方方面面。 第一篇 基础篇 第1章 Android概述 Android概述,讲述了...

    Android 底层接口与驱动开发技术详解 相关资料

    此外,Android的系统服务,如Activity Manager、Window Manager、Content Provider等,都与底层接口有密切关系。理解这些服务的工作原理和调用方式,可以帮助开发者更好地实现系统级功能,例如权限管理、多任务调度...

    Android数据存储之FileProvider

    **Android数据存储之FileProvider详解** 在Android应用开发中,数据存储是一个不可或缺的部分。FileProvider是一种特殊类型的ContentProvider,它允许应用程序安全地分享私有文件,如图片、视频或其他二进制数据,...

    Android应用开发详解教材源码(下册)

    8. **内容提供者(Content Provider)**:内容提供者是Android中用于共享数据的机制,允许不同应用之间读写数据。例如,联系人应用就是通过内容提供者暴露其数据供其他应用访问。 9. **多线程与AsyncTask**:...

    安卓课程content povider

    【Android课程:Content Provider详解】 在安卓开发中,Content Provider是一个至关重要的组件,它是四大组件之一,负责在应用程序之间共享数据。本课程将深入探讨Content Provider的原理与实践,帮助开发者掌握这...

    Android核心技术与实例详解 随书源码

    第10章:可能讲解了Android中的内容提供者(Content Provider),它是Android四大组件之一,用于在不同应用间共享数据。这章可能包含如何创建和使用Content Provider的步骤。 第5章:这章可能涵盖Android的生命周期...

Global site tag (gtag.js) - Google Analytics