Wednesday, December 22, 2010

開發之氣死人之路II - Second issue in Android

繼上一篇︰Android開發之氣死人之路I後,
這是我第2起案例,一模一樣的程式碼
跑在Android手機上的結果不同
This is my second case , programming is the same, but result in two different status.


Difficult way to develop Android program.

狀況︰
我希望將訊息通知設在上方的"進行中",而非下方的通知欄位。
用了相同method函式請求,卻產出不同結果。

下一篇(完)︰Android開發者應有的認知

Friday, December 17, 2010

Android開發之氣死人之路I

一模一樣的程式碼,在手機裡執行反應居然不一樣



狀況︰
長按後的結果不同。

原因︰
每個按鈕我都有做setOnClickListener和setOnLongClickListener,
後來發現由於電容面板的問題,
有些硬體執行完onLongClickListener後,
會雞婆的幫你執行onClickListener。

實測手機︰
Nexus One VS. Vibo A688

下一篇︰開發之氣死人之路II

Monday, December 13, 2010

進程與生命週期(Process and lifecycles)

以下文章來至Application Fundamentals :
The Android system tries to maintain an application process for as long as possible, but eventually

it will need to remove old processes when memory runs low.
只要環境允許,Android系統都會嚐試著保留著應用程式的進程。但是,如果記憶體很少時,它們還是會被砍殺的。
To determine which processes to keep and which to kill, Android places each process

into an "importance hierarchy" based on the components running in it and the state of those components.
為了能夠決定哪些進程要保留、哪些進程又要砍殺,Android將每個進程放入一個叫「層級優先權」的地方做管理了。這裡面記錄著哪些元件是執行中、哪些元件是在背景執行


Processes with the lowest importance are eliminated first, then those with the next lowest, and so on. 
如果是那種低重要性的(非被使用),會被第1個踢出去,系統會繼續找誰第二、誰第三、以此類推。

There are

five levels
 in the hierarchy. The following list presents them in order of importance:

1.A foreground process
2.A visible process
3.A service process
4.A background process
5.An empty process
以上這五種進程,由高至低,排序了其進程在系統裡的優先權。

底下詳細說明這5種進程。
什麼是前景進程 (foreground process)?

  • It is running an activity that the user is interacting with (the Activity object's onResume() method has been called). - Activity正在被使用者使用的當下(onResume()事件發生時)
  • It hosts a service that's bound to the activity that the user is interacting with. - 一個activity有互動的Service
  • It has a Service object that's executing one of its lifecycle callbacks (onCreate(), onStart(), or onDestroy()). - 有一個Service物件,而且這個Service物件還執行callback回呼函式(像Service裡的onCreate()、onStart()或onDestroy()之類的)
  • It has a BroadcastReceiver object that's executing its onReceive() method. - 有一個廣播監聽物件,而且該廣播還執行了onReceive這個callback回呼函式。
Only a few foreground processes will exist at any given time. They are killed only as a last resort.
因為在同樣的時間裡,只會有少數的前景進程存在,所以它們被排到最最最最最後面,才有機會被系統砍殺。





什麼是可用進程 (visible process)?

A visible process is one that

doesn't have any foreground components, but still can affect what the user sees on screen.
可用進程沒會有任何的前景元件執行(像Activity),但是呢,它卻仍會影響使用者所看的螢幕畫面。

  • It hosts an activity that is not in the foreground, but is still visible to the user (its onPause() method has been called). This may occur, for example, if the foreground activity is a dialog that allows the previous activity to be seen behind it. - 像是我們叫出了一個畫面裡的訊息對話視窗,此時原程式的onPause()被呼叫,我們稱此時該進程為可用進程
  • It hosts a service that's bound to a visible activity. - 一個綁到可用activity中的Service

A visible process is considered extremely important and will not be killed unless doing so is required to keep all foreground processes running.
可用進程也是非常重要的,系統會盡量的讓所有這些前景進程保持運作中,除非非不得己,才會砍掉。


什麼是Service進程 (service process)?
  Although service processes are not directly tied to anything the user sees, they are generally doing things that

the user cares about (such as playing an mp3 in the background or downloading data on the network), so the system keeps them running unless there's not enough memory to retain them along with all foreground and visible processes.
雖然Service進程不是對使用者所觀看到的畫面產生直接影響的元件,但是它們一般都被拿來做一些使用者在乎的事,像是在背景播mp3啦、從網路下載檔案啦…,所以,系統在記憶體不足以前,也會如同前景進程和可用進程一樣努力的保持著它的作業。


什麼是背景進程 (background process)?
A background process is

one holding an activity that's not currently visible to the user (the Activity object's
onStop() method has been called).
背景進程是一個使用者沒有在使用狀態的activity(此時Activity的onStop()會被系統呼叫)
因為通常系統如果呼叫到程式的onStop時,幾乎可以說該應用程式已經不是使用者當下想執行了。所以Android可以很大膽的先處理掉這種進程,這麼做,一點都不影響使用者的使用體驗。


