星期一, 10月 31, 2011

Fragment (一)

Android應用程式學習筆記

Fragments

Fragment用來描述在Activity上使用者介面的一部份或是行為,你可以結合多個fragments在單一activity上建立多框架的activity還有可以在多個activity重複利用單一fragment,你可以將fragment認為是activity的模件部分,fragment擁有自己的生命周期,接收自己的事件輸入,你可以在activity運行時,新增或移除fragment。

Fragment必須鑲嵌在activity中,且fragment的生命週期直接受到宿主activity的影響。例如,當activity暫停,所有嵌在activity上的fragments也會暫停;當activity被銷毀,所有嵌在activity上的fragments也會銷毀。然而當activity正在運行(在resume生命週期狀態),你可以獨立操作每個fragment,比如,增加或是移除它們。

當你增加fragment作為activity布局的一部份,它存在activity的視圖階層樹的ViewGroup中,且fragment定義自己的視圖布局,你可以通過在activity布局文件中宣告fragment標籤<fragment>,在你的activity的布局中插入fragment,或是從應用程式程式碼中插入到已存在ViewGroup。然而,fragment並不是一定要是activity布局的一部份,你也可以不為fragment設定使用者介面,讓它作為activity的隱形工作者。


小小總結:
Fragment中文來說應該就是框架,就像是網頁框架一樣,可以將網頁切割成幾個部分。所以在activity上就可以利用fragment產生畫面上的切割,並在不同部分設計達成不同需求。

星期日, 10月 30, 2011

Activity (八)

Android應用程式學習筆記

Coordinating activities

Activity A 啟動 Activity B的流程:
1.執行Activity A的onPause()方法。
2.依序執行Activity B的onCreate()、onStart()、onResume()方法。
3.然後,如果Activity A不再顯示在屏幕,執行onStop()方法。

了解流程可以幫助你管理從activity轉換到另一個activity的資訊。比如,你必須在第一個activity停止前將數據寫入資料庫,如此讓接下來的activtiy可以讀取,你應該在onPause()方法執行寫入資料庫的工作,而不是onStop()。

Activity (七)

Android應用程式學習筆記

接著Activity (六)的內容繼續學習。

然而,即使你沒做甚麼和沒有實現onSaveInstanceState()方法,Activity類預設實現onSaveInstanceState()方法還保存一些activity狀態。特別的是,預設會為布局的每個視圖呼叫onSaveInstanceState()方法,允許每個視圖提供應該被儲存的資訊,在Android架構下幾乎每個部件都會實現這個方法,這樣當你的activity再次建立時,在使用者介面上的任何可見的改變都可以自動保留儲存起來。比如,EditText部件會保存用戶輸入的文字,CheckBox部件保存用戶是否check。這些只會在當你提供你想保存狀態的部件的ID(android:id屬性)才有作用,如果部件沒有ID,就無法保存狀態。

雖然預設會執行onSaveInstanceState()方法來保存與activity的使用者介面有關的有用資訊,你仍可能需要複寫onSaveInstanceState()方法來保存額外資訊。比如,你可能需要保存在activity的生命中改變的變數值。

因為預設實現的onSaveIntanceState()方法幫助儲存使用者介面的狀態,如果你複寫此方法來保存額外資訊,你應該在執行任何工作之前呼叫superclass實現onSaveInstanceState()

測試你的應用程式有能力保存狀態的做簡單方法就是轉動裝置,讓屏幕方向改變。當屏幕方向改變,系統為了恢復資源銷毀又在建立activity可能利用為新的方向,單獨為此理由,你的activity能保存轉動屏幕的狀態是重要的,這樣用戶就不會經常在使用應用程式時還要轉動屏幕。

以下圖示,左邊顯示當activity被停止然後恢復,activity的狀態保持原封不動。右邊顯示當activity被銷毀然後再次建立,activity必須保存先前的activity狀態。


Activity (六)

Android應用程式學習筆記

Saving activity state

