您的位置:首页 > 移动开发 > Android开发

Android四大基本组件之 ContentProvider

2016-04-15 12:43 585 查看
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中赋予其更广阔的含义,先看个例子,如下:

content://com.example.project:200/folder/subfolder/etc
\---------/ \---------------------------/ \---/ \--------------------------/
scheme host port path
\--------------------------------/
authority

将其分为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 Uriinsert (Uri url, ContentValues values)Inserts a row into a table at the given URL.
final intdelete (Uri url, String where, String[] selectionArgs)Deletes row(s) specified by a content URI.
final Cursorquery (Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)Query the given URI, returning a Cursor over the result set.
final intupdate (Uri uri, ContentValues values, String where, String[] selectionArgs)Update row(s) in a content URI.
下面利用实例做进一步说明:

1:NotePad

Java代码



1 package com.yarin.android.Examples_06_07;
2
3 import android.net.Uri;
4 import android.provider.BaseColumns;
5
6 public class NotePad
7 {
8     //ContentProvider的uri
9     public static final String    AUTHORITY    = "com.google.provider.NotePad";
10
11     private NotePad(){}
12
13     // 定义基本字段
14     public static final class Notes implements BaseColumns
15     {
16         private Notes(){}
17
18         public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY + "/notes");
19
20         // 新的MIME类型-多个
21         public static final String CONTENT_TYPE  = "vnd.android.cursor.dir/vnd.google.note";
22
23         // 新的MIME类型-单个
24         public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/vnd.google.note";
25
26         public static final String DEFAULT_SORT_ORDER = "modified DESC";
27
28         //字段
29         public static final String    TITLE  = "title";
30         public static final String    NOTE   = "note";
31         public static final String    CREATEDDATE   = "created";
32         public static final String    MODIFIEDDATE   = "modified";
33     }
34 }


2:NotePadProvider

Java代码









