创建并使用一个地震Content Provider

  

已经创建了一个应用程序,它能够显示最近的地震列表。现在,你有一个极好的机会来和其它应用程序共享这些信息。

 

通过一个Content Provider来暴露这些数据,你或其他人都可以创建基于这些数据的应用程序,而不用加倍网络流量和相关的XML解析。

 

创建Content Provider

 

接下来的例子显示了如何创建一个地震Content Provider。每一个quake都将储存在一个SQLite数据库。

 

1. 打开Earthquake工程,创建一个新的EarthquakeProvider类,扩展Content Provider。重写onCreategetTypequeryinsertdeleteupdate方法。

 

package com.paad.earthquake;

import android.content.*;

import android.database.Cursor;

import android.database.SQLException;

import android.database.sqlite.SQLiteOpenHelper;

import android.database.sqlite.SQLiteDatabase;

import android.database.sqlite.SQLiteQueryBuilder;

import android.net.Uri;

import android.text.TextUtils;

import android.util.Log;

public class EarthquakeProvider extends ContentProvider {

 

@Override

public boolean onCreate() {

}

 

@Override

public String getType(Uri url) {

}

 

@Override

public Cursor query(Uri url, String[] projection, String selection, String[] selectionArgs, String sort) {

}

 

@Override

public Uri insert(Uri _url, ContentValues _initialValues) {

}

 

@Override

public int delete(Uri url, String where, String[] whereArgs) {

}

 

@Override

public int update(Uri url, ContentValues values, String where, String[] wArgs) {

}

}

 

2. 为这个Provider定义一个Content URI。这个URI将用于在程序组件中,使用ContentResolver来访问这个Content Provider

 

public static final Uri CONTENT_URI = Uri.parse(“content://com.paad.provider.earthquake/earthquakes”);

 

3. 创建数据库,用来存储地震数据。在EarthquakeProvider类中,创建一个新的SQLiteDatabase实例,并且暴露列名称和索引的公共变量。包含一个SQLiteOpenHelper的扩展类来管理数据库的创建和版本控制。

 

// The underlying database

private SQLiteDatabase earthquakeDB;

private static final String TAG = “EarthquakeProvider”;

private static final String DATABASE_NAME = “earthquakes.db”;

private static final int DATABASE_VERSION = 1;

private static final String EARTHQUAKE_TABLE = “earthquakes”;

 

// Column Names

public static final String KEY_ID = “_id”;

public static final String KEY_DATE = “date”;

public static final String KEY_DETAILS = “details”;

public static final String KEY_LOCATION_LAT = “latitude”;

public static final String KEY_LOCATION_LNG = “longitude”;

public static final String KEY_MAGNITUDE = “magnitude”;

public static final String KEY_LINK = “link”;

 

// Column indexes

public static final int DATE_COLUMN = 1;

public static final int DETAILS_COLUMN = 2;

public static final int LONGITUDE_COLUMN = 3;

public static final int LATITUDE_COLUMN = 4;

public static final int MAGNITUDE_COLUMN = 5;

public static final int LINK_COLUMN = 6;

// Helper class for opening, creating, and managing

// database version control

private static class earthquakeDatabaseHelper extends SQLiteOpenHelper {

private static final String DATABASE_CREATE =“create table “ + EARTHQUAKE_TABLE + “ (“

+ KEY_ID + “ integer primary key autoincrement, “

+ KEY_DATE + “ INTEGER, “

+ KEY_DETAILS + “ TEXT, “

+ KEY_LOCATION_LAT + “ FLOAT, “

+ KEY_LOCATION_LNG + “ FLOAT, “

+ KEY_MAGNITUDE + “ FLOAT, “

+ KEY_LINK + “ TEXT);”;

 

public earthquakeDatabaseHelper(Context context, String name, CursorFactory factory, int version) {

super(context, name, factory, version);

}

 

@Override

public void onCreate(SQLiteDatabase db) {

db.execSQL(DATABASE_CREATE);

}

 

@Override

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

Log.w(TAG, “Upgrading database from version “ + oldVersion + “ to “

+ newVersion + “, which will destroy all old data”);

db.execSQL(“DROP TABLE IF EXISTS “ + EARTHQUAKE_TABLE);

onCreate(db);

}

}

 

4. 创建一个UriMatcher来处理不同不同的URI请求。包含对整个数据集(QUAKES)和单个记录的索引(QUAKE_ID)的查询和交互的支持。

 

// Create the constants used to differentiate between the different URI

// requests.

private static final int QUAKES = 1;

private static final int QUAKE_ID = 2;

private static final UriMatcher uriMatcher;

// Allocate the UriMatcher object, where a URI ending in ‘earthquakes’

