求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
  
 
 
     
   
分享到
android LiveFolder(活动文件夹) 完全解析
 

作者:byandby ,发布于2012-8-20

 

探索活动文件夹

活动文件夹是在SDK1.5中引入的,支持开发人员在设备的默认打开屏幕(我们将其称为设备的主页)上公开 ContentProvider,如联系人信息、笔记和媒体。将ContentProvider(比如Android的 contactsContentProvider)在主页上公开为活动文件夹之后,在联系人数据库中添加、删除或修改联系人时,此活动文件夹能够刷新自身所包含的内容。

Android中的活动文件夹对ContentProvider的作用就相当于RSS阅读器对发布网站的作用。ContentProvider也是类似于根据URI提供信息的网站。随着网站的迅速增加,每个网站都会以独特的方式发布自己的信息,这就需要集中多个网站的信息,以便用户可以通过单一阅读器了解最新发展动态。为此,RSS应运而生。RSS强制在不同的信息集之间提供一种通用的使用模式。有了通用模式,你只需设计一次阅读器,就可以使用它阅读任何内容,只要该内容具有统一的结构即可。

活动文件夹在概念上也没有什么不同。就像 RSS阅读器为所发布的网站内容提桶通用的接口一样,活动文件夹也为Android中的 ContentProvider定义一种通用接口。只要 ContentProvider遵守此协议,Android就能够在设备的主页上创建活动文件夹图标来表示该 ContentProvider。当用户单击此活动文件夹图标时,系统将联系 ContentProvider。ContentProvider 应该会返回一个游标。根据活动文件夹契约,此游标必须具有一组预定义的列。此游标通过 ListView 或 GridView直观地显示出来。

android活动文件夹 E文名 android LiveFolder live活 活动的意思 为什么说它是活的,因为它可以根据我们后台数据库的变化更新自身 更新UI 这样无论什么时候显示的内容都是最新的。 比如 我们删除了一条联系人信息,我们的 Live Foler马上也会 更新。是马上 而且你也不用做任何操作 它自己会更新。至于 具体的效果 大家还是下载源码运行一下 就明白了。

Live Folder的工作原理如下。

(1) 首先在主页上创建一个图标,表示来自ContentProvier的一组行。通过为图标指定一个URI来进行连接。

(2) 当用户单击该图标时,系统接受URI 并用它调用ContentProvider。ContentProvider通过游标(Cursor)返回一组行。

(3) 只要此游标包含Live Foler想要的列(比如名称、描述和在单击该行时调用的程序),系统就会以ListView或GridView的形式呈现这些行。

(4) 因为在基础数据存储更改时,ListView和GridView能够更新自己的数据,所以这些视图为 “活的”,“活动文件夹” 也因此而得名。

在活动文件夹中有两个重要的原则。第一个原则是,列名称在各个游标中是相同的。此原则使Android能够同等地对待面向活动文件夹的所有游标。第二个原则是,Android视图知道如何查找基础游标数据中的更新,并相应地更改自身。第二个原则不是活动文件夹所特有的,适用于Android中所有的视图,尤其是依赖于游标的视图。上面是一个活动文件夹的一些概念了,下面介绍用户如何使用活动文件夹。

用户如何使用活动文件夹

活动文件夹通过设备的主页向用户公开。用户可以按照下面的顺序来使用活动文件夹。

(1) 打开android模拟器 来到主页 (默认屏幕)

(2) 转到主页的上下文菜单。通过在主页的空白处进行长单击(按住不撒手 大约2秒钟),就可以看到上下文菜单了。

(3) 找到一个名为 Folders(中文名就叫文件夹) 的上下文菜单选项,单击可以查看可能可用的活动文件夹。

(4) 从列表中选择并单击希望在主页上公开的活动文件夹名称。这会在主页上创建一个图标来表示所选的活动文件夹。

(5) 单击在第4步中设置的活动文件夹图标,调出 ListView或GridView中的信息(该活动文件夹表示的数据)行。

(6) 单击一行以调用知道如何显示该行数据的应用程序。

(7) 使用该应用程序显示的更多菜单选项查看或操作目标选项。也可以使用应用程序的菜单选项创建它支持的任何新项。

(8) 请注意,活动文件夹显示区域会自动反应对一个或多个项所做的更改。