介紹Managing the Activity Lifecycle簡單地提到在activity被暫停或是停止,狀態是可以被保留的。這是真的,因為在暫停或停止時,Activity物件仍保留在記憶體中-所有有關的資訊及目前狀態仍是活的。因此用戶在activity上產生的任何改變都會保留在記憶體中,以便當activity回到前台,這些改變仍能存在。

然而當系統為了恢復記憶體而銷毀activity,Activity物件就會被銷毀,所以無法輕易以它完整無缺的狀態恢復activity。代替的方法就是,如果用戶操作回到activity,系統必須再次建立Activity物件。到目前為止,用戶不會察覺系統銷毀activity並重新建立activity,因此期望activity能精確地回到之前的狀態。在此情況下,你能擔保有關activity狀態的重要資訊被保存下來,藉著實現額外的回調方法來保存有關你的activity狀態的資訊然後在系統重新建立activity時恢復。

保存與目前activity狀態有關的資訊的回調方法為onSaveInstanceState()方法,系統呼叫此方法之前,使activity容易銷毀,並傳入Bundle物件。Bundle物件是你保存與activity有關的狀態資訊的地方,比如鍵值對,利用一些方法將值放入Bundle物件,比如putString()。然後,如果系統殺掉你的activity後用戶操作回到你的activity,系統將Bundle物件傳到onCreate()方法,所以你可以恢復到在onInstanceState()方法中保存的activity狀態。如果沒有任何資訊需要恢復,Bundle傳入onCreate()方法為null。


星期六, 10月 29, 2011

Activity (五)

Android應用程式學習筆記

我們把生命周期的所有回調方法列在以下表中,對每個回調方法進行描述以及它是否可以被系統殺掉。


MethodDescriptionKillable after?Next
onCreate()Always followed by onStart().當activity第一次被建立時呼叫該方法,該方法用來完成靜態設置-建立視圖、為lists綁定數據等等。該方法傳入一個Bundle物件的參數,Bundle物件包含了activity前一次的狀態。該方法執行完後,接著一定執行onStart()方法。NoonStart()
    onRestart()
Activtiy已經被停止之後,再次啟動前呼叫onRestart()方法。接著執行的一定是onStart()方法。
NoonStart()
onStart()Activity在讓用戶看見之前呼叫該方法。如果activity到達前台,呼叫onResume()方法;如果activity隱藏起來,呼叫onStop()方法。NoonResume()
or
onStop()
    onResume()在activity開始與用戶互動之前呼叫該方法。Activity在此點是位在activity佇列的頂端,可以接收用戶的輸入。接著一定呼叫onPause()方法。NoonPause()
onPause()當系統開始恢復其他activity時呼叫此方法。該方法是典型用來將為儲存的變動交給永久數據、停止動畫及其他可能會消耗CPU的工作,onPause()裡的工作應該盡可能快速地完成,因為下一個activity將不會被恢復,直到onPause()裡的工作完成。
如果activity回到前台,接著就會呼叫onResume()方法;如果變成用戶看不見,接著就會呼叫onStop()方法。
YesonResume()
or
onStop()
onStop()當activity不再被用戶看見時呼叫onStop()方法,不被用戶看見有可能是因為activity即將被銷毀或是其他的activity已經恢復且覆蓋activity。
如果activity正回來與用戶互動,就會接著呼叫onRestart()方法;如果activity正要停止,接著就會呼叫onDestory()方法。
YesonRestart()
or
onDestroy()
onDestroy()Activity銷毀之前呼叫該方法,這是activity最後接收的呼叫。可能因為activity正在停止(呼叫finish()方法),或是因為系統臨時銷毀activity的使用空間。你可以利用isFinishing()方法分辨這兩個種可能。Yesnothing
注意"Killalbe after"是表示系統是否會在回調方法執行完後的任何時間殺掉activity。三個回調方法標記為"Yes",分別是onPause()、onStop()、onDestroy(),因為onPause()方法是三個方法的第一個,activity一旦被建立,onPause()方法肯定是在程序被殺掉之前最後呼叫的方法-如果系統必須緊急恢復記憶體空間,接著onStop()和onDestroy()可能不會被呼叫。因此你應該利用onPause()方法將決定性數據寫到記憶體。然而你應該選擇保留一些資訊,因為在方法中的任何阻礙程序會阻塞轉到下一個activity而降低用戶經驗。

表記為"No"的回調方法,保護程序不會被殺掉。因此當activity是可被殺的,從onPause()時段到onResume()時段,直到再次呼叫onPause()方法,activity才又可以被殺掉。

Activity (四)

Android應用程式學習筆記

Shutting Down an Activity

呼叫finish()方法就可以關閉activity,你也可以從另外一個activity呼叫finishActivity()方法關閉activity。


Managing the Activity Lifecycle

藉由回調方法管理activity的生命週期對於開發強健且靈活的應用程式來說是相當重要的,activity的生命週期直接受到與它相關的其他activity,它的task及back stack所影響。

activity有三個基本的狀態:
Resumed
Activity運行在前台且擁有用戶焦點。
Paused
其他Activity運行在前台且擁有用戶焦點,但是activity仍是可見的,那就是其他activities顯示在它的上面,其他activtiy部分是透明的或是不會完全覆蓋整個屏幕。被暫停的activity仍是活的,但是系統可能在極低記憶體的狀態下殺掉被暫停的activity。 
Stopped
Activity完全被其他activtiy遮掩(activity現在運行於後台),被停止的activity也仍是活的,然而被停止的activity不會被用戶看見且它可能被系統殺掉,當系統需要記憶體空間時。
如果activity處在暫停或是停止狀態,系統可以從記憶體停止這些activity,不論是要求它們結束或是殺掉它們的程序,當'它們再次被啟動,再全部重建。


Implementing the lifecycle callbacks

當activity轉換狀態,會接收許多回調方法通知。所有回調方法都可以複寫來完成在狀態改變時適合的工作,以下就是生命週期中所有回調方法:



public class ExampleActivity extends Activity {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // The activity is being created.
    }
    @Override
    protected void onStart() {
        super.onStart();
        // The activity is about to become visible.
    }
    @Override
    protected void onResume() {
        super.onResume();
        // The activity has become visible (it is now "resumed").
    }
    @Override
    protected void onPause() {
        super.onPause();
        // Another activity is taking focus (this activity is about to be "paused").
    }
    @Override
    protected void onStop() {
        super.onStop();
        // The activity is no longer visible (it is now "stopped")
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        // The activity is about to be destroyed.
    }
}


這些方法定義了activtiy的整個生命週期,藉由實現這些方法,你可以注意到在生命週期中有三個巢狀迴圈:

  • Entire lifetime-Activity的entire lifetime發生在呼叫onCreate()方法與呼叫onDestory()方法之間,你的activity應該在onCreate()方法中設置"總體"狀態(比如定義布局),在onDestory()方法中釋放所有剩下的資源。例如,如果你的activity有一個執行緒在後台執行從網路下載資料的工作,activtiy在onCreate()方法中建立執行緒,而在onDestory()方法中停止執行緒。
  • Visible lifetime-Activity的visible lifetime發生在呼叫onStart()方法與onStop()方法之間,在此時段中,用戶可以在屏幕上看見activity並與它互動。例如,當新的activity啟動而activity不再可見時,onStop()方法被呼叫。在onStart()與onStop()之間,你可以保有顯示activity給用戶的資源。例如,你可以在onStart()方法註冊BroadcastReciever監視影響UI的改變,在onStop()方法撤銷BroadcastReciever。系統可能在activity的生命週期中多次呼叫onStart()方法和onStop()方法,當activity對於用戶為可見與隱藏之間交替時。
  • Foreground lifetime-Activity的foreground lifetime發生在呼叫onResume()方法與呼叫onPause()方法之間,在此時段中,activity在屏幕上是在所有其他activity前面且擁有用戶焦點。activity會頻繁地轉進與轉出前台,例如,當裝置進入睡眠狀態時呼叫onPause()方法,或是當一個對話框出現。因為經常在此狀態轉換,這兩個方法在程式碼中應該要公平,避免變慢造成用戶在此狀態轉換時需要等待。
下圖顯示這些loops及兩狀態之間的路徑。

在這裡做個小小總結:

1.關閉activity有兩個方法,呼叫finish()及finishActivity()。
2.Activtiy生命週期中有三個迴圈,Entire lifetime、Visible lifetime、Foreground lifetime。
3.Entire lifetime為onCreate()與onDestory()之間,為activity的整個生命週期,主要執行取得資源與釋放資源的工作。
4.Visible lifetime為onStart()與onStop()之間,為activity可以被看見的時間,主要執行與使用者介面相關的工作。
5.Foreground lifetime為onResume()與onPause()之間,為activity被用戶使用的時間。
6.當執行到onCreate()時,用戶還未看見activity,當執行到onStart()時,用戶才看見activtiy。

星期三, 10月 26, 2011

Activity (三)

Amdroid應用程式學習筆記

Starting an Activity

你可以呼叫startActivity()啟動其他activity,傳入Intent物件來描述你想啟動的activity,Intent不是明確指定你想起動的activity就是描述你想執行的動作類型(系統會為你挑選適合的activity,可能是不同應用程式的activity),Intent物件也可以攜帶小量的數據到你想啟動的activity使用。

當你在自己的應用程式完成啟動其他activity,通常都是啟動已知的activity,你可以建立一個intent明確地用類別名稱定義你想啟動的activity是哪個,以下就是一個activity如何啟動另一個名稱為SignInActivity的activity的例子。


Intent intent = new Intent(this, SignInActivity.class);
startActivity(intent);

然而,你的應用程式也想執行一些動作,例如發送電子郵件、編輯簡訊或是狀態更新,既然這樣,你的應用程式也許沒有自己的activities可以執行這些動作,所以你可以使用在裝置上其他應用程式所提供的activity,且這些activity可以執行動作。這是intent有價值的地方-你可以建立一個intent描述你想執行的動作,然後系統啟動來自其他應用程式適合的activity。如果有許多activity都可以完成intent描述的動作,用戶可以選擇其中一個使用。舉例,你想允許用戶寄發電子訊息,你可以如此建立intent:


Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_EMAIL, recipientArray);
startActivity(intent);

EXTRA_EMAIL額外加到intent的是電子郵件地址的字串陣列,當電子郵件應用程式回應這個intent,應用程式讀取intent中的字串陣列。在此狀況,電子郵件應用程式啟動,用戶用完,你的activity就會恢復。


Starting an activity for a result


有時候你可能想要從你啟動的activity接收結果,既然這樣,呼叫startActivityForResult()方法啟動activity取代startActivity()方法,從被啟動的activity接收結果,實現onActivityResult()回調方法,以下為如何建立intent與處理結果:


private void pickContact() {
    // Create an intent to "pick" a contact, as defined by the content provider URI
    Intent intent = new Intent(Intent.ACTION_PICK, Contacts.CONTENT_URI);
    startActivityForResult(intent, PICK_CONTACT_REQUEST);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    // If the request went well (OK) and the request was PICK_CONTACT_REQUEST
    if (resultCode == Activity.RESULT_OK && requestCode == PICK_CONTACT_REQUEST) {
        // Perform a query to the contact's content provider for the contact's name
        Cursor cursor = getContentResolver().query(data.getData(),
        new String[] {Contacts.DISPLAY_NAME}, null, null, null);
        if (cursor.moveToFirst()) { // True if the cursor is not empty
            int columnIndex = cursor.getColumnIndex(Contacts.DISPLAY_NAME);
            String name = cursor.getString(columnIndex);
            // Do something with the selected contact's name...
        }
    }
}

在此例子中,演示了你使用onActivityResult()方法處理activity結果的基本邏輯,第一個條件式檢查請求是否成功-如果成功,resultCode為RESULT_OK-回應的請求是否已知,requestCode配對startActivytForResult()的第二個參數。

contentResolver執行查詢,回傳一個Cursor物件,通過cursor物件讀取結果。