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

[每天学点Android开发]为应用程序自定义ContentProvider对象以共享数据

2011-06-24 06:38 411 查看
今日学习任务:以简单的备忘录应用程程序为例,实现ContentProvider,并测试。

涉及的主要内容:1) 创建ContentProvider所需的步骤 2)学习官方实例代码(Note Pad)

1. 如何为自己的应用程序自定义ContentProvider

首先,我们得有数据。所以,需要创建一个SQLite数据库来存储数据。而为了访问数据库,我们需要提供访问数据库的各种接口,如创建,打开,升级等

其次,创建一个类,继承ContentProvider类,并实现其中访问数据的所有方法,包括:1)query():查询 2) insert():插入 3)update():插入 4)delete():删除 5)getType():获得类型 6)onCreate():创建时调用。

最后,定义好的ContentProvider类必须在AndroidManifest.xml里声明后,才能使用。声明中必须添加的参数是授权属性“android:authorities”。

在实际的写代码过程中,目前只能好好研究developer.android.com上面的相关实例代码,学习Google提供的良好规范的代码:

http://developer.android.com/resources/samples/NotePad/src/com/example/android/notepad/index.html

在这个Note pad的例子中,Notepad.java和NotePadProvider.java两个文件是与创建ContentProvider相关的两个文件。其中Notepad.java类定义了用于可以访问的ContentProvider的常量,之所以创建这个文件,我觉得是优化代码架构而把常量写在同一个类中方便调用和访问。而NotePadProvider则主要涉及数据的相关操作,包括数据库的创建,连接以及继承实现ContenProvider类的6个方法。在阅读这部分代码时,对我来说最大的苦难是需要很好地理解URI的原理,只有这样才能看懂Google提供的代码的结构。关于URI的理解请参考官方文档:

http://developer.android.com/guide/topics/providers/content-providers.html#creating 中最后部分:Content URI Summary。

令人欣慰的是,Google提供的实例代码有详细的注释,这样方便了我们去理解和学习。

2. 现在以备忘录程序为例,来实现以上各个部分。

注:假设备忘录程序中只有一张数据表,叫做Memo, 表中有两个字段: _ID 和 MemoContent。

2.1 参考Notepad.java 创建 MemoContract.java 类,定义各种 主要的URI和数据表字段常量。之所以定义这个类,可以参考下面关于该类的注释

package com.memo;
import android.net.Uri;

import android.provider.BaseColumns;

/**

* Defines a contract between the Memo content provider and its clients.

* A contract defines the information that a client needs to access the provider as one or more data tables.

* A contract is a public, non-extendable (final) class that contains constants defining column names and URIs.

* A well-written client depends only on the constants in the contract.

*/

public final class MemoContract {

/**

* identification of the content provider.

*/

public static final String AUTHORITY = "com.memo.MemoProvider";

/**

* This class can not be instantiated

*/

private MemoContract(){

}

/**

* Memo table contract

*/

public static final class Memo implements BaseColumns{

/**

* This class can not be instantiated

*/

private Memo(){

}

/**

* The table name offered by this provider

*/

public static final String TABLE_NAME = "Memo";

/* URI definition */

/**

* The content:// style URL for this table

*/

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

/* MIME definitions */

/**

* The MIME type of {@link #CONTENT_URI} providing a directory of memo.

*/

public static final String CONTENT_TYPE= "vnd.android.cursor.dir/vnd.companyName.memo";

/**

* The MIME type of a {@link #CONTENT_URI} sub-directory of a single memo.

*/

public static final String CONTENT_ITEM_TYPE= "vnd.android.cursor.item/vnd.companyName.memo";

/* Default sort order and column definitions for this table */

/**

* The default sort order for this table

*/

public static final String DEFAULT_SORT_ORDER = _ID+" DESC";

/**

* Column name for the content of the memo

* <P>Type: TEXT</P>

*/

public static final String COLUMN_NAME_CONTENT = "MemoContent";

}

}

2.2 参考NotePadProvider.java创建了MemoProvider类,该类提供了访问数据的主要接口,并继承实现了ContenProvider的query()方法,其它方法类似。详细代码如下:

package com.memo;

import java.util.HashMap;

import com.memo.MemoContract.Memo;

import android.content.ContentProvider;

import android.content.ContentValues;

import android.content.Context;

import android.content.UriMatcher;

import android.database.Cursor;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteOpenHelper;

import android.database.sqlite.SQLiteQueryBuilder;

import android.net.Uri;

import android.text.TextUtils;

import android.util.Log;

/**

* Provides the access to the data of Memo

*/

public class MemoProvider extends ContentProvider {

/**

* a new DbHelper

*/

private DbHelper dbHelper;

/**

* Create and initialize a UriMatcher instance

*/

private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);;

// The incoming URI matches the Memo URI pattern

private static final int MEMOS = 1;

// The incoming URI matches the Memo ID URI pattern
private static final int MEMO_ID = 2;

static{

// Add a pattern that routes URIs terminated with "Memos" to a Memos operation

sUriMatcher.addURI(MemoContract.AUTHORITY, "Memo", MEMOS);

// Add a pattern that routes URIs terminated with "Memos" plus an integer

// to a memo ID operation

sUriMatcher.addURI(MemoContract.AUTHORITY, "Memo/#", MEMO_ID);

}

/**

* A projection map used to select columns from the database

*/

private static HashMap<String, String> ProjectionMap;

/* constants for whole database */

private static final String DATABASE_NAME= "db";

private static final int DATABASE_VERSION= 2;

/* table creation SQL statements */