下面针对上边的每一步我们来看一些图片

打开android模拟器 来到主页 (默认屏幕)

转到主页的上下文菜单。通过在主页的空白处进行长单击(按住不撒手 大约2秒钟),就可以看到上下文菜单了。

找到一个名为 Folders(中文名就叫 文件夹) 的上下文菜单选项,单击可以查看可能可用的活动文件夹。

从列表中选择并单击希望在主页上公开的活动文件夹名称。这会在主页上创建一个图标来表示所选的活动文件夹。

单击在第4步中设置的活动文件夹图标,调出 ListView或GridView中的信息(该活动文件夹表示的数据)行。

单击一行以调用知道如何显示该行数据的应用程序。

使用该应用程序显示的更多菜单选项查看或操作目标选项。也可以使用应用程序的菜单选项创建它支持的任何新项。

编辑联系人,请注意,活动文件夹显示区域会自动反应对一个或多个项所做的更改。

构建活动文件夹

上边了解了一些活动文件夹的基本概念之后,接下来介绍如何构建活动文件夹。构建了活动文件夹之后,可以在主页上为该活动文件夹创建一个图标。我们还将介绍活动文件夹 “活动” 的原理。

要构建活动文件夹,需要两样东西:一个活动和一个专门的ContentProvider。Android使用此活动的 “ 标签” 来填充可用活动文件夹列表。Android还调用此活动来获得一个URI,这个URI将被调用来显示一组行。

活动提供的URI 应该指向负责返回行的专门的ContentProvider。该ContentProvider通过一个定义良好的游标返回这些行。我们要求游标 “定义良好”, 因为游标应该具有一组已知的预定义列名称。

通常,将这两项打包到一个应用程序中,将后将该程序部署到设备上。还需要一些支持文件才能使所有的这一切生效。 我们将使用一个例子来演示和解释这些概念,这个例子包含以下文件。

AndroidManifest.xml:好像所有的android程序都需要这个文件。。。。。。。。。

AllContactsLiveFolderCreatorActivity.java:此Activity 的功能简单说 就是来创建一个 Live Folder。

MyContactsProvider.java:此ContentProvider将对返回联系人游标的活动文件夹URI 进行响应。这个ContentProvider内部使用了 Android随带的联系人的 ContentProvider。

MyCursor.java:这个专门的游标知道在基础数据更改时如何执行 requery。

BetterCursorWrapper.java: MyCursor需要此文件来编排 requery。

SimpleActivity.java:这是一个简单的activity类 它是一个可选文件,可用于在开发项目时进行测试。在最终的部署中不需要此文件。

下面我们来分别介绍每一个文件。

1. AndroidManifest.xml

Xml代码

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="xiaohang.zhimeng" android:versionCode="1" android:versionName="1.0">
	<uses-sdk android:minSdkVersion="10" />
	<application android:icon="@drawable/icon" android:label="@string/app_name">
		<activity android:name=".SimpleActivity" android:label="@string/app_name">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<!-- LIVE FOLDERS -->
		<activity android:name=".AllContactsLiveFolderCreatorActivity"
			android:label="My live folder" android:icon="@drawable/contacts">
			<intent-filter>
				<action android:name="android.intent.action.CREATE_LIVE_FOLDER" />
				<category android:name="android.intent.category.DEFAULT" />
			</intent-filter>
		</activity>
		<provider android:authorities="com.ai.livefolders.contacts"
			android:multiprocess="true" android:name=".MyContactsProvider" />
	</application>
	<uses-permission android:name="android.permission.READ_CONTACTS" />
</manifest> 

根据活动文件夹协议,CREATE_LIVE_FOLDER Intent 允许主页的上下文菜单将 AllContactsLiveFolderCreatorActivity 显示为一个标题为 “My live foler” 的选项。单击此菜单选项将在主页上创建一个图标。AllContactsLiveFolderCreatorActivity 负责定义此图标,其中将包含一个图像和一个标签。在本例子中,AllContactsLiveFolderCreatorActivity 中的代码将此标签指定为 Contacts LF。下面让我们看看创建活动文件夹的类AllContactsLiveFolderCreatorActivity。

Java代码

package xiaohang.zhimeng;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.LiveFolders;

