星期二, 9月 27, 2011

Creating Menus

Android應用程式學習筆記

Creating Menus


菜單是在activity的使用者介面中蠻重要的部分,它提供使用者熟悉的方式去執行動作,Android提供一個簡單的架構讓你可以添加菜單到你的應用程式中。

有三種形式的應用程式菜單:

Options Menu
為Activity主要的菜單種類,當使用者按壓"MENU"按鍵時顯示菜單。你的應用程式運行在Android 3.0或更新版本,你可以將菜單項目放置到Action Bar中提? 快速存取的功能。
Context Menu
當使用者觸碰或按住已註冊提供context menu的view時顯示浮動的菜單項目列表。
Submenu
當使用者點選有巢狀菜單的菜單項目時顯示浮動的菜單項目列表。
接著就依種類學習Menus。


Creating a Menu Source


取代在你的應用程式程式碼中實現菜單,你應該在XML菜單資源中定義菜單以及所有的菜單項目,然後在應用程式程式碼中擴展菜單資源,使用菜單資源來定義你的菜單是較佳的方式,因為將菜單內容與應用程式程式碼分開,如此更能想像在XML中菜單的內容與結構。

建立菜單資源,先在你的專案的res/menu目錄下建立一個XML文件並用以下標籤建構菜單:

<menu>
此標籤用來定義一個菜單,它是菜單項目的容器,<menu>標籤必須是文件中的根節點且能保有一個或多個<item>與<group>標籤。
<item>
此標籤用來建立菜單項目,顯示在菜單中的項目,一個標籤對應一個菜單項目。標籤可以在包含一個巢狀<menu>標籤來產生巢狀子菜單。
<group>
 可選的,<item>標籤的無形容器,它允許你去為菜單項目分類。
以下有一個命名為game_menu.xml的例子:


<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/new_game"
          android:icon="@drawable/ic_new_game"
          android:title="@string/new_game" />
    <item android:id="@+id/help"
          android:icon="@drawable/ic_help"
          android:title="@string/help" />
</menu>

 此例包含兩個項目,每個項目包括屬性:

android:id
Id對於項目是有唯一性,它可以允許應用程式辨認是哪個項目被使用者所選到。
android:icon
引用圖片作為項目的圖標。
android:title
引用字串作為項目的標題。
有許多屬性是可以包括在<item>中, 包括可以讓Action Bar先是在項目中。更多資訊等之後會寫在Menu reference中。


Inflating a Menu Resource

從應用程式程式碼你可以使用MenuInflater.inflate()方法來擴展菜單資源(轉換xml資源成為可編成的)。例如在onCreateOptionMenu()回呼方法中擴展上述的game_menu.xml例子,並將菜單資源作為activity的菜單。


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

getMenuInflater()方法為activity回傳一個Inflater物件,有這個Inflater物件,你可以呼叫inflate()方法來擴展你的菜單資源成為Menu物件。在此例子中,定義菜單資源的game_menu.xml通過onCreateOptionMenu()方法擴展成為Menu(onCreateOptionMenu回呼方法會在下一段中討論)。


那接下來的內容就依照一種形式的菜單為一個區塊來討論,依序討論option menu、context menu、submenu。

Create an Option Menu

Option menu是應該放置你的activity的基本動作和必需的導航項目的地方(例如,用來開啟應用程式設定的按鈕)。有兩種不同方式可以訪問Option menu的項目:MENU按鈕和Action Bar(Android 3.0版以後)。

當裝置運行的是Android 2.3或更低版本,option menu顯示在屏幕的底層,如圖1。當打開菜單,第一個看見菜單的部分是圖標菜單,它有前六個菜單項目,如果你想增加超過六個菜單項目,amdroid放置第六個菜單項目來裝那些多出來的菜單項目,當使用者觸碰"More"項目。


圖1.屏幕底部為Option menu
在Android 3.0及更高的版本,Option menu的項目是被放置在Action Bar,它出現在activity的頂部取代傳統的標題欄。預設的情況下,所有Option menu的項目被放置在溢出來的菜單中,使用者可以觸碰Action Bar右側的菜單圖標開啟菜單。然而,你可以將選擇菜單項目直接放在Action Bar中作為"Action items",如圖2。

 圖2.這是一個電子郵件應用程式的Action Bar,有兩個來自option menu的action item與更多菜單

