Android示例程序剖析之记事本(一)

Android SDK提供了很多示例程序,从这些示例代码的阅读和试验中能够学习到很多知识。本系列就是要剖析Android记事本示例程序,用意就是一步步跟着实例进行动手操作,在实践中体会和学习Android开发。该系列共有四篇文章,本文是第一篇。

  前期准备

搭建开发环境,尝试编写"Hello World”,了解Android的基本概念,熟悉Android的API(官方文档中都有,不赘述)。

  记事本程序运行界面

先来简单了解下程序运行的效果:

程序入口点

  类似于win32程序里的WinMain函数,Android自然也有它的程序入口点。它通过在AndroidManifest.xml文件中配置来指明,可以看到名为NotesList的activity节点下有这样一个intent-filter,其action为android.intent.action.MAIN, Category指定为 android.intent.category.LAUNCHER,这就指明了这个activity是作为入口activity,系统查找到它后,就会创建这个activity实例来运行,若未发现就不启动(你可以把MAIN改名字试试)。

XML/HTML代码

  1. <intent-filter>
  2. <action android:name="android.intent.action.MAIN" />
  3. <category android:name="android.intent.category.LAUNCHER" />
  4. </intent-filter>

NotesList详解

就从入口点所在的activity(见图1)开始,可以看到这个activity最重要的功能就是显示日志列表。这个程序的日志都存放在Sqlite数据库中,因此需要读取出所有的日志记录并显示。先来看两个重要的私有数据,第一个PROJECTION字段指明了“日志列表“所关注的数据库中的字段(即只需要ID和Title就可以了)。

Java代码

  1. private static final String[] PROJECTION = new String[] {
  2. Notes._ID, // 0
  3. Notes.TITLE, // 1
  4. };

第二个字段COLUMN_INDEX_TITLE指明title字段在数据表中的索引。

private static final int COLUMN_INDEX_TITLE = 1;

然后就进入第一个调用的函数onCreate。

Java代码

  1. Intent intent = getIntent();
  2. if (intent.getData() == null)
  3. {
  4. intent.setData(Notes.CONTENT_URI);
  5. }

因为NotesList这个activity是系统调用的,此时的intent是不带数据和操作类型的,系统只是在其中指明了目标组件是Notelist,所以这里把“content:// com.google.provider.NotePad/notes”保存到intent里面,这个URI地址指明了数据库中的数据表名(参见以后的NotePadProvider类),也就是保存日志的数据表notes。

Cursor cursor = managedQuery(getIntent().getData(), PROJECTION, null, null, Notes.DEFAULT_SORT_ORDER);

然后调用managedQuery函数查询出所有的日志信息,这里第一个参数就是上面设置的” content:// com.google.provider.NotePad/notes”这个URI,即notes数据表。PROJECTION 字段指明了结果中所需要的字段,Notes.DEFAULT_SORT_ORDER 指明了结果的排序规则。实际上managedQuery并没有直接去查询数据库,而是通过Content Provider来完成实际的数据库操作,这样就实现了逻辑层和数据库层的分离。

Java代码

  1. SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.noteslist_item, cursor,
  2. new String[] { Notes.TITLE }, new int[] { android.R.id.text1 });
  3. setListAdapter(adapter);

查询出日志列表后,构造一个CursorAdapter,并将其作为List View的数据源,从而在界面上显示出日志列表。可以看到,第二个参数是R.layout.noteslist_item,打开对应的noteslist_item.xml文件:

XML/HTML代码

  1. <TextView xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:id="@android:id/text1"
  3. android:layout_width="fill_parent"
  4. android:layout_height="?android:attr/listPreferredItemHeight"
  5. android:textAppearance="?android:attr/textAppearanceLarge"
  6. android:gravity="center_vertical"
  7. android:paddingLeft="5dip"
  8. android:singleLine="true"
  9. />