public class AllContactsLiveFolderCreatorActivity extends Activity {

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);

		final Intent intent = getIntent();
		final String action = intent.getAction();
		System.out.println("action is " + action);
		if (LiveFolders.ACTION_CREATE_LIVE_FOLDER.equals(action)) {
			// 设置本Activity返回的结果
			setResult(
					RESULT_OK,
					createLiveFolder(MyContactsProvider.CONTACTS_URI,
							"Contacts LF", R.drawable.contacts));
		} else {
			setResult(RESULT_CANCELED);
		}
		finish();
	}

	private Intent createLiveFolder(Uri uri, String name, int icon) {
		final Intent intent = new Intent();
		intent.setData(uri);
		// 设置LiveFolder 的Name(这个名字是显示在手机的主页上的)
		intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_NAME, name);
		// 设置LiveFolder 的图标
		intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_ICON,
				Intent.ShortcutIconResource.fromContext(this, icon));
		// 指定LiveFolder 显示的模式 这里用List以列表的形式显示
		intent.putExtra(LiveFolders.EXTRA_LIVE_FOLDER_DISPLAY_MODE,
				LiveFolders.DISPLAY_MODE_LIST);
		return intent;
	}
} 

2. AllContactsLiveFolderCreatorActivity 类只有一个功能:担当活动文件夹的生成程序或创建程序。可以将它视为活动文件夹的模板。每次单击此活动(通过主页上下文菜单的Folers选项)时,它都会在主页上生成一个活动文件夹。此活动告诉调用方(在这个例子中为主页或LiveFolder框架) 活动文件夹名称、为活动文件夹图标使用的图像、提供可用数据的 URI,以及显示模式 (列表或网格)。然后,活动文件夹框架负责在主页上创建活动文件夹的图标。

API里边已经明确的说明 为我们的LiveFoler(活动文件夹) 提供内容的 ContentProvider 经过查询返回的Cursor对象必须 包含以下 列名称,也可以把它理解成使用LiveFolder的一个契约 我来是来张API 的截图比较合适。

大家仔细 看看 有些是必须的 有些是不必须的

createLiveFoler 方法主要设置调用它的Intent的值。当此 Intent返回到调用方时,调用方将知道以下信息。

活动文件夹的名称

活动文件夹所使用的图标

显示模式:列表或网格

数据或为数据调用的内容URI

这些信息足够用来创建我们的活动文件夹了。当用户单击活动文件夹的图标时,系统将调用 URI 来检索数据。此 URI 所标识的 ContentProvider提供了标准化的游标。接下来就介绍该ContentProvider的代码:MyContactsProvider类。

3. MyContactsProvider.java类

MyContactsProvider 具有以下功能。

(1) 按此方式标识传入的 URI: content:// com.ai.livefolders.contacts。

(2) 对Android提供的由content://com.android.contacts/contacts 标识的联系人 ContentProvider进行内部调用。

(3) 读取游标的所有行并将其映射回一个游标(比如 MatrixCursor),后者具有活动文件夹框架所需的合适的列名称。

(4) 将 MattixCursor包装到另一个游标中,以便经过包装的游标上的 requery 在需要时调用联系人 ContentProvider。

MyContactsProvider的代码清单如下

Java代码

package xiaohang.zhimeng;

import android.content.ContentProvider;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
import android.provider.BaseColumns;
import android.provider.ContactsContract;
import android.provider.LiveFolders;
import android.util.Log;

public class MyContactsProvider extends ContentProvider {

	public static final String AUTHORITY = "com.ai.livefolders.contacts";

	// Uri that goes as input to the live-folder creation
	public static final Uri CONTACTS_URI = Uri.parse("content://" + AUTHORITY
			+ "/contacts");

	// To distinguish this URI
	private static final int TYPE_MY_URI = 0;
	private static final UriMatcher URI_MATCHER;
	static {
		URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
		URI_MATCHER.addURI(AUTHORITY, "contacts", TYPE_MY_URI);
	}

	@Override
	public boolean onCreate() {
		return true;
	}

	@Override
	public int bulkInsert(Uri uri, ContentValues[] values) {
		return 0;
	}

