顯示具有 Activity 標籤的文章。 顯示所有文章
顯示具有 Activity 標籤的文章。 顯示所有文章

2014年4月20日 星期日

好用的 Activity.getView()

在 Activity 中最常看到的函式呼叫,就是 findViewById(),常見用法如下:

由於 findViewById() 傳回的是 View 這個通用型別。因此實務上每次都要強制轉型成實際的型別,這樣的程式碼看起來實在有點礙眼。

要解決這樣的問題,你只要在 Activity 中,加入底下這個 getView() 函式。

之後,你就可以將原先的 findViewById() 呼叫改寫成底下這個方式:

一個小技巧,卻可以讓你的程式碼看起來清爽許多。當然在 Fragment 中,你也可加上自己的 getView(),至於如何寫?建議自己研究一下。


繼續閱讀全文...

2010年9月14日 星期二

小心,AsyncTask 不是萬能的

Don't only use AsyncTask for your download task

要進入 Android 應用開發之門,真的一點都不難,不就是 Java 嘛。這是我最常聽到,剛跨過入門檻開發者告訴我的一句話。

這句話其實是沒有錯的,Android 應用開發的入門檻,比起其他平台,已經低了許多。要跨過這門檻,的確是輕鬆容易許多。不過,如果要從入門到進階,邁向下一個關卡,你第一個要了解的是 Activity 的生命週期Process 的生命週期,而且是要『透 . 徹 . 了 . 解』。這一步很重要,卻被許多開發者輕忽了。

尤其這 Activity 的生命週期,實際上的行為會比你從文件上看到的說明還來的複雜。也因此,我發現有不少,即使已有多個 Android 應用開發經驗的開發者,在開發 Android 應用時,還是栽了不少跟斗。這第一個問題,就出在這些開發者,還是沒達到我說的『透徹了解』境界。因此,今年的進階應用開發課程,特地將這一部分加入進來,希望對想踏入進階之門的開發者,有所助益。

好了,如果你已經有一段 Android 應用的開發經驗,那應該知道在 Main-thread(UI-thread) 中,你不能執行一件需時 5 秒以上的工作,例如網路或資料庫的存取、音樂的播放等等。要不然你的應用就會產生 ANR 錯誤。要解決這個 ANR 錯誤,唯一的方法就是自行建立一個新的 Thread 物件,並將該費時的工作放在 Thread.run() 中執行。關於如何解決 ANR 的細節,我建議你先讀 Painless threading,這是一篇值得一讀的好文章。

在這篇文章中,介紹了從 Android 1.5 才加入的 AsyncTask。AsyncTask 很好用,同時我也建議你研究他的 原始碼。AsyncTask 就是太好用了,有些開發者就認為,單用 AsyncTask 就能解決他的問題。其實,我早在請將要執行很久的程式碼,放在 Service 中執行這篇中,就已提過。單將費時的程式碼放在 Thread.run() 中執行,還是不夠的,你只解決一半的問題。不過,多數開發者不是便宜行事,就是不相信我說的。這些便宜行事的開發者,就是在賭這系統強制殺掉你應用的機率有多少;而那些不相信我說的,就是因為他沒有透徹了解 Activity/Process 的生命週期。

完整解決費時工作的方法,不僅要將費時的工作放在 Thread.run() 中執行,還要將這個 Thread 放在 Service 中執行。

你要知道 Android 的四大元件,Activity, BroadcastReceiver, Servcice and ContentProvider,除了 ContentProvide 外,全都是在 main-thread 中執行。而這些元件中,就只有 Service 的生命週期是最持續(長久)的。Activity 只要執行到 onPause(),BroadcastReceiver 只要離開 onReceiver(),系統隨時會殺掉這些元件,而且機率還很高。Service 當然也是會被系統砍掉,只不過它的優先順序,排在較低等級。自然被系統砍掉的機率就低很多。你還可以更進一步利用 Serivce.startForeground() 降低你被系統殺掉的優先順序。關於這部分,你要熟讀 Process 的生命週期What is a Service?

其實為了減輕開發者的負擔, Android 1.5 已經加了 IntentService 這個新類別。如果你要寫個用到網路的應用,用這個 IntentService 才是你的完美解決方案。

要使用這個 IntentService 其實很簡單,你只要繼承這個 IntentService 並將該項費時的工作,移到 onHandleIntent() 中即可。onHandleIntent() 是被 non-UI thread 所喚起的。因此在這裏面你可以放心地去執行你的下載工作。

下次,我們來研究一下這個 IntentService 的原始碼,看他是如何做的。

參考資料:


繼續閱讀全文...

2008年12月29日 星期一

Intent 用法大公開

How to use Intent to send an email, SMS, open a web browser, show map, etc.?