當android系統第一次建立Options menu,系統會呼叫你的activity的onCreateOptionMenu()方法,在你的activity中複寫此方法並且將菜單資源放置到傳遞到此方法的Menu物件中。

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    MenuInflater inflater = getMenuInflater();
    inflater.inflate(R.menu.game_menu, menu);
    return true;
}

你可以使用add()方法增加item到Menu中。


Responding to user action

 當用戶選擇來自Option menu的菜單項目時,系統會呼叫你的activity中的onOptionsItemSelected()方法,此方法會傳入用戶選擇的菜單項目,你可以呼叫getItemId方法,它會回傳項目的ID,你可以比對ID來知道哪個item被擁護選擇並執行相對應的動作。

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    // Handle item selection
    switch (item.getItemId()) {
    case R.id.new_game:
        newGame();
        return true;
    case R.id.help:
        showHelp();
        return true;
    default:
        return super.onOptionsItemSelected(item);
    }
}

此例子中,getItemId()用來查詢被選擇的項目的ID,switch的判斷式是用來將ID與在菜單資源的菜單項目的ID做比較。當siwtch成功處理菜單項目後,它會回傳true值表示item selection已經處理了。否則,default程式碼用super類呼叫原本的onOptionsMenuSelected()方法。

此外,Android 3.0為你增加了一項能力就是在菜單資源的xml檔案中定義on-click行為,使用android:onClick屬性,所擬你不需要實現onOptionsMenuSelected()方法。使用android:onClick屬性,你可以指定一個方法給被用戶選擇的菜單項目。


Changing menu item at runtime

一旦activity建立後,onCreateOptionsMenu()方法只會被呼叫一次,系統保留並重複使用在此方法定義的Menu物件直到activity被銷毀。如果想要在建立後的任何時間改變菜單,可以複寫onPrepareOptionsMenu()方法,如此就能根據應用程式目前的狀態新增、刪除、禁用或啟用菜單項目。

在Android 2.3或更低版本,系統呼叫onPrepareOptionsMenu()方法。

在Andoird 3.0或更高版本,當你想改變菜單時你可以呼叫invalidateOptionsMenu()方法,系統將會呼叫onParepareOptionsMenu()方法來更新菜單。


Creating a Context Menu

Context menu概念與當用戶使用電腦"右鍵"的菜單相似,你應該使用context menu提供用戶在使用者介面上訪問屬於特定項目的動作,在Android平台上,當用戶長按項目時顯示context menu。

你可以在任何試圖中建立context menu,雖然context menu大部分使用在ListView的項目上,當用戶長按ListView上的項目時且列表有被註冊要提供context menu,列表項目藉著動畫背景顏色來發出context menu是可用的信號-它會在打開context menu之前從橘色轉成白色。

為了讓View物件能提供context menu,你必須將context menu註冊在View物件上,呼叫registerContextMenu()方法並將想註冊context menu的View傳到此方法。當此View接收到長按事件時,它就顯示context menu。

複寫activity的contexte menu回呼方法來定義context menu的外觀與行為:onCreateContextMenu()和onContextItemSelected()。

例子,使用context_menu.xml資源的onCreateContextMenu()方法。

@Override
public void onCreateContextMenu(ContextMenu menu, View v,
                                ContextMenuInfo menuInfo) {
  super.onCreateContextMenu(menu, v, menuInfo);
  MenuInflater inflater = getMenuInflater();
  inflater.inflate(R.menu.context_menu, menu);
}

MenuInflater用來擴展來自menu resource的context menu(你也可以使用add()方法來增加菜單項目),回呼方法的參數包括給用戶選擇的view物件及ContextMenu.ContextMenuInfo提供項目被選擇時的其他資訊。你也可以用這些參數決定哪個context menu應該被建立,但是在此例子,所有對於activity的context menu都是相同的。

接著當用戶選擇了context menu中的項目,系統呼叫onContextItemSelected()方法,以下有一例子來演示可以如何處理選擇項目。

@Override
public boolean onContextItemSelected(MenuItem item) {
  AdapterContextMenuInfo info = (AdapterContextMenuInfo) item.getMenuInfo();
  switch (item.getItemId()) {
  case R.id.edit:
    editNote(info.id);
    return true;
  case R.id.delete:
    deleteNote(info.id);
    return true;
  default:
    return super.onContextItemSelected(item);
  }
}