什麼是空進程 (empty process)?
An empty process is one that

doesn't hold any active application components.
The only reason to keep such a process around is
as a cache to improve startup time the next time a component needs to run in it.
 
空進程是一個沒有執行任何啟動中的應用程式元件的進程。它存在唯一的理由就是保存cache,好讓下一次啟動元件時需要的元件,可以被快速的被找到和執行。
The system often kills these processes in order to balance overall system resources between process caches and the underlying kernel caches.
這種進程最容易被砍殺,為了讓系統保持良好的循環平衡。

何謂Service

Service文件裡提到︰
A Service is an application component representing either an application's desire to perform a longer-running operation while not interacting with the user or to supply functionality for other applications to use.
Service是應用程式的其中一種元件,它意謂著當一隻APK在不需要與使用者互動時還要運作,因而存在。

Each service class must have a corresponding <service> declaration in its package's AndroidManifest.xml. Services can be started with Context.startService() and Context.bindService().
Service在使用時,必須在AndroidManifest.xml裡宣告

使用Service的方式有2:
1.Context.startService()
A facility for the application to tell the system about something it wants to be doing in the background.
Service是一個讓應用程式告訴系統想在背景做些什麼事的工具。
2.Context.bindService()
A facility for an application to expose some of its functionality to other applications.
Service是一個讓應用程式展示它內部函式功能給其它應用程式的媒介。


Note that services, like other application objects, run in the main thread of their hosting process. This means that, if your service is going to do any CPU intensive (such as MP3 playback) or blocking (such as networking) operations, it should spawn its own thread in which to do that work.
Service就像其它應用程式的物件一樣,在該程序Process的主執行緒運作著。
所以,當我們要用到像高度的CPU運算(像是播放MP3)或是一些會卡住的運算(像網路運算),那麼就應該建立出一個自己的執行緒,好讓工作能順利完成。

The IntentService class is available as a standard implementation of Service that has its own thread where it schedules its work to be done.
IntentService是一個標準實作Service的類別,它呢,擁有一個獨立的執行緒,靠這個類別,就能完成上述所提到的「獨立完成作業」。


Processes and Threads一文中提到︰

 When the first of an application's components needs to be run, Android starts a Linux process for it with a single thread of execution.



By default, all components of the application run in that process and thread.
However, you can arrange for components to run
in other processes
, and you can spawn additional threads for any process.

當應用程式的元件(指Activity、Service、BroadcastReceiver和ContentProvider)要啟動的時候,Android會去開啟Linux裡進程的單一執行緒,開始做運算處理。
預設來說,應用程式中的所有元件,都會在"那個"進程和執行緒運作。
所以,如果要制定元件在某個特定進程運作時,程式設計師可以自行決定要在哪個另外的進程或新增的執行緒下去執行應用程式。

參考網站
1.書生雜記
2.程式搖滾

Process與Thread

一個應用程式,會開啟一個Process
一個Process,可以被程式設計師開出多個Thread

同一個process內的Threads可以共享Code、Data Section及OS Resources

一個Thread 就是一個小型的 Process ,
若我們把 Process 分為兩個部份-----Threads 和 Resources,
Threads 就是這個 Process 的動態執行者(Dynamic Object)

附上Process和Thread的差別
           
The major difference between threads and processes is 
1.Threads share the address space of the process that created it; 
processes have their own address.

2.Threads have direct access to the data segment of its process; 
processes have their own copy of the data segment 
of the parent process. 