	// Set of columns needed by a live folder
	// This is the live-folder contract
	private static final String[] CURSOR_COLUMNS = new String[] {
			BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION,
			LiveFolders.INTENT, LiveFolders.ICON_PACKAGE,
			LiveFolders.ICON_RESOURCE };

	// In case there are no rows
	// use this stand-in as an error message
	// Notice it has the same set of columns of a live folder
	private static final String[] CURSOR_ERROR_COLUMNS = new String[] {
			BaseColumns._ID, LiveFolders.NAME, LiveFolders.DESCRIPTION };

	// The error message row
	private static final Object[] ERROR_MESSAGE_ROW = new Object[] { -1, // id
			"No contacts found", // name
			"Check your contacts database" // description
	};

	// The error cursor to use
	private static MatrixCursor sErrorCursor = new MatrixCursor(
			CURSOR_ERROR_COLUMNS);
	static {
		// 为 CURSOR_ERROR_COLUMNS 添加给定的列值
		sErrorCursor.addRow(ERROR_MESSAGE_ROW);
	}

	// Columns to be retrieved from the contacts database
	private static final String[] CONTACTS_COLUMN_NAMES = new String[] {
			ContactsContract.PhoneLookup._ID,
			ContactsContract.PhoneLookup.DISPLAY_NAME,
			ContactsContract.PhoneLookup.TIMES_CONTACTED,
			ContactsContract.PhoneLookup.STARRED,
			ContactsContract.PhoneLookup.PHOTO_ID };

	@Override
	public Cursor query(Uri uri, String[] projection, String selection,
			String[] selectionArgs, String sortOrder) {
		// Figure out the uri and return error if not matching
		int type = URI_MATCHER.match(uri);
		if (type == UriMatcher.NO_MATCH) {
			// 如果URI 匹配出错则返回错误信息
			return sErrorCursor;
		}

		Log.i("ss", "query called");

		try {
			// 调用 loadNewData方法进行查询 返回 匹配好的MatrixCursor对象
			MatrixCursor mc = loadNewData(this);
			// setNotificationUri方法用来指定一个Uri以观察它的变化
			// 参数一:需要一个ContentResolver对象,从上下文对象获得
			// 参数二:要监视的URI
			mc.setNotificationUri(getContext().getContentResolver(),
					Uri.parse("content://com.android.contacts/contacts/"));
			MyCursor wmc = new MyCursor(mc, this);
			return wmc;
		} catch (Exception e) {
			System.out.println("Print yi chang ");
			// 返回我们的错误对象
			return sErrorCursor;
		}

	}

	public static MatrixCursor loadNewData(ContentProvider cp) {
		//
		MatrixCursor mc = new MatrixCursor(CURSOR_COLUMNS);
		Cursor allContacts = null;
		try {
			// 说一下query方法的参数
			/*
			 * 参数一:要查询的URI 我们查询的完整URI 为"content://com.android.contacts/contacts"
			 * 也就是所有的联系人参数二:都要查询那些列 上边我们已经定义好参数三:本质上就是一个WHERE子句,它以SQL
			 * WHERE子句(不包含WHERE本身) 的格式声明要返回的行 传递null将返回给定URI 的所有行
			 * 参数四:用来替换where子句中的?号参数五:指定排序的方式
			 */
			allContacts = cp
					.getContext()
					.getContentResolver()
					.query(ContactsContract.Contacts.CONTENT_URI,
							CONTACTS_COLUMN_NAMES, null, null,
							ContactsContract.PhoneLookup.DISPLAY_NAME);
			while (allContacts.moveToNext()) {
				// 返回第二列的值 也就是 ContactsContract.PhoneLookup.TIMES_CONTACTED的值
				// the zero-based index
				String timesContacted = "Times contacted: "
						+ allContacts.getInt(2);

				Object[] rowObject = new Object[] {
						allContacts.getLong(0), // id
						allContacts.getString(1), // name
						timesContacted, // description
						Uri.parse("content://com.android.contacts/contacts/"
								+ allContacts.getLong(0)), // intent uri
						cp.getContext().getPackageName(), // package 返回应用程序的包名称
						R.drawable.contacts // 返回我们LiveFolder的图标
				};
				// 给我们的 MatrixCursor 对象mc 添加给定的列值
				mc.addRow(rowObject);
			}
			// 返回MatrixCursor对象
			return mc;
		} finally {
			// 关闭Cursor对象, 并释放所有资源并使其无效
			allContacts.close();
		}
	}