此方法的程式碼結構與上述的例子相似,getItemId()查詢被選擇到的ID而switch判斷式比對在材單資源裡的項目的ID。

在此例中,被選擇的項目是來自ListView的項目。執行被選擇項目的動作,應用程式需要知道被寫責的項目ID,應用程式呼叫getMenuInfo()方法來得到ID,它會回傳AdapterView.AdapterContextMenuInfo物件,該物件包括ID。


Creating Submenus

Submenu是用戶可以選擇其他菜單的項目來打開的菜單。你可以在任何菜單中增加子菜單,子菜單是用來將應用程式有許多功能分類成幾個主題。

當建立菜單資源時,可以增加<menu>標籤作為一個子項目,比如:

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/file"
          android:icon="@drawable/file"
          android:title="@string/file" >
        <!-- "file" submenu -->
        <menu>
            <item android:id="@+id/create_new"
                  android:title="@string/create_new" />
            <item android:id="@+id/open"
                  android:title="@string/open" />
        </menu>
    </item>
</menu>

當用戶選擇了一個子菜單的項目,父菜單的on-item-selected方法會接收到事件。例如,上述的菜單應用在Option menu上,那當子菜單的項目被選擇時呼叫onOptionsItemSelected()方法。

你也可以呼叫addSubmenu()方法動態的增加子菜單在以存在的菜單中,它會回傳一個子菜單物件,你可以使用add()方法來增加子菜單的項目。


Other Menu Feature

這裡有一些其他屬性你可以應在大部分的菜單。

Menu groups

Menu group是菜單項目的集合,有group,你可以做:
  • 用setGroupVisible()方法顯示或隱藏所有項目。
  • 用setGroupEnabled()方法啟用或禁用所有項目。
  • 用setGroupCheckable()方法所有項目是否為checkable。
你可以在菜單資源中<group>標籤裡面增加巢狀<item>來建立group,或用add()方法指定group ID。

以下是包含一個group的菜單資源。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/item1"
          android:icon="@drawable/item1"
          android:title="@string/item1" />
    <!-- menu group -->
    <group android:id="@+id/group1">
        <item android:id="@+id/groupItem1"
              android:title="@string/groupItem1" />
        <item android:id="@+id/groupItem2"
              android:title="@string/groupItem2" />
    </group>
</menu>



Cheackable menu items

一個可以作為開關項目的介面的菜單,獨立選項可以使用複選框(checkbox),或互相排斥選項的group可以使用單選按鈕(radio button)。

你可以在<item>標籤中使用android:checkable屬性來定義個別項目checkable屬性,或者在<group>標籤中用android:checkableBehavior屬性來定義整個group的行為。

例子,all items in this menu group are checkable with a radio button。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <group android:checkableBehavior="single">
        <item android:id="@+id/red"
              android:title="@string/red" />
        <item android:id="@+id/blue"
              android:title="@string/blue" />
    </group>
</menu>

android:checkableBehavior屬性可以接受數值有:
  • single-Group中只有一個項目可以檢查(radio button)。
  • all-所有項目都可以檢查(checkbox)。
  • none-沒有可檢查的項目。

 你可以先用android:checked屬性的預設值,然後在程式碼鐘用setChecked()方法修改。

當可檢查的項目被選到時,系統會呼叫各自的select-item回呼方法(比如,onOptionsItemSelected()方法),在這裡你須設定複選框的狀態,因為複選框或單選按紐都不法自動改變狀態,你可以用isCheck()方法查詢項目的狀態並用setChecked()設定狀態。


@Override
public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case R.id.vibrate:
  case R.id.dont_vibrate:
    if (item.isChecked()) item.setChecked(false);
    else item.setChecked(true);
    return true;
  default:
    return super.onOptionsItemSelected(item);
  }
}

如果你不想用此種方式設定狀態,當用戶選擇到項目時就不會看見狀態的改變。當你做了設定狀態,activity保留項目被檢查的狀態以便當用戶打開菜單後,你可以設定以檢查狀態為可見的。


Shortcut Keys

Dynamic adding menu intents

Allowing your activity to be added other menus

星期日, 9月 25, 2011

Declaring Layout

Android應用程式學習筆記

Declaring Layout