就是用来显示一条日志记录的TextView,最后两个字段指明了实际的字段映射关系,通过这个TextView来显示一条日志记录的title字段。

  处理“选择日志”事件

既然有了“日志列表”,就自然要考虑如何处理某一条日志的单击事件,这通过重载onListItemClick方法来完成:

Java代码

  1. @Override
  2. protected void onListItemClick(ListView l, View v, int position, long id) {
  3. Uri uri = ContentUris.withAppendedId(getIntent().getData(), id);
  4. String action = getIntent().getAction();
  5. if (Intent.ACTION_PICK.equals(action) || Intent.ACTION_GET_CONTENT.equals(action)) {
  6. // The caller is waiting for us to return a note selected by
  7. // the user.  The have clicked on one, so return it now.
  8. setResult(RESULT_OK, new Intent().setData(uri));
  9. } else {
  10. // Launch activity to view/edit the currently selected item
  11. startActivity(new Intent(Intent.ACTION_EDIT, uri));
  12. }
  13. }

首先通过”content:// com.google.provider.NotePad/notes”和日志的id 号拼接得到选中日志的真正URI,然后创建一个新的Intent,其操作类型为Intent.ACTION_EDIT,数据域指出待编辑的日志URI(这里只分析else块)。

  Intent深度剖析

那么,上面这句startActivity(new Intent(Intent.ACTION_EDIT, uri))执行后会发生什么事情呢?这时候Android系统就跳出来接管了,它会根据intent中的信息找到对应的activity,在这里找到的是NoteEditor这个activity,然后创建这个activity的实例并运行。

那么,Android又是如何找到NoteEditor这个对应的activity的呢?这就是intent发挥作用的时刻了。

new Intent(Intent.ACTION_EDIT, uri)

这里的Intent.ACTION_EDIT=” android.intent.action.EDIT”,另外通过设置断点,我们看下这里的uri值:

可以看到选中的日志条目的URI是:content://com.google.provider.NotePad/notes/1。然后我们再来看下Androidmanfest.xml,其中有这个provider:

XML/HTML代码

  1. <provider android:name="NotePadProvider"
  2. android:authorities="com.google.provider.NotePad"/>

发现没有?它也有com.google.provider.NotePad,这个是content://com.google.provider.NotePad/notes/1的一部分,同时:

XML/HTML代码

  1. <activity android:name="NoteEditor"
  2. android:theme="@android:style/Theme.Light"
  3. android:label="@string/title_note"
  4. android:screenOrientation="sensor"
  5. android:configChanges="keyboardHidden|orientation"
  6. >
  7. <!-- This filter says that we can view or edit the data of
  8. a single note -->
  9. <intent-filter android:label="@string/resolve_edit">
  10. <action android:name="android.intent.action.VIEW" />
  11. <action android:name="android.intent.action.EDIT" />
  12. <action android:name="com.android.notepad.action.EDIT_NOTE" />
  13. <category android:name="android.intent.category.DEFAULT" />
  14. <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
  15. </intent-filter>
  16. <!-- This filter says that we can create a new note inside
  17. of a directory of notes. -->
  18. <intent-filter>
  19. <action android:name="android.intent.action.INSERT" />
  20. <category android:name="android.intent.category.DEFAULT" />
  21. <data android:mimeType="vnd.android.cursor.dir/vnd.google.note" />
  22. </intent-filter>
  23. </activity>

上面第一个intent-filter中有一个action 名为android.intent.action.EDIT,而前面我们创建的Intent也正好是Intent.ACTION_EDIT=” android.intent.action.EDIT”,想必大家已经明白是怎么回事了吧。

  下面就进入activity选择机制了:

  系统从intent中获取道uri,得到了content://com.google.provider.NotePad/notes/1,去掉开始的content:标识,得到com.google.provider.NotePad/notes/1,然后获取前面的com.google.provider.NotePad,然后就到Androidmanfest.xml中找到authorities为com.google.provider.NotePad的provider,这个就是后面要讲的contentprovider,然后就加载这个content provider。