	// 如果有自定义类型,必须实现此方法 这里我们 用的是 系统定义好的类型
	@Override
	public String getType(Uri uri) {
		// indicates the MIME type for a given URI
		// targeted for this wrapper provier
		// This usually looks like
		// "vnd.android.cursor.dir/vnd.google.note"
		return ContactsContract.Contacts.CONTENT_TYPE;

	}

	@Override
	public Uri insert(Uri uri, ContentValues values) {
		throw new UnsupportedOperationException(
				"no insert as this is just a wrapper");
	}

	@Override
	public int delete(Uri uri, String selection, String[] selectionArgs) {
		throw new UnsupportedOperationException(
				"no delete as this is just a wrapper");
	}

	@Override
	public int update(Uri uri, ContentValues values, String selection,
			String[] selectionArgs) {
		throw new UnsupportedOperationException(
				"no update as this is just a wrapper");
	}

} 

大部分字段大家也都应该明白,可能INTENT项有点迷惑。先说一下 timesContacted 它是用来记录 我们的联系人呼叫我我们几次 比如你电话存着 妈妈的电话 timesContacted就记录着 妈妈给你打了几个电话,或者说呼叫了你几次,还有就连这个也可以时时更新,所以说还是比较强大滴。

INTENT 字段实际上是一个字符串,指向 ContentProvider 中该项的URL。在用户单击该项时,Android将使用此URL 来调用VIEW操作。此字符串字段称为 INTENT 字段是因为,在内部,Android会从字符串 URI 派生 INTENT。

另外请大家注意,上面的MyContactsProvider 包含了下面几行代码

Java代码

    MatrixCursor mc = loadNewData(this);
    mc.setNotificationUri(getContext().getContentResolver(), Uri.parse(
    "content://com.android.contacts/contacts/")); 

函数 loadNewData() 从联系人提供程序获取一组联系人并创建 MatrixCursor,MatrixCursor对象包含我们需要的列。这段代码然后告诉 MatrixCursor 向 ContentResolver 注册自身,以便在URI (content://com.android.contacts/contacts/) 所指向的数据以任何形式发生变化时,ContentResolver能够提醒游标也就是我们的Cursor对象。

将 MatrixCursor 包装到我们自己的游标中也很重要。

Java代码

MyCursor wmc = new MyCursor(mc,this);

MyCursor对象是我们自己定义的一个Cursor对象,这里要理解为什么需要包装游标,需要了解视图如何更新更改的内容。ContentProvider(比如Contacts)通常通过将一个URI 注册为 query方法实现的一部分,告诉游标它需要监视更改。这是通过 cursor.setNotificationUri完成的。游标然后将向 ContentProvider 注册此URI 及它的所有子URI。然后,当在 ContentProvider 上发生插入或删除操作时,插入或删除操作的代码需要发出一个事件,表示特定URI 所标识的行中的数据发生了更改。

这将出发游标通过 requery进行更新,视图也将相应更新。遗憾的是, MatrixCursor不适用此 requery。SQLiteCursor适用于它,但我们无法在这里使用 SQLiteCursor,因为我们已将这些列映射到了一组新列。

为了解决这一限制,我们将MatrixCursor包装到一个游标包装器中,并重写 requery 方法以丢弃内部的 MatrixCursor,并使用更新的数据创建一个新游标。更明确的讲,每次数据更改时,我们都希望获得新的 MatrixCursor。但我们仅向 Android活动文件夹框架返回所包装的外部游标。这将告诉活动文件夹框架只有一个游标,但在后台,当数据更改时我们会创建新游标,我们下面来说说这两个类。

4. MyCursor.java

请注意,MyCursor最开始使用一个 MatrixCursor进行初始化。在requery上, MyCursor 将回调提供程序来返回一个 MatrixCursor。然后,新 MatrixCursor 将使用 set 方法替代旧 MatrixCursor。

说明:可以通过重写 MatrixCursor的requery来完成此任务,但该类无法清除数据并重新启动。所以这是一种合理的解决办法。(请注意,MyCursor扩展了 BetterCursorWrapper,接下来将讨论。)

MyCursor 源代码

Java代码

package xiaohang.zhimeng;

import android.content.ContentProvider;
import android.database.MatrixCursor;

public class MyCursor extends BetterCursorWrapper {

	private ContentProvider mcp = null;

	public MyCursor(MatrixCursor mc, ContentProvider inCp) {
		super(mc);
		mcp = inCp;
	}

	@Override
	public boolean requery() {
		MatrixCursor mc = MyContactsProvider.loadNewData(mcp);
		this.setInternalCursor(mc);
		return super.requery();
	}

} 

现在看一下 BetterCursorWrapper类,了解如何包装游标。

5. BetterCursorWrapper.java

BetterCursorWrapper类 非常类似于 Android数据库框架中的 CursorWrapper类。但我们还需要 CursorWrapper 所缺少的另外两项功能。首先,它没有提供 set方法来替换 requery 方法中的内部游标。其次, CursorWrapper 不是CrossProcessCursor。活动文件夹需要 CrossProcessCursor,而不是普通游标,因为活动文件夹会跨进程边界进行工作。

BetterCursorWrapper源代码

Java代码

package xiaohang.zhimeng;

import android.content.ContentResolver;
import android.database.CharArrayBuffer;
import android.database.ContentObserver;
import android.database.CrossProcessCursor;
import android.database.CursorWindow;
import android.database.DataSetObserver;
import android.net.Uri;
import android.os.Bundle;

public class BetterCursorWrapper implements CrossProcessCursor {

	// Holds the internal cursor to delegate methods to
	protected CrossProcessCursor internalCursor;

	public CursorWindow getWindow() {
		return internalCursor.getWindow();
	}

	public boolean onMove(int oldPosition, int newPosition) {
		return internalCursor.onMove(oldPosition, newPosition);
	}

	public int getCount() {
		return internalCursor.getCount();
	}

	public int getPosition() {
		return internalCursor.getPosition();
	}

	public boolean move(int offset) {
		return internalCursor.move(offset);
	}

	public boolean moveToPosition(int position) {
		return internalCursor.moveToPosition(position);
	}

	public boolean moveToFirst() {
		return internalCursor.moveToFirst();
	}

	public boolean moveToLast() {
		return internalCursor.moveToLast();
	}

	public boolean moveToNext() {
		return internalCursor.moveToNext();
	}

	public boolean moveToPrevious() {
		return internalCursor.moveToPrevious();
	}

	public boolean isFirst() {
		return internalCursor.isFirst();
	}

	public boolean isLast() {
		return internalCursor.isLast();
	}

	public boolean isBeforeFirst() {
		return internalCursor.isBeforeFirst();
	}

	public boolean isAfterLast() {
		return internalCursor.isAfterLast();
	}

	public int getColumnIndex(String columnName) {
		return internalCursor.getColumnIndex(columnName);
	}

	public int getColumnIndexOrThrow(String columnName)
			throws IllegalArgumentException {
		return internalCursor.getColumnIndexOrThrow(columnName);
	}

	public String getColumnName(int columnIndex) {
		return internalCursor.getColumnName(columnIndex);
	}

	public String[] getColumnNames() {
		return internalCursor.getColumnNames();
	}

	public int getColumnCount() {
		return internalCursor.getColumnCount();
	}

	public byte[] getBlob(int columnIndex) {
		return internalCursor.getBlob(columnIndex);
	}

	public String getString(int columnIndex) {
		return internalCursor.getString(columnIndex);
	}

	public void copyStringToBuffer(int columnIndex, CharArrayBuffer buffer) {
		internalCursor.copyStringToBuffer(columnIndex, buffer);
	}

	public short getShort(int columnIndex) {
		return internalCursor.getShort(columnIndex);
	}

	public int getInt(int columnIndex) {
		return internalCursor.getInt(columnIndex);
	}

	public long getLong(int columnIndex) {
		return internalCursor.getLong(columnIndex);
	}

	public float getFloat(int columnIndex) {
		return internalCursor.getFloat(columnIndex);
	}

	public double getDouble(int columnIndex) {
		return internalCursor.getDouble(columnIndex);
	}

	public boolean isNull(int columnIndex) {
		return internalCursor.isNull(columnIndex);
	}

	public void deactivate() {
		internalCursor.deactivate();
	}

	public boolean requery() {
		return internalCursor.requery();
	}

	public void close() {
		internalCursor.close();
	}

	public boolean isClosed() {
		return internalCursor.isClosed();
	}

	public void registerContentObserver(ContentObserver observer) {
		internalCursor.registerContentObserver(observer);
	}

	public void unregisterContentObserver(ContentObserver observer) {
		internalCursor.unregisterContentObserver(observer);
	}

	public void registerDataSetObserver(DataSetObserver observer) {
		internalCursor.registerDataSetObserver(observer);
	}

	public void unregisterDataSetObserver(DataSetObserver observer) {
		internalCursor.unregisterDataSetObserver(observer);
	}

	public void setNotificationUri(ContentResolver cr, Uri uri) {
		internalCursor.setNotificationUri(cr, uri);
	}

	public boolean getWantsAllOnMoveCalls() {
		return internalCursor.getWantsAllOnMoveCalls();
	}

	public Bundle getExtras() {
		return internalCursor.getExtras();
	}

	public Bundle respond(Bundle extras) {
		return internalCursor.respond(extras);
	}

	// Constructor takes a crossprocesscursor as an input
	public BetterCursorWrapper(CrossProcessCursor inCursor) {
		this.setInternalCursor(inCursor);
	}

	// You can reset in one of the derived class's method
	public void setInternalCursor(CrossProcessCursor inCursor) {
		internalCursor = inCursor;
	}

	@Override
	public void fillWindow(int pos, CursorWindow winow) {
		internalCursor.fillWindow(pos, winow);
	}

}  

大家看前几个方法就行了,后边方法都没有用到 实现CrossProcessCursor这个接口就会实现这些方法。大家也可以用 Eclipse 自动生成一下,将光标放在 internalCursor上。用鼠标右键单击并选择 Source---》GenerateDelegate Methods。Eclipse随后将填充该类剩余部分。现在看一下完成此示例需要的一个简单activity.

6 .SimpleActivity.java

SimpleActivity.java 不是活动文件夹必须的类,但在项目中包含它可以为所有项目提供一种通用模式。此外,它支持在通过 Eclipse调试时,部署应用程序并在屏幕上查看它。

SimpleActivity 源代码

Java代码

package xiaohang.zhimeng;

import android.app.Activity;
import android.os.Bundle;

public class SimpleActivity extends Activity {
	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
	}
} 