佈局(Layout,以下都稱作布局)是在一個activity中使用者介面的結構,它定義了佈局結構及確保每個元素顯示給使用者,你有兩種方式可以宣告你的布局:

  • Declaring UI elements in XML
    Android提供對應view類與子類的簡單XML詞彙,例如,部件與佈局。
  • Instantiate layout elements at runtime
    你的應用程式能在編程時建立View及ViewGroup。
Android架構給妳相當高的靈活性,你可以使用其中一種方式或兩種方式都用來宣告與管理你的應用程式的使用者介面。例如,你可以在XML宣告你的應用程式的預設布局,包括顯示在布局上的屏幕元素及佈局的屬性。你可以在應用程式中添加程式碼,在執行時修改屏幕物件的狀態,包括宣告在XML的也可以修改。

在XML宣告你的使用者介面的好處是使你更能從控制使用者介面行為的程式碼中分離出來,將你的使用者介面的描述從應用程式程式碼中分離出來,如此表示你可以修改或調整使用者介面描述不需要修改原始碼及重新編譯。例如,你可以為不同取向的介面、不同裝置屏幕大小、不同語言來建立布局文件。此外,在XML宣告布局更容易想像使用者介面的結構,如此就能更輕鬆的調適錯誤。

一般來說,宣告UI元件的XML詞彙緊隨類別與方法的結構與命名,這裡元件名稱對應到類別名稱,屬性名稱對應到方法。事實上,該隊應是非常直覺的,你可以猜到甚麼樣的屬性對應甚麼樣的方法,或者甚麼樣的方法對應到給定的xml元件。然而不是所友都能辨識出來,在一些案例中,有一些命名有輕微的不同。例如,EditView元件有一個text屬性對應了EditView.settext()方法。


Write the XML

使用android的XML詞彙,你可以快速地設計你的UI及UI中的屏幕元件,與你用HTML建立網頁的方式一樣-有許多巢狀標籤。

每個布局文件必須確切地包含一個根標籤,它必須是View或ViewGroup物件。一旦你定義了根標籤,你可以增加其他的布局物件及部件作為子標籤,逐步建立起定義布局的View階層樹。例子,以下有一個XML文件使用了垂直的線性布局並容納了一個TextView與一個Button。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent" 
              android:orientation="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

在XML宣告了你的布局後,儲存為.xml附檔名的檔案,並存在res/layout目錄下,


Load the XML Resource

當你編譯你的應用程式,每一個XML布局文件編譯成View資源,你應該從程式碼中載入布局資源,在Activity.onCreate()回呼方法中實現。藉著呼叫setContentView()方法,用R.layout.layout_filenam格式來引用布局資源。例如如果你的布局文件存為main_layout.xml,你就會如此為activity載入此文件:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

當你的activity啟動時,android架構會去呼叫在activity中的onCreate()回呼方法。


Attributes

每個View與ViewGroup物件支持它們自己的XML屬性,有些屬性是給特定View物件(例如,TextView物件支持textSize屬性),這些屬性也是繼承自任何繼承自這個類別的View物件。有些屬性對於所有View物件是普遍的,因為它們都是繼承自根View類別(如Id屬性)。且其他屬性被視為"布局參數",它們是描述View物件的布局取向。

ID
任何一個View物件都有一個整數ID屬性伴隨,辨識在階層樹中的View的唯一標籤。當應用程式被編譯,這個ID以一個整數被引用,但是ID屬性在XML文件中通常被分配為一個字串。ID屬性對所有View物件是相當普遍的且你會很常使用到它,在XML文件中是如此表示的:

android:id="@+id/my_button"

字串開頭的@表示XML解析器應該分析及擴展其餘的字串並視為一個ID資源。加號符號(+)是表示這是一個新的資源名稱,必須鍵立即增加到我們的資源(R.java檔案)。Android架構提供許多其他ID資源,當引用一個ID資源時,你不需要加號符號,但是必須加上android package namesapce,如以下:

android:id="@android:id/empty"

有android package namespace,我們現在從android.R資源中引用一個ID。
為了建立試圖以及從應用程式引用它們,普遍的模式是:

  1. 定義view/widget物件並分配一個唯一的ID:
    <Button android:id="@+id/my_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/my_button_text"/>
  2. 建立view物件實體,從佈局中取得它(通常在onCreate()方法中):
    Button myButton = (Button) findViewById(R.id.my_button);
當建立RelativeLay時,為view物件定義ID是相當重要的。在相對布局(Relativelayout)中,兄弟view物件可以定義布局相對於其他兄弟view物件透過引用唯一的ID來達成。


Layout Parameters

XML布局屬性命名為layout_something來為view定義布局參數,對ViewGroup也是如此。

每個ViewGroup類都是繼承ViewGroup.LayoutParams來實現巢狀類,這個子類包括定義每個子view物件的大小及位置的特性,ViewGroup物件也是。以下圖示顯示父view group來定義每個子view的布局參數。


注意每個布局參數子類都有自己的語法來設定數值,每個子元件必須定義布局參數。

每個view小組包括寬和高(layout_width及layout_height),且每個view也必須定義它們,許多布局參數也包括選擇邊沿與邊界。

你可以指定確切的尺寸,雖然你通常不想如此,更加平常的是,擬將使用這些常數來設定寬和高:
  • wrap_contents
    告訴你的view物件自己的尺寸需要包含內容,意思就是view的尺寸要剛好能容納內容。
  • fill_parent
    告訴你的view物件尺寸與父view物件一樣大。
一般來說,是不推薦使用絕對單位如像素指定布局的寬和高,取而代之的是使用相對尺寸如 density-independent pixel (dp)、wrap_contents、fill_parent是較適合的方式,因為能幫助確保你的應用程式顯示在不同的裝置上。


Layout Position

View的幾何形狀是矩形,view都有它的位置,可以用left和top一對來表示、用二維座標來表示、用寬和高來表示。位置和座標的單位都是像素。

呼叫getLeft()和getTop()方法取得view物件的位置是有可能的,前者回傳left或X來表示view的座標,後者回傳top或Y來表示座標。這些方法皆是回傳與它的父view物件相對的位置,例如,getLeft()回傳20,表示位於父view物件的左邊緣右邊20像素的位置。

此外,有提供許多方便的方法來避免不必要的運算,如getRight()和getBottom()。


Size , Pading and Margin

一個view大小可以表示成寬和高,實際上一個view具有兩組的寬和高。

第一組是measured width和measured height,這些尺寸定義了view在父view物件想要有多大,測量的尺寸能藉著呼叫getMeasuredWidth()方法和getMeasuredHeight()方法取得寬和高。

第二組是width和height,或有時是drawing width和drawing height,這些尺寸定義了view實際在屏幕上的大小,這些數值可能與measured width和measrued height的數值不同,我們可以呼叫getWidth()方法和getHeight()方法取得寬和高。

去測量尺寸時,view是有考慮到填充的大小,Padding是表示view的左側、頂部、右側、底部的大小,Padding可以用像素來彌補view的內容,例如left padding of 2就是只view的內容往左邊界的右邊推出去2個像素。我們可以呼叫setPadding(int ,int ,int ,int)來設定Padding以及呼叫getPaddingLeft()、getPaddingTop()、getPaddingRight()、getPaddingBottom()來取得Padding大小。



好了,以上是宣告布局的內容,以下做一個整理:
在這篇內容中說道如何宣告一個布局、如何設定布局的屬性。

1.我們有兩種方式能宣告布局,有就是說我們有兩種方式能編輯activity的使用者介面。
  • 在XML中編輯。
  • 在程式碼中編輯。
建議是將使用者介面的布局編輯在XMl文件中。

2.使用View和ViewGroup對應的標籤來編輯布局文件。
  • <RelativeLayout>對應RalativeLayout。
  • <TextView>對應TextView。
  • <Button>對應Button。
  • ...
3.在activity的onCreate()方法中呼叫setContentView()來取得布局資源。

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main_layout);
}

4.在布局文件中設定View和ViewGroup的屬性。

5.view與viewgroup之間的關聯。

6.布局文件中view與viewgroup的位置設定。

Adapter 與 Styles and Themes

Android應用程式學習筆記

Adapter
有時你會想在viewgroup中填充一些容易編碼的資訊在裡面,相反,你希望你的view與外部數據資源連結。要如此做,你要用AdapterView作為你的ViewGroup且每個子View物件用從adapter來的數據來初始化與填充。

AdapterView是ViewGroup的實現,它根據給定的Adapter物件決定它的子View物件,Adapter扮演了像在你的數據資源(也許是外部字串陣列)與AdapterView之間的信使。有許多Adapter類別實現的方式,比如,從Cursor物件讀取資料數數據的CursorAdapter或從隨意的陣列讀取數據的ArrayAdapter。


Styles and Themes
也許你會對標準的部件外觀不是很滿意,去調整它們,你可以建立一些自己的樣式與主題。

  • Style是一個或多個格式屬性組成,你可以應用它到你的布局上的單個元素上。比如,你可以定義一個style用來指定文字大小及顏色,並應用它到指定的view元素。
  • Theme是一個或多格格是屬性組成,你可以應用它到你的應用程式的所有activities上。比如,你可以定義一個Theme來設定窗框及面板的背景的顏色,以及設定菜單的文字大小及顏色。Theme可以被應用在特定activities或是整個應用程式。
樣式與主題是資源,Android提供一些預設的樣式與主題給你使用,或是你可以宣告自己的樣式與主題資源。

星期六, 9月 24, 2011

Menus

Android應用程式學習筆記

Menus

應用程式菜單是應用程式UI的另一重要部分,菜單提供了確實介面來顯示應用程式功能與設定。最普遍的應用程式菜單是當裝置上的菜單按鍵按下顯示的菜單,然而你也可以增加上下文菜單,當使用者按下或按住一個項目時顯示。

菜單也是用view階層樹為結構,但是你不需要自己定義這個結構,取而代之的是,你需要為你的activity定義onCreateOptionMenu()或onCreateContextMenu()回呼方法的內容以及你想包含在你的菜單裡的項目。在適當的時間,android會為菜單自動建立必須的view階層樹並且繪製每個菜單項目。

菜單也處理自己的事件,所以不需要在菜單上的項目註冊監聽器。當你的菜單的項目被選到時,系統會去呼叫onOptionItemSelected()或onContextItemSelected()方法。

如你的應用程式的布局文件一樣,你可以選擇在xml宣告菜單中的項目。

UI events

Android應用程式學習筆記

UI events

一旦你增加一些View或Widget到你的UI中,你就有可能想要知道使用者與它們的互動,因此你可以執行一些動作。要被UI事件通知,你需要實現兩個其中一個:

  • 定義一個事件監聽器並且將它向View註冊
    數見不鮮,這是常用監聽事件的方式。在View類別中包含命名為on<something>Listener的巢狀介面的集合,每個都有一個on<something>()的回呼方法。例如,View.onClickListener(專處理View的"click"事件),View.onTouchListener(專處理View的觸碰屏幕的事件)及View.onKeyListener(專處理View的裝置按鍵受按壓的事件),所以,你想你的View在"click"時被告知要怎麼處理,就要實現onClickListenter並定義onClick()(當按下後執行動作的地方)回呼方法的內容,然後用setOnClickListener()方法將監聽器向View註冊。
  • 複寫存在於View的回呼方法
    當你想要實現自己的View類別並監聽發生在此類別中的特定事件,你應該使用此方法。舉例你可以實現的監聽器包括觸碰屏幕(onTouchEvent)、軌跡球移動(onTrackballEvent)或裝置按鍵被按壓(onKeyDown)。此允許你定義在客製的view中的每個監聽事件的行為及決定事件是否應該通過其他子view。
以上翻譯自官網的敘述,說實在我不是了解第二種方法,不過它有其他文件可以深入了解。之後再補上了。

繼承Service類實現started類型的service

Android應用程式學習筆記

繼承Service類實現started類型的service

首先,我們從之前學習到實現started有兩種方法,一種是繼承IntentService類別,一種是繼承Service類別,以下有我們的程式碼,一樣我們設定三個按鈕,一個按鈕是啟動service,一個是
停止service,一個是再啟動service一次,service自己會運行10秒鐘後自動銷毀。

那有幾個特點我們藉這次機會實驗一下:
1.started service的生命週期是
組件呼叫startService()方法 -> onCreate() -> onStartCommand() -> Service running -> Service stoped by itself or client -> onDestroy()
那我們就在各個回呼方法中加上 System.out.println("")來驗證,當執行到該回呼方法就會輸出回呼方法的名稱。