1 package com.yarin.android.Examples_06_07;
2
3 import java.util.HashMap;
4
5 import android.content.ContentProvider;
6 import android.content.ContentUris;
7 import android.content.ContentValues;
8 import android.content.Context;
9 import android.content.UriMatcher;
10 import android.content.res.Resources;
11 import android.database.Cursor;
12 import android.database.SQLException;
13 import android.database.sqlite.SQLiteDatabase;
14 import android.database.sqlite.SQLiteOpenHelper;
15 import android.database.sqlite.SQLiteQueryBuilder;
16 import android.net.Uri;
17 import android.text.TextUtils;
18
19 import com.yarin.android.Examples_06_07.NotePad.Notes;
20
21 public class NotePadProvider extends ContentProvider
22 {
23     private static final String             TAG                 = "NotePadProvider";
24     // 数据库名
25     private static final String             DATABASE_NAME       = "note_pad.db";
26     private static final int                DATABASE_VERSION    = 2;
27     // 表名
28     private static final String             NOTES_TABLE_NAME    = "notes";
29     private static HashMap<String, String>    sNotesProjectionMap;
30     private static final int                NOTES               = 1;
31     private static final int                NOTE_ID             = 2;
32     private static final UriMatcher         sUriMatcher;
33     private DatabaseHelper  mOpenHelper;
34     //创建表SQL语句
35     private static final String             CREATE_TABLE="CREATE TABLE "
36                                                         + NOTES_TABLE_NAME
37                                                         + " (" + Notes._ID
38                                                         + " INTEGER PRIMARY KEY,"
39                                                         + Notes.TITLE
40                                                         + " TEXT,"
41                                                         + Notes.NOTE
42                                                         + " TEXT,"
43                                                         + Notes.CREATEDDATE
44                                                         + " INTEGER,"
45                                                         + Notes.MODIFIEDDATE
46                                                         + " INTEGER" + ");";
47
48     static
49     {
50         sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
51         sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
52         sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);
53
54         sNotesProjectionMap = new HashMap<String, String>();
55         sNotesProjectionMap.put(Notes._ID, Notes._ID);
56         sNotesProjectionMap.put(Notes.TITLE, Notes.TITLE);
57         sNotesProjectionMap.put(Notes.NOTE, Notes.NOTE);
58         sNotesProjectionMap.put(Notes.CREATEDDATE, Notes.CREATEDDATE);
59         sNotesProjectionMap.put(Notes.MODIFIEDDATE, Notes.MODIFIEDDATE);
60     }
61     private static class DatabaseHelper extends SQLiteOpenHelper
62     {
63         //构造函数-创建数据库
64         DatabaseHelper(Context context)
65         {
66             super(context, DATABASE_NAME, null, DATABASE_VERSION);
67         }
68         //创建表
69         @Override
70         public void onCreate(SQLiteDatabase db)
71         {
72             db.execSQL(CREATE_TABLE);
73         }
74         //更新数据库
75         @Override
76         public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
77         {
78             db.execSQL("DROP TABLE IF EXISTS notes");
79             onCreate(db);
80         }
81     }
82     @Override
83     public boolean onCreate()
84     {
85         mOpenHelper = new DatabaseHelper(getContext());
86         return true;
87     }
88     @Override
89     //查询操作
90     public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
91     {
92         SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
93         switch (sUriMatcher.match(uri))
94         {
95             case NOTES:
96                 qb.setTables(NOTES_TABLE_NAME);
97                 qb.setProjectionMap(sNotesProjectionMap);
98                 break;
99
100             case NOTE_ID:
101                 qb.setTables(NOTES_TABLE_NAME);
102                 qb.setProjectionMap(sNotesProjectionMap);
103                 qb.appendWhere(Notes._ID + "=" + uri.getPathSegments().get(1));
104                 break;
105
106             default:
107                 throw new IllegalArgumentException("Unknown URI " + uri);
108         }
109         String orderBy;
110         if (TextUtils.isEmpty(sortOrder))
111         {
112             orderBy = NotePad.Notes.DEFAULT_SORT_ORDER;
113         }
114         else
115         {
116             orderBy = sortOrder;
117         }
118         SQLiteDatabase db = mOpenHelper.getReadableDatabase();
119         Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy);
120         c.setNotificationUri(getContext().getContentResolver(), uri);
121         return c;
122     }
123     @Override
124     // 如果有自定义类型,必须实现该方法
125     public String getType(Uri uri)
126     {
127         switch (sUriMatcher.match(uri))
128         {
129             case NOTES:
130                 return Notes.CONTENT_TYPE;
131
132             case NOTE_ID:
133                 return Notes.CONTENT_ITEM_TYPE;
134
135             default:
136                 throw new IllegalArgumentException("Unknown URI " + uri);
137         }
138     }
139     @Override
140     //插入数据库
141     public Uri insert(Uri uri, ContentValues initialValues)
142     {
143         if (sUriMatcher.match(uri) != NOTES)
144         {
145             throw new IllegalArgumentException("Unknown URI " + uri);
146         }
147         ContentValues values;
148         if (initialValues != null)
149         {
150             values = new ContentValues(initialValues);
151         }
152         else
153         {
154             values = new ContentValues();
155         }
156         Long now = Long.valueOf(System.currentTimeMillis());
157
158         if (values.containsKey(NotePad.Notes.CREATEDDATE) == false)
159         {
160             values.put(NotePad.Notes.CREATEDDATE, now);
161         }
162         if (values.containsKey(NotePad.Notes.MODIFIEDDATE) == false)
163         {
164             values.put(NotePad.Notes.MODIFIEDDATE, now);
165         }
166         if (values.containsKey(NotePad.Notes.TITLE) == false)
167         {
168             Resources r = Resources.getSystem();
169             values.put(NotePad.Notes.TITLE, r.getString(android.R.string.untitled));
170         }
171         if (values.containsKey(NotePad.Notes.NOTE) == false)
172         {
173             values.put(NotePad.Notes.NOTE, "");
174         }
175         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
176         long rowId = db.insert(NOTES_TABLE_NAME, Notes.NOTE, values);
177         if (rowId > 0)
178         {
179             Uri noteUri = ContentUris.withAppendedId(NotePad.Notes.CONTENT_URI, rowId);
180             getContext().getContentResolver().notifyChange(noteUri, null);
181             return noteUri;
182         }
183         throw new SQLException("Failed to insert row into " + uri);
184     }
185     @Override
186     //删除数据
187     public int delete(Uri uri, String where, String[] whereArgs)
188     {
189         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
190         int count;
191         switch (sUriMatcher.match(uri))
192         {
193             case NOTES:
194                 count = db.delete(NOTES_TABLE_NAME, where, whereArgs);
195                 break;
196
197             case NOTE_ID:
198                 String noteId = uri.getPathSegments().get(1);
199                 count = db.delete(NOTES_TABLE_NAME, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
200                 break;
201
202             default:
203                 throw new IllegalArgumentException("Unknown URI " + uri);
204         }
205         getContext().getContentResolver().notifyChange(uri, null);
206         return count;
207     }
208     @Override
209     //更新数据
210     public int update(Uri uri, ContentValues values, String where, String[] whereArgs)
211     {
212         SQLiteDatabase db = mOpenHelper.getWritableDatabase();
213         int count;
214         switch (sUriMatcher.match(uri))
215         {
216             case NOTES:
217                 count = db.update(NOTES_TABLE_NAME, values, where, whereArgs);
218                 break;
219
220             case NOTE_ID:
221                 String noteId = uri.getPathSegments().get(1);
222                 count = db.update(NOTES_TABLE_NAME, values, Notes._ID + "=" + noteId + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs);
223                 break;
224
225             default:
226                 throw new IllegalArgumentException("Unknown URI " + uri);
227         }
228         getContext().getContentResolver().notifyChange(uri, null);
229         return count;
230     }
231 }


View Code

3:Activity01

Java代码







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());

}

}

}

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代码







<?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>

<?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://lpqsun-126-com.iteye.com/blog/1257643
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: