星期五, 9月 23, 2011

View Hierarchy

Android應用程式學習筆記

View Hierarchy

在android平台上,你使用了View和ViewGroup節點的階層定義了activity的UI,如以下顯示。這個階層數可以依你的需要求變的簡單或者複雜。你可以用android事先定義的部件與佈局或者用你自己客製的View物件來建構階層。


為了附加view階層樹到屏幕來渲染屏幕,你的activty必須呼叫setContentView()方法及引用根節點物件。android系統接收引用並用它來廢止、測量或繪製該樹,階層的根節點請求它的子節點自己繪製-反過來,每一個ViewGroup節點都有責任去呼叫它的子節點讓它們自己繪製,它們可能要求父節點的大小與位置,但是最後父節點決定了子節點該要多大。android會依序解析你的布局元件(從階層樹的最頂端)。

以下我們做個小小總結以上內容:
在android平台中,每個畫面都是一棵階層樹,而階層樹是由View物件與ViewGruop物件所組成。系統在顯示畫面時,是從階層樹的根節點依序往子節點呼叫,如此繪製出畫面。

星期四, 9月 22, 2011

Activtiy (一)

Android應用程式學習筆記

Activities

Activity是應用程式的組件之一,提供能與使用者互動的屏幕,比如,撥打電話、接聽電話、寄送電子郵件或者觀看地圖。每個activity是一特定視窗,在視窗你繪製它的使用者介面。視窗一般是填滿整個屏幕,但是也可能小於屏幕。

應用程式通常由許多activities組成,且彼此之間並沒有太緊密的連結。通常情況下,應用程式中的一個activity為"main"activity,該activity在應用程式第一次啟動時顯示給使用者。每個activity皆能啟動其他activities去執行不同的動作。每次一個新的activity啟動,前一個activity就會停止,但是系統會保留前一個activity於佇列(back stack)中。當新的activity啟動時,新的activity就會被放入佇列(back stack)中,並取得使用者的焦點。佇列遵守了"先進後出"的特性,所以,當使用者用完目前的activity且按下"BACK"鍵時,目前的activity就會被拋出佇列並銷毀,而前一個activity恢復運行。

當一個activity因為新的activity啟動而停止,它會通過activity的生命週期的回呼方法來通知狀態上的改變,一個activity可能接收許多個回呼方法,基於狀態的改變-不論是系統創建、停止、恢復或銷毀activity-且每個回呼方法都提供你機會去執行適合改變狀態的工作。例如,當activity停止,你的activity應該釋放較大的物件,比如,網路或資料庫的連結,當activity恢復,你可以重新獲得必需的資源。


以上是官網的內容,看起來真的有些霧煞煞。以下就做個小小總結。
總結:
Activity並沒有適合的翻譯,我們就都用activity來說吧。
Activity是android應用程式中四種組件其中一種,它是使用者與應用程式互動的接口,使用者操作應用程式都是透過activity來完成的,比如點擊按鈕或填寫一些內容等等。它有自己的生命週期,生命週期中有許多狀態,每個狀態都有一個回呼方法,當activity狀態改變時會回呼對應的方法來完成狀態改變所需要執行的工作。

Android應用程式

Android應用程式學習筆記

The Androidmanifest's file

Declaring component capabilities

在之前學習到如何激活組件,我們可以使用Intent物件來啟動activities、services及broadcast receiver,你可以這樣做,在intent物件中明確地命名目標組件,intent的真正威力在於intent action的觀念,有intent action你可以輕易的描述想執行的動作型態,並允許系統去找裝置上能執行該動作的組件且啟動它。如果有許多組件都能完成intent描述的動作,然後使用者選擇一個來使用。

系統辨識可以回應intent的組件的方式是藉由比較intent接收到在裝置上其他應用程式的the androidmanifest's file的意圖過濾器(intent filters)。

當你在the manifest's file中宣告組件時,你可以在組件屬性中選擇包含意圖過濾器,因此,它才可以回應其他應用程式的意圖。你可以為你的組件增加<intent-filter>標籤來宣告意圖過濾器。

例如,電子郵件應用程式有一個用來撰寫新郵件的activity,可以在the androidmanifest's file宣告意圖過濾器來回應"send"意圖。在你的應用程式的一個activity可以產生有"send"動作(ACTION_SEND)的意圖,系統配電子郵件應用程式的"send"activity,並在當你用startActvity()方法傳遞意圖啟動activity。

好了,就以上簡短的內容做小小的總結。

總結:
我的應用程式中的組件可以被其他應用程式所調用,這是因為我的組件允許其他組件調用。那要怎麼允許其他組件調用就是要在manifest檔案中做一個宣告,用<intent-filter>標籤宣告,這樣就能允許其他組件調用了。其他更詳細內容會在之後花一些時間寫成文章。