2.一旦service啟動後,就會無限地在後台運行。所以我們試著在啟動service後10秒鐘內按下"BACK"關閉應用程式,看看service是不是還在後台運行。因為service在10秒鐘會自己銷毀,並呼叫onDestory()方法來驗證。

3.它與IntentService不同是能處理多執行續。(還在試)

4.執行續一次只執行一個請求,所以後進的請求必須等前一個請求完成後才會被處理。那我們這就用兩個按鈕來對service傳送兩個請求,並看看是不是在第一個請求執行10秒後,才在執行第二個請求。



package test.helloservice;

import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;

public class HelloService extends Service {

//宣告一個Looper物件作為與執行續通訊的接口
private Looper mServiceLooper;
//宣告一個Handler物件作為處理訊息的接口
private ServiceHandler mServiceHandler;

//Handler接收從執行續傳來的訊息
private final class ServiceHandler extends Handler{
public ServiceHandler(Looper looper){
super(looper);
System.out.println("ServiceHandler");
System.out.println("Thread------> " + Thread.currentThread().getId());
}

//處理訊息的方法
@Override
public void handleMessage(Message msg){
System.out.println("handleMessage");
System.out.println("Thread------> " + Thread.currentThread().getId());
//通常我們把要執行的工作在此處完成
long endTime = System.currentTimeMillis() + 10*1000;
       while (System.currentTimeMillis() < endTime) {
           synchronized (this) {
               try {
                   wait(endTime - System.currentTimeMillis());
               } catch (Exception e) {
               }
           }
       }
     
       stopSelf(msg.arg1);
}
}



//第一次產生service時系統呼叫此方法
@Override
public void onCreate(){
System.out.println("onCreate");
System.out.println("Thread------> " + Thread.currentThread().getId());
//因為通常直service工作會在主執行緒中完成,但此方式可能會阻塞主執行緒,所以我們另外產生執行緒
HandlerThread thread = new HandlerThread("ServiceStartArguments" ) ;
thread.start();
//從執行續取得Looper物件
mServiceLooper = thread.getLooper();
//將Looper物件設置到handler,如此handler才會處理執行許傳遞的訊息
mServiceHandler = new ServiceHandler(mServiceLooper);
}


@Override
public int onStartCommand(Intent intent , int flags , int startId){
System.out.println("onStartCommand");
System.out.println("Thread------> " + Thread.currentThread().getId());

Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
mServiceHandler.sendMessage(msg);

return START_STICKY;

}
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
System.out.println("onBind");
System.out.println("Thread------> " + Thread.currentThread().getId());
return null;
}

@Override
public void onDestroy(){
System.out.println("onDestroy");
System.out.println("Thread------> " + Thread.currentThread().getId());
super.onDestroy();
}

}


以下那我們實驗結果

1.

2.3.4.可以自己回去實驗。

星期五, 9月 23, 2011

Widget

學習筆記

Widget

部件是一個View物件作為與使用者互動的介面,Android提供一個全面性的部件,像是按鈕、checkboxex等,所以你可以很快地建立你的使用者介面。Android提供一些較複雜的部件,像是日期選擇、時鐘及變焦控制。你也不用被android所提供的部件給限制了,如果你想做一些客製化,或者建立新的部件,這些都是允許的。

Layout

Android應用程式學習筆記

Layout

要定義布局與表示視圖階層的最普遍的方式就是xml的布局文件,XML為布局提供一個我們較好閱讀的結構,XML很像HTML。在XML裡的標籤不是View物件就是ViewGruop物件,View物件視階層樹的葉子,ViewGroup物件視階層樹的枝幹。

XML標籤的名字各自以Java類別的顯示。所以在你的UI中,一個<TextView>標籤產生一個TextView,而一個<LinearLayout>標籤產生一個LinearLayout的ViewGroup。當你裝載一個布局資源,android系統就會初始這些物件,對應你布局文件的標籤。

以下有一個例子,簡單的垂直布局有一個textview及一個按鈕:


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="fill_parent" 
              android:layout_height="fill_parent"
              android:orientation="vertical" >
    <TextView android:id="@+id/text"
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:text="Hello, I am a TextView" />
    <Button android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Hello, I am a Button" />
</LinearLayout>

注意到LinearLayout標籤中容納了TextView與Button,你可以巢狀增加其他LinearLayout在這裡面,去延長視圖階層樹並產生更複雜的布局。