简单的 XML 布局文件

Xml代码

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
	android:orientation="vertical" android:layout_width="fill_parent"
	android:layout_height="fill_parent">
	<TextView android:layout_width="fill_parent"
		android:layout_height="wrap_content" android:text="Live Folder Example" />
</LinearLayout>  

现在,通过Eclipse构建、部署和运行示例活动文件夹项目所需的所有类都已就绪。我们可以运行试试了,刚打开会打开一个Activity 就是我们上边的那个SimpleActivity 然后我们切换到主页 按照我们 最开始 介绍的步骤就可以建立 活动文件夹了,另外觉得觉得这个例子还有不足的地方,比如 我们可以自己定义一些联系人的头像 然后从数据库读取出来,让每个联系人都显示自己的头像。


相关文章

深度解析:清理烂代码
如何编写出拥抱变化的代码
重构-使代码更简洁优美
团队项目开发"编码规范"系列文章
相关文档

重构-改善既有代码的设计
软件重构v2
代码整洁之道
高质量编程规范
相关课程

基于HTML5客户端、Web端的应用开发
HTML 5+CSS 开发
嵌入式C高质量编程
C++高级编程

 
分享到
 
 
     


android人机界面指南
Android手机开发(一)
Android手机开发(二)
Android手机开发(三)
Android手机开发(四)
iPhone消息推送机制实现探讨
手机软件测试用例设计实践
手机客户端UI测试分析
手机软件自动化测试研究报告
更多...   


Android高级移动应用程序
Android应用开发
Android系统开发
手机软件测试
嵌入式软件测试
Android软、硬、云整合


领先IT公司 android开发平台最佳实践
北京 Android开发技术进阶
某新能源领域企业 Android开发技术
某航天公司 Android、IOS应用软件开发
阿尔卡特 Linux内核驱动
艾默生 嵌入式软件架构设计
西门子 嵌入式架构设计
更多...