- 浏览: 1697277 次
- 性别:
- 来自: 北京
文章分类
- 全部博客 (159)
- android 2D (13)
- android 控件 (12)
- android UI (16)
- android 动画 (5)
- android 线程 (3)
- android 数据存储 (15)
- android 基础 (13)
- android xml解析 (1)
- android 多媒体开发 (4)
- android 服务 (4)
- android 安全 (1)
- android WebKit以及相关 (3)
- android 电话 (2)
- android 首选项 (5)
- java基础 (16)
- java 多线程 (1)
- java IO (7)
- android工具使用篇 (1)
- android素材资源区 (1)
- android教程资源区 (1)
- java_android异常记录 (5)
- android问题记录 (1)
- android 推荐资源 (1)
- android 源码篇 (3)
- android SDK (2)
- Google Map For Android (2)
- android 项目问题 (2)
- git (0)
- android API 变化 (1)
- MyEclipse (2)
- Swing组件 (1)
- 活法 (0)
- 其它 (2)
- linux (7)
- 菜鸟的java学习笔记 (0)
- 网络 (0)
- 健康 (1)
- Eclipse在Ubuntu下无法双击启动解决办法 (1)
最新评论
-
tydyz:
引用
android SQLiteOpenHelper使用示例 -
tydyz:
[color=red][/color]
android SQLiteOpenHelper使用示例 -
tydyz:
[flash=200,200][flash=200,200][ ...
android SQLiteOpenHelper使用示例 -
梁家大丫头:
写的还不错,不过不是我需要的。
android 理解和使用自定义权限 -
love_java_cc:
牛逼,太齐全了,收藏
MyEclipse 快捷键大全
如果大家对 ContentProvider 还不熟悉的话 先看看这两篇文章把 ContentProvider整的明白些 看起来会更顺利。 【android 自定义 Content Provider示例】http://byandby.iteye.com/blog/837466 【android Content Provider的使用】http://byandby.iteye.com/blog/836212
探索活动文件夹
活动文件夹是在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
根据活动文件夹协议,CREATE_LIVE_FOLDER Intent 允许主页的上下文菜单将
AllContactsLiveFolderCreatorActivity 显示为一个标题为 “My live foler” 的选项。单击此菜单选项将在主页上创建一个图标。AllContactsLiveFolderCreatorActivity 负责定义此图标,其中将包含一个图像和一个标签。在本例子中,AllContactsLiveFolderCreatorActivity 中的代码将此标签指定为 Contacts LF。下面让我们看看创建活动文件夹的类AllContactsLiveFolderCreatorActivity。
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的代码清单如下
大部分字段大家也都应该明白,可能INTENT项有点迷惑。先说一下 timesContacted 它是用来记录 我们的联系人呼叫我我们几次 比如你电话存着 妈妈的电话 timesContacted就记录着 妈妈给你打了几个电话,或者说呼叫了你几次,还有就连这个也可以时时更新,所以说还是比较强大滴。
INTENT 字段实际上是一个字符串,指向 ContentProvider 中该项的URL。在用户单击该项时,Android将使用此URL 来调用VIEW操作。此字符串字段称为 INTENT 字段是因为,在内部,Android会从字符串 URI 派生 INTENT。
另外请大家注意,上面的MyContactsProvider 包含了下面几行代码
函数 loadNewData() 从联系人提供程序获取一组联系人并创建 MatrixCursor,MatrixCursor对象包含我们需要的列。这段代码然后告诉 MatrixCursor 向 ContentResolver 注册自身,以便在URI (content://com.android.contacts/contacts/) 所指向的数据以任何形式发生变化时,ContentResolver能够提醒游标也就是我们的Cursor对象。
将 MatrixCursor 包装到我们自己的游标中也很重要。
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 源代码
现在看一下 BetterCursorWrapper类,了解如何包装游标。
5. BetterCursorWrapper.java
BetterCursorWrapper类 非常类似于 Android数据库框架中的 CursorWrapper类。但我们还需要 CursorWrapper 所缺少的另外两项功能。首先,它没有提供 set方法来替换 requery 方法中的内部游标。其次, CursorWrapper 不是CrossProcessCursor。活动文件夹需要 CrossProcessCursor,而不是普通游标,因为活动文件夹会跨进程边界进行工作。
BetterCursorWrapper源代码
大家看前几个方法就行了,后边方法都没有用到 实现CrossProcessCursor这个接口就会实现这些方法。大家也可以用 Eclipse 自动生成一下,将光标放在 internalCursor上。用鼠标右键单击并选择 Source---》GenerateDelegate Methods。Eclipse随后将填充该类剩余部分。现在看一下完成此示例需要的一个简单activity.
6 .SimpleActivity.java
SimpleActivity.java 不是活动文件夹必须的类,但在项目中包含它可以为所有项目提供一种通用模式。此外,它支持在通过 Eclipse调试时,部署应用程序并在屏幕上查看它。
SimpleActivity 源代码
简单的 XML 布局文件
现在,通过Eclipse构建、部署和运行示例活动文件夹项目所需的所有类都已就绪。我们可以运行试试了,刚打开会打开一个Activity 就是我们上边的那个SimpleActivity 然后我们切换到主页 按照我们 最开始 介绍的步骤就可以建立 活动文件夹了,另外觉得觉得这个例子还有不足的地方,比如 我们可以自己定义一些联系人的头像 然后从数据库读取出来,让每个联系人都显示自己的头像。 欢迎大家 讨论 批评 指点。
源码已上传
探索活动文件夹
活动文件夹是在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 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。
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的代码清单如下
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 包含了下面几行代码
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 包装到我们自己的游标中也很重要。
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 源代码
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源代码
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 源代码
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 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 然后我们切换到主页 按照我们 最开始 介绍的步骤就可以建立 活动文件夹了,另外觉得觉得这个例子还有不足的地方,比如 我们可以自己定义一些联系人的头像 然后从数据库读取出来,让每个联系人都显示自己的头像。 欢迎大家 讨论 批评 指点。
源码已上传
- LiveFolder_Demo.rar (85.6 KB)
- 下载次数: 206
发表评论
-
android Preferences使用示例二
2010-12-09 14:54 16813Preperences 是一种应用程序内部轻量级的 ... -
android 自定义 Content Provider示例
2010-12-09 13:04 18603我们大家都知道 ... -
android SQLiteOpenHelper使用示例
2010-12-08 01:08 51018我们大家都知道Android平台提供给我们一个数据库辅 ... -
android Content Provider的使用
2010-12-07 23:31 5700Content Provider 属于A ... -
android 读取Resources 和 Assets 中的文件
2010-12-07 15:50 33647在Android平台下,除了对应用程序的私有文件夹中的 ... -
android 私有文件夹 文件的写入与读取
2010-12-07 15:05 19919在介绍如何在Android平台下进行文件的读取之前, ... -
android SQLite使用SQLiteOpenHelper类对数据库进行操作
2010-12-07 13:58 103952一、 SQLite介绍 SQLite是android内置的一个 ... -
android SQLite数据库基本操作示例
2010-12-06 23:36 21221这个例子实现了一个完整的数据库操作示例。首先运行项 ... -
android SQLite编程详解
2010-12-05 18:51 8333SQLite 数据库功能非常强大,使用起来也非常方便 ... -
android SQLite简介
2010-12-05 00:05 2798一些概念性的东西 ... -
android 数据存储之 Network
2010-12-04 23:03 3460这篇文章演示2 ... -
android 数据存储之 Files
2010-12-04 18:43 3105Android中可以在设备本身的存储设备或者外接的 ... -
android 数据存储之 Shared Preferences
2010-12-04 12:22 7400Shared Preferences类似于我们常 ... -
android 数据存储初探
2010-12-04 00:02 1864一些概念性的 ...
相关推荐
android下选择图片文件夹并显示对应文件夹下的图片文件,有需要的可以参考一下。 android下选择图片文件夹并显示对应文件夹下的图片文件,有需要的可以参考一下。 android下选择图片文件夹并显示对应文件夹下的图片...
android 删除文件夹及文件夹下面的所有文件
在Android平台上,从指定文件夹显示图片涉及到一系列的步骤和技术,包括文件系统操作、图片加载库的使用以及UI设计。以下是对这个主题的详细讲解: 首先,我们需要理解Android的文件系统结构。Android设备通常有两...
本文将深入探讨如何在Android中创建和删除SD卡上的文件夹,以及如何利用ListView和BaseAdapter来显示这些文件夹信息。 首先,让我们了解如何获取SD卡的路径。在Android中,SD卡通常被视为外部存储,可以通过`...
android多国语言文件夹文件汇总[收集].pdf
在Android开发中,有时我们需要在应用内部存储一些资源文件,如音频、文本或图片,而`assets`文件夹就是用于存放这些非编译型资源的一个特殊目录。在本例中,我们将探讨如何从`assets`文件夹中读取音频文件,并提供...
简单样例,Android10外部储存文件夹创建以及文件创建Demo。git: https://gitee.com/fshaoooo/android10createdir.git。不会用Git的,可以直接在CSDN下载。
思路: 获取当前目录下的文件列表,然后显示到listview上面,当点击某个文件夹,则重新加载listview的内容为该文件夹下的文件列表,如果点击文件,则选择打开文件...实现和小米自带文件夹浏览器需求的文件夹浏览器实现
在Android平台上实现类似iPhone的文件夹分裂效果,可以让用户的交互体验更加接近iOS系统,提高应用的用户友好性。这个过程涉及到Android的自定义Launcher(桌面启动器)开发,包括对ListView、Animation以及触摸事件...
先看看效果图: package wuwang.tools.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.text.DecimalFormat;...im
总的来说,理解如何从assets文件夹读取和解析XML是Android开发中的一个重要技能。它能帮助开发者灵活地处理非标准资源,提高应用的可扩展性和灵活性。通过实践这个示例,开发者可以学习到如何在实际项目中应用Pull...
在Android系统中,开发一个自定义的文件管理器是一项常见的任务,特别是在Android 7.0(API级别24)及更高版本中。本教程将详细解释如何创建一个模仿真实文件管理器的应用,重点在于获取文件夹路径。我们将讨论以下...
在Android开发中,进行大文件下载时,为了提高效率并充分利用设备资源,通常会采用多线程下载技术。此外,为了提升用户体验,断点续传功能也显得尤为重要,尤其是在网络不稳定或者用户中断下载后,可以从上次停止的...
文件文件夹批量蓝牙分享 android的蓝牙批量分享,可以参考
在Android平台上,获取本地文件夹信息是开发过程中常见的需求,特别是在处理文件管理和数据存储时。以下将详细讲解如何实现这个功能。 首先,我们要了解Android的文件系统结构。Android使用Linux内核,因此其文件...
在Android平台上,解析并显示Microsoft Office格式的文件(如doc, docx, xls, xlsx)是一项常见的需求,尤其在移动应用开发中。这个任务通常涉及到将这些文档转换为更易于处理的格式,例如HTML,以便在Android的...