星期三, 9月 21, 2011

Application components

Android應用程式學習筆記

Application components

應用程式組件是組建android應用程式的重要區塊,每個組件都是系統能進入應用程式的不同進入點。不是所有組件都有給使用者實際進入點,有些是要依賴其他組件,但是每個組件都有它自己的實體和扮演的角色-每個組件都有獨一的建立區塊來幫助你完成應用程式的完整行為。

有四種類型應用程式組件,每種類型都有其目的以及生命週期。

以下就來簡單介紹這四種類型組件:

Activities
簡單地來說明activity的意思,可以解釋一個activity顯示一個使用者介面。例如,一個電子郵件應用程式可能有一個activity來列表顯示所有新郵件的介面,另一個activity來顯示撰寫郵件功能的介面,另一個activity顯示讀郵件的介面。在電子郵件應用程式中有許多activities通力合作拼合成使用者的使用體驗。而activities彼此之間是獨立的,因此,不同的應用程式可以啟動這些activties中的任何一個activity。例如,攝影應用程式可以啟動電子郵件應用程式的activity來撰寫新郵件,為了與朋友分享照片。
實現一個activity要繼承Activity類別。
Services
service是運行在後台的組件,用來執行長時間的操作或執行遠端進程的工作。與activity不同,service是不提供使用者介面。例如,一個service可能在後台播放音樂,當使用者在不同應用程式,或者從網路取得數據且不會阻塞正在與使用者互動的activity。其他組件也能啟動service並讓它運,或者綁定它與它互動。
實現service必須繼承Service類別。
Content provider
Content provider主要功能在管理應用程式分享的數據。你可以儲存數據在檔案系統、SQLite資料庫、網路、或者其他你得應用程式能夠存取的儲存設備,通過content provider,其他應用程式可以查詢甚至修改這些數據。例如,android系統提供content provider管理使用者的聯絡人資訊。因此,有適合許可的應用程式可以查詢content provider的部分,去讀及寫私人的資訊。
content provide也可以用來讀及寫你的應用程式私有的、不想分享的數據。
Broadcast receiver
Broadcast receiver是用來回應系統廣播的公告,許多廣播來自系統-例如,廣播公告螢幕已經關閉、電池為低電量或以取得相片。應用程式也可以初始一個廣播,例如,讓應用程式知道數據已經下載ˇ到裝置中,並且已準備好可以使用。雖然,broadcast receiver不提供使用者介面,它們可以在廣播事件發生時產生狀態列來提醒使用者。更常見地,廣播接收器就是其他組件的"出入口",也被命令做少量工作。
 Broadcast receiver繼承自BroadcastReceiver類別,每個廣播透過Intent物件傳遞訊息。
 Android系統獨特的設計是任何應用程式可以啟動其他應用程式的組件。例如,如果你想使用者用攝影機擷取相片,有其他應用程式也可以做到,那你的應用程式也可以用此應用程式來完成擷取相片的功能,取代自己開發。你不需要合併或者甚至連接攝影應用程式的程式碼,取而代之的是你可以輕易地攝影應用程式的activity來擷取相片。當完成後,相片甚至可以回傳到你的應用程式,所以你可以使用相片,對使用者來說,相機似乎就是應用程式的一部份。

當系統啟動一個組件,它會為應用程式產生進程,且實作組件需要的類別。例如,如果你的應用程式攝影應用程式擷取相片的activity,activity運行在屬於攝影應用程式的進程中,而不是在你的應用程式的進程中,因此,不像在大部分平台的應用程式,android應用程式不會有單一的進入點。

因為系統執行應用程式於分開的進程中,對其他應用程式有文件權限來限制存取,你的應用程式無法直接啟動其他應用程式的組件,然而,android系統可以,所以,激活其他應用程式的組件,你必須傳遞一個訊息給系統,你的intent物件來指定要啟動的特定組件,然後系統為你啟動組件。

User Interface

User Interface

在android應用程式中,使用者介面是由View與ViewGroup物件建立而成。View與ViewGroup物件有許多類型,每一個都是繼承自View類別。

在Android平台上,View物件是使用者介面的做基本組成單元。View類別為"widgets"的基礎子類,它提供實現UI的物件,比如像是按鈕。ViewGroup類別為"Layout"的基礎子類,它提供不同類型的布局(layout)結構,比如像是線性布局、相對布局。


Service(八)

Android應用程式學習筆記

Running a Service in the Foreground

Service不僅只在後台執行,也可以讓service在前台運行,只是這樣的用法比較少。

只要呼叫startForeground()啟動service,就可以讓service在前台執行。這個方法有兩個參數,第一個參數是整數,只用來標識notification。第二個參數是Notification物件。

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION, notification);

停止service只要呼叫stopForeground()。


Managing the Lifecycle of a Service