XML/HTML代码

  1. <provider android:name="NotePadProvider"
  2. android:authorities="com.google.provider.NotePad"/>

在这里是NotePadProvider,然后调用NotePadProvider的gettype函数,并把上述URI传给这个函数,函数返回URI所对应的类型(这里返回Notes.CONTENT_ITEM_TYPE,代表一条日志记录,而CONTENT_ITEM_TYPE = " vnd.android.cursor.item/vnd.google.note ")。

Java代码

  1. @Override
  2. public String getType(Uri uri) {
  3. switch (sUriMatcher.match(uri)) {
  4. case NOTES:
  5. return Notes.CONTENT_TYPE;
  6. case NOTE_ID:
  7. return Notes.CONTENT_ITEM_TYPE;
  8. default:
  9. throw new IllegalArgumentException("Unknown URI " + uri);
  10. }
  11. }

上面的sUriMatcher.match是用来检测uri是否能够被处理,而sUriMatcher.match(uri)返回值其实是由决定的。

sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes", NOTES);
        sUriMatcher.addURI(NotePad.AUTHORITY, "notes/#", NOTE_ID);

然后系统使用获得的" vnd.android.cursor.item/vnd.google.note "和”android.intent.action.EDIT”到androidmanfest.xml中去找匹配的activity。

XML/HTML代码

  1. <intent-filter android:label="@string/resolve_edit">
  2. <action android:name="android.intent.action.VIEW" />
  3. <action android:name="android.intent.action.EDIT" />
  4. <action android:name="com.android.notepad.action.EDIT_NOTE" />
  5. <category android:name="android.intent.category.DEFAULT" />
  6. <data android:mimeType="vnd.android.cursor.item/vnd.google.note" />
  7. </intent-filter>

正好NoteEditor这个activity的intent-filter满足上述条件,这样就找到了NoteEditor。于是系统加载这个类并实例化,运行,然后就到了NoteEditor的OnCreate函数中(见后续文章)。

  小技巧

  1. 在命令行中使用”adb shell”命令进入系统中,然后”cd app”进入应用程序所在目录,”rm XXX”就可以删除你指定的apk,从而去掉其在系统顶层界面占据的图标,若两次”cd data”则可以进入应用程序使用的数据目录,你的数据可以保存在这里,例如Notepad就是把其数据库放在它的databases目录下,名为note_pad.db.

  2. 第一次启动模拟器会比较慢,但以后就别关闭模拟器了,修改代码,调试都不需要再次启动的,直接修改后run或debug就是。

时间: 2024-10-08 14:34:54

Android示例程序剖析之记事本(一)的相关文章

Android cocos2dx游戏开发——示例程序HelloCpp源码分析