public static final String CREATE_TABLE_MEMO= "create table "+Memo.TABLE_NAME+" ("

+Memo._ID+" integer primary key autoincrement, "

+Memo.COLUMN_NAME_CONTENT+" text)";

/**

* The helper class which manage the database creation and database version upgrade

*/

private class DbHelper extends SQLiteOpenHelper{

public DbHelper(Context context) {

super(context, DATABASE_NAME, null, DATABASE_VERSION);

}

/**

* Create the data table by executing the SQL statement

*/

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(CREATE_TABLE_MEMO);

}

/**

*

* Demonstrates that the provider must consider what happens when the

* underlying database is changed. In this sample, the database is upgraded

* by destroying the existing data.

* A real application should upgrade the database in place.

*/

@Override

public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {

// Logs that the database is being upgraded

Log.w(DATABASE_NAME, "Upgrading database from version " + oldVersion + " to " + newVersion

+ ", which will destroy all old data");

// Kills the table and existing data

db.execSQL("DROP TABLE IF EXISTS Memo");

// Recreates the database with a new version

onCreate(db);

}

}

/**

*

* Initializes the provider by creating a new DbHelper. onCreate() is called

* automatically when Android creates the provider in response to a resolver request from a

* client.

*/

@Override

public boolean onCreate() {

// Creates a new helper object. Note that the database itself isn't opened until

// something tries to access it, and it's only created if it doesn't already exist.

dbHelper=new DbHelper(getContext());

// Assumes that any failures will be reported by a thrown exception.

return true;

}

/**

* This method is called when a client calls

* {@link android.content.ContentResolver#query(Uri, String[], String, String[], String)}.

* Queries the database and returns a cursor containing the results.

*

* @return A cursor containing the results of the query. The cursor exists but is empty if

* the query returns no results or an exception occurs.

* @throws IllegalArgumentException if the incoming URI pattern is invalid.

*/

@Override

public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,

String sortOrder) {

// Constructs a new query builder and sets its table name

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

/**

* Choose the projection and adjust the "where" clause based on URI pattern-matching.

*/

switch (sUriMatcher.match(uri)) {

// If the incoming URI is for menos, chooses the Memos projection

case MEMOS:

qb.setTables(Memo.TABLE_NAME);

qb.setProjectionMap(ProjectionMap);

break;

/* If the incoming URI is for a single memo identified by its ID, chooses the

* memo ID projection, and appends "_ID = <MemoID>" to the where clause, so that

* it selects that single memo

*/

case MEMO_ID:

qb.setTables(Memo.TABLE_NAME);

qb.setProjectionMap(ProjectionMap);

qb.appendWhere(

Memo._ID + // the name of the ID column

"=" +

// the position of the memo ID itself in the incoming URI

uri.getPathSegments().get(1));

break;

default:

// If the URI doesn't match any of the known patterns, throw an exception.

throw new IllegalArgumentException("Unknown URI " + uri);

}

String orderBy;

// If no sort order is specified, uses the default

if (TextUtils.isEmpty(sortOrder)) {

orderBy = Memo.DEFAULT_SORT_ORDER;

} else {

// otherwise, uses the incoming sort order

orderBy = sortOrder;

}

// Opens the database object in "read" mode, since no writes need to be done.

SQLiteDatabase db = dbHelper.getReadableDatabase();

/*

* Performs the query. If no problems occur trying to read the database, then a Cursor

* object is returned; otherwise, the cursor variable contains null. If no records were

* selected, then the Cursor object is empty, and Cursor.getCount() returns 0.

*/

Cursor c = qb.query(

db, // The database to query

projection, // The columns to return from the query

selection, // The columns for the where clause

selectionArgs, // The values for the where clause

null, // don't group the rows

null, // don't filter by row groups

orderBy // The sort order

);

// Tells the Cursor what URI to watch, so it knows when its source data changes

c.setNotificationUri(getContext().getContentResolver(), uri);

return c;

}

@Override

public int delete(Uri arg0, String arg1, String[] arg2) {

// TODO Auto-generated method stub

return 0;

}

@Override

public String getType(Uri arg0) {

// TODO Auto-generated method stub

return null;

}

@Override

public Uri insert(Uri arg0, ContentValues arg1) {

// TODO Auto-generated method stub

return null;

}

@Override

public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3) {

// TODO Auto-generated method stub

return 0;

}

}

2.3 在AndroidMenifest.xml中声明我们定义的ContentProvider:

<provider android:name="MemoProvider"

android:authorities="com.memo.MemoProvider">
</ provider>

2.4 为了测试我定义的ContentProvider,我们在创建的Main.activity中,利用ContentResolver读取数据,并用ListView显示:参考上一篇博文: /article/5936031.html 代码如下:

package com.memo;

import java.util.ArrayList;

import com.memo.MemoContract.Memo;

import android.app.ListActivity;

import android.database.Cursor;

import android.net.Uri;

import android.os.Bundle;

import android.widget.ArrayAdapter;

import android.widget.ListView;

public class Main extends ListActivity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

Uri memoUri= Memo.CONTENT_URI;

String[] proj1=new String[]{Memo.COLUMN_NAME_CONTENT};

Cursor cur=getContentResolver().query(memoUri,proj1, null, null, null);

//declare a ArrayList object to store the data that will present to the user

ArrayList<String> memoList=new ArrayList<String>();

if(cur.getCount()>0){

while(cur.moveToNext()){

memoList.add(cur.getString(0));

}

}

// binding the data to ListView

setListAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, memoList));

ListView lv=getListView();

lv.setTextFilterEnabled(true);

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