service的生命週期比起activity的簡單多了,然而,密切關注你的service如何產生及如何銷毀的甚至更重要,因為service可以在後台執行,不會被使用者意識到。

service生命週期可以分成兩部分來看:
  • A started service
    Service由其他組件在呼叫startService()方法產生,service會無限地運行,藉著自己呼叫stopSelf()停止自己,或者其他組件呼叫stopService()來停止service,當service停止後,系統銷毀。
  • A bound service
    service由其它組件呼叫bindService()產生,客戶端通過IBinder與service通訊,客戶端可以透過呼叫unbindService()關閉與service的連結。假設許多客戶端綁定在同一個service,當它們都不再與service連結時,系統就會銷毀service。
以下你可以練習來幫助了解生命週期

public class ExampleService extends Service {
    int mStartMode;       // indicates how to behave if the service is killed
    IBinder mBinder;      // interface for clients that bind
    boolean mAllowRebind; // indicates whether onRebind should be used

    @Override
    public void onCreate() {
        // The service is being created
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        // The service is starting, due to a call to startService()
        return mStartMode;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // A client is binding to the service with bindService()
        return mBinder;
    }
    @Override
    public boolean onUnbind(Intent intent) {
        // All clients have unbound with unbindService()
        return mAllowRebind;
    }
    @Override
    public void onRebind(Intent intent) {
        // A client is binding to the service with bindService(),
        // after onUnbind() has already been called
    }
    @Override
    public void onDestroy() {
        // The service is no longer used and is being destroyed
    }
}



星期二, 9月 20, 2011

繼承IntentService實作started service

Android應用程式學習筆記

繼承IntentService實作started service

之前已學習到started service有兩種實現方式,一種是繼承IntentService類別,另一種是繼承Service類別,今天就來實現一下繼承IntentService的started service。

1.首先開啟新專案HelloIntentService
2.main.xml產生兩個按鈕,一個是啟動service,一個是停止service
3.HelloIntentService的activity執行按鈕按下啟動service及停止service

啟動service:

Intent intent = new Intent(this , HelloIntentService.class);
    startService(intent);
停止service:

Intent intent = new Intent(this , HelloIntentService.class);
    stopService(intent);



4.在HelloIntentService/src目錄下新增.java文件


package test.hellointentservice;

import android.app.IntentService;
import android.content.Intent;
import android.os.IBinder;

public class HelloIntentService extends IntentService {

public HelloIntentService(){
super("IntentService");
}

//當service第一次被啟動時,系統第一個呼叫此方法,接著才會呼叫其他方法。
@Override
public void onCreate(){
super.onCreate();
System.out.println("Service--------->onCreate");
System.out.println("thread-------->" + Thread.currentThread().getId());
}

@Override
public void onStart(Intent intent , int startId){
super.onStart(intent, startId);
System.out.println("Service------->onStart");
System.out.println("thread-------->" + Thread.currentThread().getId());
}

@Override
protected void onHandleIntent(Intent intent){
System.out.println("Service--------->onHandleIntent");
System.out.println("intent.flag--------->" + intent.getFlags());
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) {
             }
         }
     }
}
//started形式的service所必須複寫的方法,組件呼叫startService()方法後,系統會自動呼叫此方法。
@Override
public  int onStartCommand(Intent intent , int flags , int startId){
System.out.println("service--------->onStartCommand");
System.out.println("thread-------->" + Thread.currentThread().getId());
return super.onStartCommand(intent, flags, startId);
}
//bound形式的service必須複寫的方法
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
System.out.println("Service---->onBind");
return null;
}
//當service銷毀時呼叫此方法。
@Override
public void onDestroy(){
super.onDestroy();
System.out.println("Service------->onDestroy");
}
}

IntentService執行時會產生新的thread來完成工作,因此我們就來試試是否如此。在每個方法都加上System.out.println("thread-------->" + Thread.currentThread().getId())來看看現在是哪一個執行續。
其中也要注意,我們之前說過能複寫onCreate()、onDestroy()、onStartCommand()等方法,但唯有onBind()方法不需要呼叫super類別,所以我們在複寫時都有加上super.類別。

執行結果如下

從中可以發現activity啟動intentservice的順序。
activity呼叫startService()啟動service ---> 系統呼叫onCreate()產生新的執行續 ---> 系統呼叫onStartCommand() ---> 呼叫onStart(),傳遞intent物件到onHanldeIntent() ---> 呼叫onHandleIntent(),執行service工作 ---> 工作完成,service銷毀,呼叫onDestroy()。

因為service第一次啟動,所以會先呼叫onCreate()方法。
給service執行的工作放在onHandleIntent()方法中。

另外你可以試試,在service工作還沒完成之前把activity關閉,看看service是不是會受到影響。
那我們發現是不會的,activity關閉後,service並沒有因此停止,而是繼續執行直到工作完成。