本文通过分析cocos2dx提供的示例程序HelloCpp来分析cocos2dx的启动过程. 我们从HelloCpp.java开始: [java] view plaincopyprint? package org.cocos2dx.hellocpp; import org.cocos2dx.lib.Cocos2dxActivity; import android.os.Bundle; public class HelloCpp extends Cocos2dxActivity{ protecte

android应用程序签名(转)

概述 Android系统要求,所有的程序经过数字签名后才能安装.Android系统使用这个证书来识别应用程序的作者,并且建立程序间的信任关系.证书不是用于用户控制哪些程序可以安装.证书不需要授权中心来签名:Android应用程序上使用自己签名的证书是完全允许且普遍的. 理解Android应用程序签名有以下几个重要点: 所有的应用程序都必须签名.系统不会安装任何一个不签名的程序. 你可以使用自己的证书来签名.不需要任何授权中心. 当你要为最终用户发布你的应用程序的时候,你必须签入一个合适的密钥.你

使用 Eclipse PhoneGap 构建 Android 应用程序入门

Eclipse 是一种支持多种技术的开源集成开发环境 (IDE),但本文重点介绍 Java 支持,这也是 Android 应用程序的“母语”.Android 是 Google 发布的开源移动操作系统.Android 现已成为许多智能手机和平板设备的操作系统,其中包括三星 Galaxy 系列手机和平板电脑.亚马逊 Kindle Fire 平板电脑.Barnes and Noble Nook 平板电脑,以及大量制造商生产的许多其他设备.PhoneGap 是一个开源应用程序平台,可让您使用 HTML

Android学习笔记-Android应用程序初步认识

一直觉得自己的技术没有一门专长,似乎什么都会一点,但是却一点都不深入.决定学习Android的开发,说不出的理由,希望自己能够坚持下去. 其实之前已经搭建好了Android的开发环境eclipse+ADT+SDK,这里就不做具体介绍了,个人觉得还是非常有必要把这3个软件单独安装一下, 这样对开发工具能有个系统的认识.Eclipse是一个IDE,针对多门开发语言都能够使用,SDK是针对Android应用开发提供的一个框架,其中有开发 过程中使用到的包和一些集成的工具,ADT是安装在eclipse上

第一个Xamarin的 Android 应用程序!

你好,安卓 Xamarin的工作室 Xamarin的应用程序图标和启动屏幕 脱机使用PDF格式: 介绍与Xamarin的Android开发 示例代码: 开始使用应用程序的探险家 显示说明: Visual Studio 在这个由两部分组成的指南,我们建立我们的第一次Xamarin的. Android应用程序使用Xamarin的工作室或Visual Studio和发展的理解与Xamarin的Android应用程序开发的基本原理. 一路上我们将介绍工具,概念,构建和部署Xamarin的所需的步骤. A

用 Eclipse 开发 Android 应用程序

转自:http://www.apkbus.com/android-13828-1-1.html 开始之前 本教程介绍如何在 Eclipse 环境中进行 Android 应用程序开发,包括两个示例应用程序.第一个示例是一个基本的应用程序,涉及构建和调试的所有阶段.第二个应用程序示例涉及比较复杂的 Android 特性,包括联系人搜索和 Google Maps 地址查找.要想从本教程获得最大收益,具备移动开发经验会有帮助,但不是必需的.开发 Android 应用程序需要 Java? 编程技能,但是对

如何编译ReactNative示例程序Examples

通过示例程序可以看到一些基本组件的使用,对于学习ReactNative是很有帮助的. 编译示例程序需要将整个项目导入到androidStudio中,androidStudio导入项目时选择react-native/ReactAndroid目录. 由于项目依赖ndk因此如果要编译Examples还需要安装配置ndk目录,下载ndk后是一个自解压程序,会释放ndk的目录.然后需要设置环境变量或者在react-native根目录下新建local.properties文件,文件内容如下:sdk.dir=

Android应用程序破解(反编译)

一.apktools进行反编译 1.首先安装需要JAVA环境(JDK和JRE) 设置JAVA环境变量 CLASSPATH       %JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar JAVA_HOME     C:\Program Files\Java\jdk1.8.0_20 Path    %JAVA_HOME%\bin;C:\Program Files\Java\jre1.8.0_20\bin 2.下载apktools并解压 (1)下载apk

使用 JDB 调试 Android 应用程序

By Huang Tao of TinyLab.org 2015/04/13 前言 自从有了各种 IDE 工具,程序猿调试工作轻松了不少,只要在 IDE 上面点击两下按钮,各种程序运行时的信息全部都显示在屏幕上面,很美好的一件事情,我们都要感谢开发这些 IDE 工具的前辈,是他们让我们的工作变得这么"轻松简单",但是对于我个人来说,不是很喜欢这些 IDE 工具: 第一是因为这类 IDE 工具实在是变化太快,我们要花费很大的时间成本来学习这一类工具,然而当你好不容易熟悉了一种工具之后,别