Intent 應該算是 Andorid 中特有的東西。你可以在 Intent 中,指定要應用程式執行的動作 (view, edit, dial),以及應用程式執行該動作時,所需要的資料。都指定好後,只要透過 startActivity(),Android 系統會自動尋找,最符合你指定要求的應用程式,並喚起執行該應用程式。

不過,這部份的文件還不是很完整。Reference of Available Intents 有列一些。底下是我收集的一些用法,分享出來給有需要的你。有些還沒有實際驗證過,如果發現有錯誤,或有新的用法,也請告訴我。

顯示網頁

顯示地圖

路徑規劃

撥打電話

傳送 SMS/MMS

傳送 Email

顯示聯絡人清單

顯示某個朋友的詳細資料

播放多媒體

從圖庫中回傳選到的圖片

啟動照相機,並將相片存在指定的檔案中

Market 相關

Uninstall 應用程式

安裝 APK 檔


繼續閱讀全文...

2008年12月1日 星期一

記得要在程式中,處理鍵盤開啟或關閉的動作

Handle the open/close keyboard usage for your Android applications

之前寫了一個 Android 版的世界時鐘 (world clock) 程式,自認為應該沒什麼大問題了,就丟上網讓使用者開始下載。嗯,下載數是不少,心喜之餘,還是有幾個人反應,無法完成註冊的問題。

由於,當時 G1 手機沒有到手,只能用模擬機測,測了半天,一直無法重現使用者提到的問題。只好再檢視註冊相關的程式碼,一樣,看了不下十遍,還是沒看到什麼問題。終於,有天想到使用者要註冊時,應該要輸入使用者名稱及註冊碼,而實機不像我們在模擬機上,直接用 PC 的鍵盤輸入,他應該要打開鍵盤輸入才行。會不會,是這個問題的關係?

首先,第一個是做的是,要如何在模擬機上,模擬打開鍵盤這個動作?告訴你,你在網路上一定找不到這樣的資訊。今天就分享給你,這可是我嘗試了許久,才發現的秘訣。

告訴你,答案就是按下 PC 鍵盤上的 KEYPAD_7 or KEYPAD_9 鍵。疑,這不就是 如何以程式的方式,旋轉 Android 螢幕 文章中,提到的旋轉模擬機螢幕方向 (直立 <-> 水平) 的按鍵嗎?的確是,所有的文件都只說明,這是用來旋轉螢幕的按鍵,根本沒人提到,這也是模擬鍵盤打開或關閉的按鍵。

還來我才知道,在實機上,系統並不會自動隨著機器的旋轉,而自動旋轉螢幕方向。只有當你打開鍵盤時,系統才會自動將螢幕轉成水平。當你收起鍵盤時,才又將螢幕轉成垂直方向。

那這開啟或關閉鍵盤 (正確地,應該說旋轉螢幕方向) 的動作,為什麼會造成程式的問題呢?

原來,這螢幕的旋轉,是靠重新起動你的 activity (不是整個應用程式喔) 而達成的。蝦米,這是什麼意思?我發現,當螢幕準備要開始旋轉時,系統會先殺掉你現在的 activity,接著呼叫底層的顯示系統,旋轉螢幕的方向,最後才又重新啟動你的 activity。從使用者看來,只是螢幕轉個方向而已,什麼事也沒發生。但從程式面來看,這可是已經經歷過一次生死輪迴了。

我寫個簡單的程式,證明給你看。

首先,當你執行這個程式後,你會看到底下這樣的結果。

onCreate(null)
onStart()
onPostCreate()
onResume()
onPostResume()

可是當你按下 KEYPAD_7 ,將螢幕轉成水平的方向,你會看到底下這樣的結果。

onSaveInstanceState()
onPause()
onStop()
onDestroy()
onCreate(Bundle[{android:viewHierarchyState=
  Bundle[{android:views=
  android.util.SparseArray@43370a48}], key=123}])
onStart()
onRestoreInstanceState()
onPostCreate()
onResume()
onPostResume()

看到了嗎? onDestroy() 證明系統殺了你的 activity, onCreate() 則是又重新啟動你的 activity。

我原先無法讓使用者無法完成註冊的問題,就是有些 local variables 的值,因為這重起 activity 的動作,而不見了。

這個經驗,讓我學到了,千萬要有程式隨時會被系統殺掉的準備

有經驗的你,可能會發現為什麼 activity 上 EditText 內的文字,不會隨著旋轉螢幕的動作,而重設。翻翻 EditText 的原始碼,你會發現其實 EditText 也有特別針對這樣的行為來處理。所以說,如果你有寫自己的 custom widget 時,別忘了也要做類似的處理。不過, widget 的處理動作,和 activity 完全不同。有機會的話,再談這部份。

後記,在寫這篇時,又去 Google 了 一下,看到 Rotational Forces…On Your Android App 中,也有詳細提到關於旋轉螢幕的問題處理。值得參考。


繼續閱讀全文...