3.Threads can directly communicate with other threads of its process; 
processes must use interprocess communication to communicate with sibling processes. 

4.Threads have almost no overhead; processes have considerable overhead.

5.New threads are easily created; new processes require duplication of the parent process.

6.Threads can exercise considerable control over threads of the same process; 
processes can only exercise control over child processes. 

7.Changes to the main thread (cancellation, priority change, etc.) 
may affect the behavior of the other threads of the process; 
changes to the parent process does not affect child processes. 

何謂Task和Back Stack

撰寫時間︰2010/12/13 12:38
修改時間︰2012/07/10 10:38
修改次數︰2

一、前言
假設今天我們的APP裡要寫一個新功能︰「撰寫e-mail連絡開發者」。
該怎麼做?
我們開發人員要寫一個全新的頁面才能做到嗎?

這個答案是否定的。

Android提供了好用的Intent,
我們只要簡單的使用它,
就可以叫出系統發送e-mail的畫面,
當使用者撰寫好並發送出去後,
畫面又回到原本觸發發送e-mail的畫面。

這件事很奇怪,
發送e-mail的頁面不是我們程式撰寫的,
但是為什麼使用體驗就好像是APP裡寫出來的東西?
原來,
這一切是因為Android系統背後,藏了一個Stack(堆疊)機制。

二、文章開始
一個APP通常來說,都擁有數個Activity。
每個Activity都能夠執行個自的任務,
甚至是啟動另一個Activity。
舉例來說,當使用者開啟了e-mail軟體,
他們看到條列式的e-mail列表清單,
當使用者點擊了列表清單,
一個新的Activity又會開出來,
顯示那些e-mail的內容。

使用者在看e-mail清單列表,
又看了裡面的e-mail內容,
一次一次的舉動,
每個Activity頁面都被存進了任務容器(collection of activities),
我們稱這個容器為背景堆疊(back stack)。

當一個Activity啟動了另一個Activity之後,
新的Activity就被放進堆疊的最頂層,
而之前的Activity則被保留在堆疊中,
但是屬於暫停的狀態。

一旦Activity遭暫停(stop),
系統就會自動將該頁面的使用狀態儲存起來。
當使用者從新頁面按下返回按鈕後,
新的頁面被消毀(destroy),
而舊的頁面在此時又會被恢復(resume)。
也因此,堆疊的特性是「後進先出」。
圖1. 這張圖表顯示出每一個新的Activity是如何被放進背景堆疊中。當使用者按下返回鍵,當下的Activity就會被消毀(destroy),然後會將前一個Activity恢復(resume)給使用者。

======底下文章為2010/12/13撰寫======
To the user, it will seem as if the map viewer is part of the same application as your activity, even though it's defined in another application and runs in that application's process. Android maintains this user experience by

keeping both activities in the same task. Simply put, a task is what the user experiences as an "application." It's a group of related activities, arranged in a stack.
Task是使用者在使用Application時的User Experiences。如果今天我們的APK功能要開啟Google map,也許我們程式會做連結直接開啟MAP。但這個MAP卻不是我們寫的。但從我們的程式到展開MAP卻感覺是一體的。那是因為Google想要照顧這部份的使用者經驗。
Task寫在Stack,也就是堆疊裡。

The root activity in the stack is the one that began the task — typically, it's an activity the user selected in the application launcher.

The activity at the top of the stack is one that's currently running — the one that is the focus for user actions. When one activity starts another, the new activity is pushed on the stack; it becomes the running activity. The previous activity remains in the stack. When the user presses the BACK key, the current activity is popped from the stack, and the previous one resumes as the running activity.
Task裡放的,就是我們在使用一隻應用程式時,所有和這隻應用程式相關的Activity的存放空間。
程式會依我們最先開啟的Activity,在堆疊裡,開出一個Task(任務)空間,然後呢,它被放在Task的最頂層。如果此時又開了一個新的Activity,就會把前一個Activity往下推,而成為你眼前看到的畫面。之前那個Activity還是在堆疊裡,所以如果此時你又按了[返回]鍵,目前的新畫面,會"彈出"這個堆疊,然後把之前的Activity,利用onResume()的方式,呼叫回來你面前。

