Android文字時鐘 — Part3

fhdis發表於2014-02-17

前面的文章中,我們在主螢幕上新增了一個應用小部件,但並不能顯示任何真實資料。看上去沒什麼實際用處。在這篇文章中,我們將在小部件上顯示時間。

為了在小部件上更新時間,我們將使用IntentService。相對於通過呼叫Context.startService(Intent intent)啟動的一般Android Service,IntentService比較特殊——一旦動作(Action)執行完畢就會自動關閉。IntentService非常適合定期執行的細粒度操作。與後臺服務不同,這些操作的不會執行很長時間,因此工作管理員無法發現並殺死這些操作。

為了實現IntentService介面,必須要覆蓋建構函式和onHandleIntent()方法,還需要宣告一個DateFormat,後面將會用到。

每次IntentService啟動時都會呼叫onHandleIntent()方法,方法執行完畢服務會自動關閉。我們還需要一個自定義動作用來觸發元件更新。

如果想讓獲取的時間儘可能有意義,建議使用WakeLock阻止裝置休眠(這會阻止我們的服務執行),或者使用Mark Murphy的WakefulIntentService。然而,我們只需要執行很短的時間,所以不需要這樣做。

當然,現在我們需要在Manifest裡面宣告過濾器響應我們自定義的動作。

這樣我們的IntentService就定義好了,但是怎樣更新應用小部件?

一個應用小部件和一個標準的Activity有很大不同:在Activity裡你可以做任何你想做的事情;應用小部件會在主介面執行,可能還有其他小部件在執行,我們不能對他們干擾。例如,正常的Activity區域內可以繪製超過自身的區域,甚至可以通過clipChildern屬性處理父控制元件的佈局。然而,在主介面這樣做會干擾其他部件。為了阻止小部件這種行為,它們不能直接訪問小部件佈局及其子檢視。於是,小部件需要使用RemoteViews物件更新這些檢視。RemoteViews 是一個代理,它會提供對這些檢視帶限制的訪問。所以,可以在我們的應用小部件中使用下面這些小部件。它們是:

  • AnalogClock
  • Button
  • Chronometer
  • ImageButton
  • ImageView
  • ProgressBar
  • TextView
  • ViewFlipper
  • ListView
  • GridView
  • StackView
  • AdapterViewFlipper

同樣的限制,我們的小部件只能使用下列布局:

  • FrameLayout
  • LinearLayout
  • RelativeLayout
  • GridLayout

雖然看上去有些限制,但是我們仍能做出很酷的東西。下面我們通過服務更新時間,每當服務啟動時執行下列程式碼:

updateTime()方法包含一個AppWidgetManager例項,這樣可以在系統上更新元件。我們查詢AppWidgetManager例項的元件名稱,使用它得到一個應用部件的ID列表。這裡可能會有多個元件例項,因為使用者可能不止在一處新增,所以列舉出所有活動的應用元件對全部小部件完成更新。根據由在這個系列教程第一篇文章中定義的業務邏輯,生成表示當前時間的文字。然後通過對小部件ID進行迭代,基於在前一篇文章中應用元件佈局建立RemoteView。在實際通過AppWidgetManager請求更新前,呼叫updateTime()更新這些檢視。

updateTime()方法會根據我們需要顯示的字數去改變佈局中TextView的可見性,同時設定文字。RemoteView 允許這種控制,雖然會有一些限制。

為了讓它工作,我們需要呼叫AppWidgetProvider的onUpdate方法啟動IntentService。當元件被新增到主介面時會呼叫該方法。

執行後,可以看到應用小部件的文字進行了更新。但是,如果比較應用元件的時間和狀態列的時間,就會發現這個小部件並沒有更新時間。

widget-no-update

在下一篇文章中,我們將獲取更新後的時間。

本文的程式碼可以從這裡獲取,TextClock應用可以從Google Play下載。

相關文章