http://hi.baidu.com/tomatohxy/blog/item/050a9e279be84a108a82a1a4.html
Android 應用程序 — 概述
我們來看看 Android 應用程序的四種主要類型:活動、服務、接收器和 ContentProvider。我們還要看看顯示用戶界面(UI)元素的視圖。
活動
活動是最常用的 Android 應用程序形式。活動在一個稱爲視圖 的類的幫助下,爲應用程序提供 UI。視圖類實現各種 UI 元素,比如文本框、標籤、按鈕和計算平臺上常見的其他 UI 元素。
一個應用程序可以包含一個或多個活動。這些活動通常與應用程序中的屏幕形成一對一關係。
應用程序通過調用 startActivity() 或 startSubActivity() 方法從一個活動轉移到另一個活動。如果應用程序只需 “切換” 到新的活動,就應該使用前一個方法。如果需要異步的調用/響應模式,就使用後一個方法。在這兩種情況下,都需要通過方法的參數傳遞一個 intent。
由操作系統負責決定哪個活動最適合滿足指定的 intent。
服務和接收器
與其他多任務計算環境一樣,“在後臺” 運行着一些應用程序,它們執行各種任務。Android 把這種應用程序稱爲 “服務”。服務是沒有 UI 的 Android 應用程序。
接收器是一個應用程序組件,它接收請求並處理 intent。與服務一樣,接收器在一般情況下也沒有 UI 元素。接收器通常在 AndroidManifest.xml 文件中註冊。清單 2 是接收器代碼的示例。注意,接收器的類屬性是負責實現這個接收器的 Java 類。
清單 2. 接收器代碼
package com.msi.samplereceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentReceiver;
public class myreceiver extends IntentReceiver
{
public void onReceiveIntent(Context arg0, Intent arg1)
{
// do something when this method is invoked.
}
}
用 ContentProvider 進行數據管理
ContentProvider 是 Android 的數據存儲抽象機制。我們以移動設備上常見的一種數據爲例:地址簿或聯繫人數據庫。地址簿包含所有聯繫人及其電話號碼,用戶在使用手機時可能需要使用這些數據。ContentProvider 對數據存儲的訪問方法進行抽象。ContentProvider 在許多方面起到數據庫服務器的作用。對數據存儲中數據的讀寫操作應該通過適當的 ContentProvider 傳遞,而不是直接訪問文件或數據庫。可能還有 ContentProvider 的 “客戶機” 和 “實現”。
下一節介紹 Android 視圖,這是 Android 在移動設備屏幕上顯示 UI 元素的機制。
視圖
Android 活動通過視圖顯示 UI 元素。視圖採用以下佈局設計之一:
LinearVertical
後續的每個元素都排在前一個元素下面,形成一個單一列。
LinearHorizontal
後續的每個元素都排在前一個元素右邊,形成一個單一行。
Relative
後續的每個元素相對於前一個元素有一定的偏移量。
Table
與 HTML 表相似的一系列行和列。每個單元格可以包含一個視圖元素。
選擇一種佈局(或佈局的組合)之後,就可以用各個視圖顯示 UI。
視圖元素由大家熟悉的 UI 元素組成,包括:
Button
ImageButton
EditText
TextView(與標籤相似)
CheckBox
Radio Button
Gallery 和 ImageSwitcher(用來顯示多個圖像)
List
Grid
DatePicker
TimePicker
Spinner(與組合框相似)
AutoComplete(具有文本自動補全特性的 EditText)
視圖是在一個 XML 文件中定義的。清單 3 給出一個簡單的 LinearVertical 佈局示例。
清單 3. 簡單的 LinearVertical 佈局
<?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="Activity 1!"
/>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Activity 1, second text view!"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Switch To Activity 2"
id="@+id/switchto2"
/>
</LinearLayout>
注意,每個元素有一個或多個屬於 Android 名稱空間的屬性。
下一節討論如何獲取 Android SDK 並在 Eclipse 環境中配置它。
本節要使用 Android Developer Tools 創建一個基本的 Android 應用程序,它稱爲 SaySomething。創建這個應用程序之後,將調試和運行它。New project 嚮導
第一步是創建一個新項目。選擇用來創建 Android 項目的嚮導,如下所示。
圖 2. New project 嚮導
這個應用程序需要:
Name
Location
Package name
Activity name — 可以認爲這是應用程序的主 “表單” 或屏幕
Application name
看看這個新項目。
圖 3. 新的 Android 項目
這會創建一個默認的應用程序,可以構建和運行它。可以在 Package Explorer 中查看它的組件。
Package Explorer
Package Explorer(在 Eclipse 的 Java 透視圖中)顯示 Android 示例應用程序的所有組件,見圖 4。
圖 4. Package Explorer
需要注意的組件包括:
src 文件夾
包含示例應用程序的包,即 com.msi.ibmtutorial。
R.java
Android Developer Tools 自動創建這個文件,它提供訪問 Android 應用程序的各種資源所需的常量。後面會詳細討論 R 類與資源之間的關係。
SaySomething.java
應用程序的主活動類的實現。
Referenced libraries
包含 android.jar,這是 Android SDK 中的 Android 運行時類的 jar 文件。
res 文件夾
包含應用程序的資源,包括:
圖標佈局文件
字符串
AndriodManifest.xml
示例應用程序的部署描述符。
接下來,詳細研究一下源代碼。
應用程序的主活動
這個示例應用程序由一個活動組成,即 SaySomething。正如前面提到的,SaySomething 類是在 SaySomething.java 文件中實現的。
清單 4. SaySomething.java
package com.msi.ibmtutorial;
import android.app.Activity;
import android.os.Bundle;
public class SaySomething extends Activity
{
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle)
{
super.onCreate(icicle);
setContentView(R.layout.main);
}
}
在這個源代碼片段中,要注意幾點:
SaySomething 是一個普通的 Java 類,包含包和導入語句。
SaySomething 擴展 android.app 包中的 Android 基類 Activity。
onCreate() 方法是這個活動的入口點,它接受一個 Bundle 類型的參數。Bundle 類本質上是 map 或 hashmap 的包裝器。在這個參數中傳遞構造活動所需的元素。本教程不討論這個參數。
setContentView(..) 負責用 R.layout.main 參數創建主 UI。R.layout.main 是應用程序資源中主佈局的標識符。
下一節討論示例應用程序的資源。
應用程序的資源
正如前面提到的,Android 中的資源放在項目的 res 子目錄中。資源分爲三類:
Drawables
這個文件夾包含圖形文件,比如圖標和位圖。
Layouts
這個文件夾包含表示應用程序佈局和視圖的 XML 文件。後面會詳細研究這些文件。
Values
這個文件夾包含 strings.xml 文件。這是爲應用程序實現字符串本地化的主要方法。
下一節研究 main.xml 文件,瞭解示例應用程序的 UI 資源。
main.xml
這個示例應用程序包含一個活動和一個視圖。應用程序包含一個名爲 main.xml 的文件,它代表活動的主 UI 的視覺方面。注意,在 main.xml 中沒有指定在哪裏使用這個佈局。這意味着,如果需要的話,可以在多個活動中使用它。清單 5 給出佈局文件的內容。
清單 5. 佈局文件
<?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="Hello World, SaySomething"
/>
</LinearLayout>
這是最簡單的佈局,其中只有一個垂直的線性佈局,這意味着所有元素排成一列。這裏有一個 TextView 元素,它與其他開發環境中的標籤類似。TextView 代表不可編輯的靜態文本。
注意,每個視圖元素(比如這個示例中的 LinearLayout 和 TextView)都有屬於 Android 名稱空間的屬性。一些屬性是所有視圖元素都有的,比如 android:layout_width 和 android:layout_height。這些屬性可以採用的值是:
fill_parent
使視圖元素佔滿可用的空間。也可以認爲這就是 “拉伸”。
wrap_content
這個值讓 Android 把元素一個接一個地排列,不進行拉伸。
在構建期間,對所有資源進行編譯。編譯過程的輸出之一是 R.java 文件,這個文件嚮應用程序的其餘部分提供資源。下面討論 R.java 文件。
R.java
R.java 文件是在構建時自動創建的,所以不要手工修改它,因爲所有修改都會丟失。清單 6 給出這個示例應用程序的 R.java 文件。
清單 6. R.java 文件
/* AUTO-GENERATED FILE. DO NOT MODIFY.
*
* This class was automatically generated by the
* aapt tool from the resource data it found. It
* should not be modified by hand.
*/
package com.msi.ibmtutorial;
public final class R {
public static final class attr {
}
public static final class drawable {
public static final int icon=0x7f020000;
}
public static final class layout {
public static final int main=0x7f030000;
}
public static final class string {
public static final int app_name=0x7f040000;
}
}
R 類包含一些匿名子類,每個子類包含前面描述的各種資源的標識符。注意,這些類都是靜態的。
請注意 R.layout.main 代表的元素。這個標識符代表由 main.xml 定義的佈局。在活動的 onCreate 方法中使用過這個值:setContentView(R.layout.main);。這就是在運行時把特定的活動(在這個示例中是 SayAnything)和特定的佈局(主佈局)聯繫在一起的方法。
構建應用程序
在默認情況下,每次保存文件時,都將對它們進行編譯。
圖 5. 錯誤面板
我們在源代碼中引入了一個錯誤,即在 setContent 和 View 之間加了一個空格。在保存這個文件時,它被編譯並在屏幕底部的 Problems 面板中顯示錯誤。在源代碼中糾正這個錯誤之後,應用程序就能夠成功編譯,並從問題列表中刪除錯誤。
AndroidManifest.xml
AndroidManifest.xml 文件是 Android 應用程序的部署描述符。這個文件列出應用程序中包含的所有活動、服務、內容提供器和接收器,以及應用程序支持的 IntentFilter。下面是這個示例應用程序的完整的 AndroidManifest.xml 文件。
清單 7. AndroidManifest.xml 文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.msi.ibmtutorial">
<application android:icon="@drawable/icon">
<activity class=".SaySomething" android:label="@string/app_name">
<intent-filter>
<action android:value="android.intent.action.MAIN" />
<category android:value="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
請注意以下情況:
這裏指定了源文件中的包名。這裏採用與 Java 源文件和導入語句相似的模式。<manifest> 標記的實際作用是 “導入” 這個包中的類。在這個文件中,所有非完全限定的類都屬於 package 屬性指定的包。
<application> 標記的一個屬性引用了應用程序的一個資源。請注意 drawable 標識符前面的 @ 符號。這裏的意思是,在應用程序資源的 drawable 文件夾中尋找名爲 “icon” 的資源。
<activity> 標記包含以下屬性和值:
class 屬性表示實現這個活動的 Java 類。
android:label 是應用程序的名稱。注意,它來自一個字符串資源。string.xml 文件包含應用程序的本地化字符串。
<intent-filter> 表示應用程序中可用的 IntentFilter。這是 Android 應用程序中最常見的 IntentFilter。這個過濾器的實際意思是,它實現 “主” 操作(也就是入口點),而且它位於 OS 的啓動器中。這意味着可以在 Android 設備上像啓動其他應用程序一樣,從應用程序主列表中啓動它。
下一節討論如何在 Eclipse 中的 Android 模擬器上啓動應用程序。
運行應用程序
應用程序已經成功地編譯了,現在該運行這個示例應用程序了。在 Eclipse 中選擇 Open Run Dialog 或工具欄上的快捷按鈕。這會打開一個對話框,可以在這裏創建啓動配置。選擇 Android Application 選項並單擊 New 的圖標。
圖 6 顯示本教程示例所用的值。
圖 6. Run 對話框
指定配置名稱。本教程使用的名稱是 Tutorial Configuration。在可用項目列表中選擇 ibmtutorial 項目(單擊 Browse 可以看到可用項目)。在下拉列表中選擇啓動活動。現在選擇 Emulator 選項卡,根據需要指定模擬器設置。可以保持默認設置。有兩個設置需要注意,見圖 7。
圖 7. Run 對話框,Emulator 選項卡
有幾種可供選擇的屏幕大小和方向,還有網絡選擇。如果運行應用程序的移動設備的因特網連接速度不同,網絡選擇就很重要了。在構造應用程序原型時,選擇完整網絡速度而且沒有延遲。開發了主要功能之後,最好在比較真實的網絡環境中進行測試,看看應用程序的響應速度如何。
選擇 Run 運行示例應用程序。
圖 8. 模擬器
應用程序已經在模擬器上運行了,現在看看幕後發生的情況。Dalvik Debug Monitor Service(DDMS)將會幫助檢查應用程序的運行情況。
調試應用程序
要想檢查正在運行的應用程序中發生了什麼情況,就需要查看正在運行的 Dalvik VM。在 Eclipse 中,選擇 Window > Open Perspective > Other。在出現的對話框中選擇 DDMS。這會在 Eclipse 中打開一個新的透視圖,其中有許多有趣的窗口。下面簡要介紹一下 DDMS 透視圖中提供的資源:
LogCat 是一個日誌文件,它記錄 VM 中發生的活動。應用程序可以通過 Log.i(tag,message); 在這個日誌文件中添加自己的日誌項,其中的 tag 和 message 都是 Java 字符串。Log 類屬於 android.util.Log 包。
圖 9 顯示 LogCat。
圖 9. LogCat
DDMS 中的另一個方便的工具是文件管理器,可以用它訪問模擬器的文件系統。圖 10 顯示在模擬器上部署本教程示例應用程序的位置。
圖 10. 在模擬器上部署的示例應用程序
用戶應用程序部署在 /data/app 目錄中,而 Android 內置的應用程序部署在 /system/app 目錄中。
在 DDMS 中還可以查看正在運行的進程。
圖 11. 正在運行的進程列表
創建內容提供器和 Google Maps 應用程序
您已經看到了一個完整的應用程序示例,現在簡要討論一下更加複雜的應用程序。
內容提供器和 Google Maps
本教程中討論的第二個應用程序適用於提供上門服務的專業人員,比如設備維修技術人員,這些人必須找到去客戶地址的路線。這個應用程序使用 Android 內置的聯繫人數據庫作爲記錄存儲庫。本節將講解如何訪問內容提供器中的數據,還將看看 intent 的效果。我們將用聯繫人數據庫中的地址數據執行 Google Maps 搜索。爲了讓這個應用程序在 Android 模擬器上正確運行,必須記錄一些聯繫人,而且必須填寫家庭地址字段。圖 12 顯示模擬器中與聯繫人應用程序相關的條目。
圖 12. 模擬器中與聯繫人應用程序相關的條目
模擬器中與聯繫人應用程序相關的條目
下面是這個應用程序的一個代碼片段。注意,這個應用程序的主 Activity 類擴展 ListActivity。這是因爲我們需要在列表中顯示信息。
清單 8. 第一個代碼片段
public class MobileServiceCallContacts extends ListActivity { final String tag = "MSCC"; /** Called when the activity is first created. */ @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.main); // Get a cursor with all people Cursor c = getContentResolver().query(People.CONTENT_URI, null, null, null, null); startManagingCursor(c); ListAdapter adapter = new SimpleCursorAdapter(this,android.R. layout.simple_list_item_1,c,new String[] {People.NAME} ,new int[] {android.R.id.text1}); setListAdapter(adapter); }...}
注意,這裏使用遊標類查詢聯繫人數據庫。這個 “結果集” 遊標通過 ListAdapter 類鏈接到 UI。圖 13 顯示當設備上記錄了聯繫人時應用程序的效果。注意,這個屏幕上的記錄沒有排序。
圖 13. 應用程序的運行效果
應用程序的運行效果
可以通過鼠標單擊、按模擬器的中間按鈕或按鍵盤上的 Enter 鍵選擇一個聯繫人。選擇聯繫人之後,代碼必須查詢所選聯繫人的地址。這要使用覆蓋的 onListItemClick() 方法。這個方法的實現有四個重要參數,其中最重要的是 dbidentifier。因爲遊標綁定到 UI,所以在調用這個方法時,它實際上會獲得底層數據源的標識符。可以使用 dbidentifier 字段在聯繫人數據庫中查詢所需的信息。還可以使用它啓動聯繫人應用程序,所用的 intent 見清單 9 中被註釋掉的代碼。
清單 9. 覆蓋的 onListItemClick() 方法
@Override protected void onListItemClick(ListView list,View view,int position,long dbidentifier) { super.onListItemClick(list,view,position,dbidentifier); try { // this commented out code below will launch the Contacts application // and "view" the contact Intent myIntent = / new Intent(android.content. // Intent.VIEW_ACTION,new ContentURI("content://contacts/people/" |-------10--------20--------30--------40--------50--------60--------70--------80--------9| |-------- XML error: The previous line is longer than the max of 90 characters ---------| // + dbidentifier)); startSubActivity(myIntent,position); // let's lookup specifics on this record ContentURI theContact = / new ContentURI(android.provider.Contacts.ContactMethods.CONTENT_URI.toURI()); // IMPORTANT // in order to use this sample application, you need to have at least // one Contact record on your Android emulator/ // and be sure to have populated the 'Home Address field' // // this "where clause" is for HOME address and for the person record // selected in the GUI (id, dbidentifier) Cursor c = managedQuery(theContact,null," type = 1 and person = " + dbidentifier,null); if (!c.first()) { showAlert("MSCC","No Contact Methods Available!","",true); return; } String address = c.getString(c.getColumnIndex("data")); address = address.replace("/n",""); address = address.replace(",",""); address = address.replace(" ","+"); Intent geoIntent = new Intent("android.intent.action.VIEW", new ContentURI/ ("geo:0,0?q=" + address)); startActivity(geoIntent); } catch (Exception ee) { Log.i(tag,ee.getMessage()); } }
找到地址之後,需要通過一些簡單的字符串操作清理數據,準備查詢 Google Maps。geoIntent 是一個用來執行地理搜索的新的 intent,它通過調用 Google Maps 提供默認的 Android 模擬器圖像。
第一個應用程序的所有主要元素仍然適用於這個應用程序。它有一個從主應用程序屏幕啓動的活動。當然,還有 AndroidManifest.xml 文件。在 下載 一節中可以找到完整的源代碼。
關於第二個應用程序,還有最後一點需要注意。AndroidManifest.xml 文件中包含一個條目,它使應用程序能夠讀取聯繫人數據庫:<uses-permission id="android.permission.READ_CONTACTS" />。如果不這樣做,Linux 內核就會禁止應用程序訪問聯繫人數據庫。