A task is a stack of activities, not a class or an element in the manifest file.
Task是一個Activity的堆疊,而非類別或任何manifest檔裡你看的見的物件。

Sunday, December 12, 2010

IntentService的功用

盧育聖的網站中,教了大家很清楚的IntentService的概念,但看了還不是很懂。
因為,這要從Thread講起(我接下來要說的,大家可以參考高煥堂-物件導向技術與執行緒模式一書找到更完整的解說)。
Android在傳遞訊息時,主要用到Looper和Message,每一個執行緒,都有一個Looper。
主畫面(UI)的Thread本身就有Looper去Handler(處理)各種訊息,但是,程式裡new出來的副Thread,當中的Looper必須被new出來,因為android沒有替副Thread做Looper。
想像一下,Looper是運轉中的果汁機,Message是柳丁,Android傳遞訊息的原理就是將Message丟進Looper,再由Handler(老闆娘)去處理看是要賣還是要自己喝。
在知道上面Thread、Looper、Message和Handler的概念後,我們再回到盧育聖的網站裡看。
IntentService繼承Service,我們先前知道,Service的幾個良好的特性︰
1.系統當發現資源不足,而砍殺現有程序時,Service是最後幾名被砍的,不會馬上被砍。
2.Service不用畫面就能做事情

所以,當我們用Intent去開啟IntentService時,就可以很放心的將要在背後做的事,放在IntentService去做,不用再擔心會被系統砍掉!

這裡還有asynctask和IntentService的差別。倒也可以順便看看。

總之,IntentService幫我們處理掉煩人的Looper、Message和Handler啦!

Service一些手札記錄

以下文章來至於Android guide

it's started by calling Context.startService() and stopped by calling Context.stopService(). It can stop itself by calling Service.stopSelf() or Service.stopSelfResult()
靠Context的method:startService()來啟動,
並靠stopService()關閉
另外,Service也能自行自殺:stopSelf()(果然具有服務精神啊!)


Only one stopService() call is needed to stop the service, no matter how many times startService() was called.
只需要呼叫一次stopService()就能關閉Service了。但是startService()愛叫幾次都行!(服務生真是周到!)

The two modes are not entirely separate. You can bind to a service that was started with startService().
開起服務生後,還能綁架他。
For example, a background music service could be started by calling startService() with an Intent object that identifies the music to play.
當叫服務生播音樂後,
Only later, possibly when the user wants to exercise some control over the player or get information about the current song, would an activity establish a connection to the service by calling bindService().
客人想要看歌曲資訊,也許這時後我們能呼叫綁架服務生。
In cases like this, stopService() will not actually stop the service until the last binding is closed. 
這時候,就算要關閉服務生,也因為被我們綁架了,他也逃不了了,除非我們解繩。

另外,服務生因為不是最重要的,所以生命短暫︰
他只有
void onCreate()  活吧!
void onStart(Intent intent)  做事了!
void onDestroy() 去死吧!
However, onStart() is called only for services started by startService().

當然,如果服務生被綁架了,事情就沒有那麼單純了!
快來看看會發生什麼事!?
 會產生3個Callback
IBinder onBind(Intent intent)
boolean onUnbind(Intent intent)
void onRebind(Intent intent)

The onBind() callback is passed the Intent object that was passed to bindService and onUnbind() is handed the intent that was passed to unbindService().
onBind()函式被拿來傳送Intent(意圖),
If the service permits the binding, onBind() returns the communications channel that clients use to interact with the service.
onBind()會回傳管道上和Service互動的資訊

keep in mind that any service, no matter how it's started, can potentially allow clients to bind to it, so any service may receive onBind() and onUnbind() calls.

因為任何的Service都有可能被綁架,所以你會看到實作Service時,都會有onBind()的出現
不管你是用bindService還是startService,總之,Service都有可能接到onBind()呼叫啦!

Tuesday, December 7, 2010

在Ubuntu10.04增加Android2.3的adb環境變數

1.終端機裡打上︰
sudo gedit '/etc/environment'
2.最後一行加上
:/media/Data/android-sdk-linux_86/platform-tools
3.重開機

adb工具在android2.3好像移到了platform-tools目錄(待查證)
(查證結果︰沒錯,果真被移至此
所以環境變數必須重新設定,才能繼續在任何目錄使用adb工具)