// will correspond to a request for all earthquakes, and ‘earthquakes’

// with a trailing ‘/[rowID]’ will represent a single earthquake row.

static {

uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

uriMatcher.addURI(“com.paad.provider.Earthquake”, “earthquakes”, QUAKES);

uriMatcher.addURI(“com.paad.provider.Earthquake”, “earthquakes/#”, QUAKE_ID);

}

 

5. 重写getType方法来返回每个支持的URI结构的字符串。

 

@Override

public String getType(Uri uri) {

switch (uriMatcher.match(uri)) {

case QUAKES:

return “vnd.android.cursor.dir/vnd.paad.earthquake”;

case QUAKE_ID:

return “vnd.android.cursor.item/vnd.paad.earthquake”;

default:

throw new IllegalArgumentException(“Unsupported URI: “ + uri);

}

}

 

6. 重写ProvideronCreate方法,来创建一个数据库辅助类的实例,并打开一个数据库的连接。

 

@Override

public boolean onCreate() {

Context context = getContext();

earthquakeDatabaseHelper dbHelper;

dbHelper = new earthquakeDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);

earthquakeDB = dbHelper.getWritableDatabase();

return (earthquakeDB == null) ? false : true;

}

 

7. 实现查询和交互的函数。首先是查询方法;它应该解析发送的请求(是所有的内容还是单行),并应用selectionprojectionsortorder等参数来返回一个Cursor

 

@Override

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

SQLiteQueryBuilder qb = new SQLiteQueryBuilder();

qb.setTables(EARTHQUAKE_TABLE);

// If this is a row query, limit the result set to the passed in row.

switch (uriMatcher.match(uri)) {

case QUAKE_ID:

qb.appendWhere(KEY_ID + “=” + uri.getPathSegments().get(1));

break;

default: break;

}

 

// If no sort order is specified sort by date / time

String orderBy;

if (TextUtils.isEmpty(sort))

{

orderBy = KEY_DATE;

}

else

{

orderBy = sort;

}

 

// Apply the query to the underlying database.

Cursor c = qb.query(earthquakeDB,projection,selection, selectionArgs,null, null,orderBy);

 

// Register the contexts ContentResolver to be notified if

// the cursor result set changes.

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

 

// Return a cursor to the query result.

return c;

}

 

8. 现在实现insertdeleteupdate方法。在这种情况下,这个过程基本上是练习将Content Provider的交互请求映射到数据库上。

 

@Override

public Uri insert(Uri _uri, ContentValues _initialValues) {

// Insert the new row, will return the row number if

// successful.

long rowID = earthquakeDB.insert(EARTHQUAKE_TABLE, “quake”,_initialValues);

// Return a URI to the newly inserted row on success.

if (rowID > 0)

{

Uri uri = ContentUris.withAppendedId(CONTENT_URI, rowID);

getContext().getContentResolver().notifyChange(uri, null);

return uri;

}

throw new SQLException(“Failed to insert row into “ + _uri);

}

 

@Override

public int delete(Uri uri, String where, String[] whereArgs) {

int count;

switch (uriMatcher.match(uri)) {

case QUAKES:

count = earthquakeDB.delete(EARTHQUAKE_TABLE, where, whereArgs);

break;

case QUAKE_ID:

String segment = uri.getPathSegments().get(1);

count = earthquakeDB.delete(EARTHQUAKE_TABLE, KEY_ID + “=”+ segment

+ (!TextUtils.isEmpty(where) ? “ AND (“

+ where + ‘)’ : “”), whereArgs);

break;

default: throw new IllegalArgumentException(“Unsupported URI: “ + uri);

}

getContext().getContentResolver().notifyChange(uri, null);

return count;

}

 

@Override

public int update(Uri uri, ContentValues values, String where,String[] whereArgs) {

int count;

switch (uriMatcher.match(uri)) {

case QUAKES:

count = earthquakeDB.update(EARTHQUAKE_TABLE, values,where, whereArgs);

break;

case QUAKE_ID:

String segment = uri.getPathSegments().get(1);

count = earthquakeDB.update(EARTHQUAKE_TABLE, values, KEY_ID + “=” + segment

+ (!TextUtils.isEmpty(where) ? “ AND (“

+ where + ‘)’ : “”), whereArgs);

break;

default: throw new IllegalArgumentException(“Unknown URI “ + uri);

}

getContext().getContentResolver().notifyChange(uri, null);

return count;

}

 

9. 当Content Provider完成时,在程序的manifestapplication标签中添加一个节点来注册它。

 

<provider android:name=”.EarthquakeProvider” android:authorities=”com.paad.provider.earthquake” />

 

使用Provider

 

现在,你可以更新Earthquake Activity来使用EarthquakeProvider来储存quake,并使用它们来填入ListView

 

1. 在Earthquake Activity中,更新addNewQuake方法。它应该使用程序的ContentResolver来插入每个地震信息。把现有的数组控制逻辑移动到新的addQuakeToArray方法中。

 

private void addNewQuake(Quake _quake) {

ContentResolver cr = getContentResolver();

// Construct a where clause to make sure we don’t already have this

// earthquake in the provider.

String w = EarthquakeProvider.KEY_DATE + “ = “ + _quake.getDate().getTime();

// If the earthquake is new, insert it into the provider.

Cursor c = cr.query(EarthquakeProvider.CONTENT_URI,null, w, null, null);

int dbCount = c.getCount();

c.close();

if (dbCount > 0) (应该是 == 0 的判断)

{

ContentValues values = new ContentValues();

values.put(EarthquakeProvider.KEY_DATE, _quake.getDate().getTime());

values.put(EarthquakeProvider.KEY_DETAILS, _quake.getDetails());

double lat = _quake.getLocation().getLatitude();

double lng = _quake.getLocation().getLongitude();

values.put(EarthquakeProvider.KEY_LOCATION_LAT, lat);

values.put(EarthquakeProvider.KEY_LOCATION_LNG, lng);

values.put(EarthquakeProvider.KEY_LINK, _quake.getLink());

values.put(EarthquakeProvider.KEY_MAGNITUDE, _quake.getMagnitude());

cr.insert(EarthquakeProvider.CONTENT_URI, values);

earthquakes.add(_quake);(似乎多插入了一次。)

addQuakeToArray(_quake);

}

}

 

private void addQuakeToArray(Quake _quake) {

if (_quake.getMagnitude() > minimumMagnitude)

{

// Add the new quake to our list of earthquakes.

earthquakes.add(_quake);

// Notify the array adapter of a change.

aa.notifyDataSetChanged();

}

}

 

2. 创建一个loadQuakesFromProvider方法来从EarthquakeProvider加载所有的地震数据,并且使用addQuakeToArray方法来将它们插入到数组列表中。

 

private void loadQuakesFromProvider() {

// Clear the existing earthquake array

earthquakes.clear();

 

ContentResolver cr = getContentResolver();

// Return all the saved earthquakes

 

Cursor c = cr.query(EarthquakeProvider.CONTENT_URI, null, null, null, null);

if (c.moveToFirst())

{

do

{

// Extract the quake details.

Long datems = c.getLong(EarthquakeProvider.DATE_COLUMN);

String details;

details = c.getString(EarthquakeProvider.DETAILS_COLUMN);

Float lat = c.getFloat(EarthquakeProvider.LATITUDE_COLUMN);

Float lng = c.getFloat(EarthquakeProvider.LONGITUDE_COLUMN);

Double mag = c.getDouble(EarthquakeProvider.MAGNITUDE_COLUMN);

String link = c.getString(EarthquakeProvider.LINK_COLUMN);

Location location = new Location(“dummy”);

location.setLongitude(lng);

location.setLatitude(lat);

Date date = new Date(datems);

Quake q = new Quake(date, details, location, mag, link);

addQuakeToArray(q);

} while(c.moveToNext());

}

c.close();

}

 

3. 在onCreate方法中调用loadQuakeFromProvider方法来初始化EarthquakeListView

 

@Override

public void onCreate(Bundle icicle) {

super.onCreate(icicle);

setContentView(R.layout.main);

earthquakeListView =

(ListView)this.findViewById(R.id.earthquakeListView);

earthquakeListView.setOnItemClickListener(new OnItemClickListener() {

public void onItemClick(AdapterView _av, View _v, int _index, long arg3) {

selectedQuake = earthquakes.get(_index);

showDialog(QUAKE_DIALOG);

}

});

int layoutID = android.R.layout.simple_list_item_1;

aa = new ArrayAdapter<Quake>(this, layoutID , earthquakes);

earthquakeListView.setAdapter(aa);

loadQuakesFromProvider();

updateFromPreferences();

refreshEarthquakes();

}

 

4. 最后,对refreshEarthquake方法做一项变更,在清除数组之后,添加新的quake之前,加载保存的地震数据。

 

private void refreshEarthquakes() {

[ ... exiting refreshEarthquakes method ... ]

// Clear the old earthquakes

earthquakes.clear();

loadQuakesFromProvider();

[ ... exiting refreshEarthquakes method ... ]

}

 

posted on 2009-08-10 16:11  xirihanlin  阅读(1352)  评论(0编辑  收藏  举报