桌面widget詳解(一)——基本demo構建

一、概述

App Widget是應用程序窗口小部件(Widget)是微型的應用程序視圖,它可以被嵌入到其它應用程序中(比如桌面)並接收週期性的更新。你可以通過一個App Widget Provider來發佈一個Widget。官方文檔地址:《App Widgets》

這裏涉及到兩個方面的內容:AppWidgetProvider類和appwidget-provider標籤;
 

1、appwidget-provider標籤:

這個玩意是用來定義桌面widget的大小,初始狀態等等信息的,它的位置應該放在res/xml文件夾下,具體的xml參數如下:

  • android:minWidth : 最小寬度
  • android:minHeight : 最小高度
  • android:updatePeriodMillis : 更新widget的時間間隔(ms),"86400000"爲1個小時
  • android:previewImage : 預覽圖片
  • android:initialLayout : 加載到桌面時對應的佈局文件
  • android:resizeMode : widget可以被拉伸的方向。horizontal表示可以水平拉伸,vertical表示可以豎直拉伸
  • android:widgetCategory : widget可以被顯示的位置。home_screen表示可以將widget添加到桌面,keyguard表示widget可以被添加到鎖屏界面。
  • android:initialKeyguardLayout : 加載到鎖屏界面時對應的佈局文件
     

至於具體怎麼用,等下實戰的時候會講。

 

2、AppWidgetProvider類:

上面我們通過appwidget-provider標籤就可以得到初始化的佈局,視圖等,但我們的widget要實時更新怎麼辦,要響應用戶操作怎麼辦,這就需要額外的類來輔助處理了,這個類就是AppWidgetProvider。

由於AppWidgetProvider要接收到當前widget的狀態(是否被添加,是否被刪除等),所以要接收通知,必然是派生自BroadcastReceiver。
 

AppWidgetProvider中的廣播處理函數如下:(根據不同的使用情況,重寫不同的函數)

onUpdate():

在3種情況下會調用OnUpdate()。onUpdate()是在main線程中進行,因此如果處理需要花費時間多於10秒,處理應在service中完成。(第二篇會講爲什麼還要有service)
(1)在時間間隔到時調用,時間間隔在widget定義的android:updatePeriodMillis中設置;
(2)用戶拖拽到主頁,widget實例生成。無論有沒有設置Configure activity,我們在Android4.4的測試中,當用戶拖拽圖片至主頁時,widget實例生成,會觸發onUpdate(),然後再顯示activity(如果有)。這點和資料說的不一樣,資料認爲如果設置了Configure acitivity,就不會在一開始調用onUpdate(),而實驗顯示當實例生成(包括創建和重啓時恢復),都會先調用onUpate()。在本例,由於此時在preference尚未有相關數據,創建實例時不能有效進行數據設置。
(3)機器重啓,實例在主頁上顯示,會再次調用onUpdate()
 

onDeleted(Context, int[]):

當 widget 被刪除時被觸發。

onEnabled(Context):

當第1個 widget 的實例被創建時觸發。也就是說,如果用戶對同一個 widget 增加了兩次(兩個實例),那麼onEnabled()只會在第一次增加widget時觸發。

onDisabled(Context):

當最後1個 widget 的實例被刪除時觸發。

onReceive(Context, Intent):

在接收到廣播時,調用。

二、實戰

先看一下顯示效果:

就這麼一個桌面widget,一個音樂播放器,這一篇只是顯示出來,後面我們會慢慢完善它的功能。

1、appwidget-provider及佈局文件

前面我們講過,appwidget-provider提供了桌面widget的初始化顯示狀態、默認圖標、大小等功能,但它必須放在res/xml文件夾下,看看這裏的代碼:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:initialLayout="@layout/example_appwidget"
    android:minHeight="60dp"
    android:minWidth="180dp"
    android:previewImage="@drawable/preview"
    android:resizeMode="horizontal|vertical"
    android:widgetCategory="home_screen|keyguard" >
 
</appwidget-provider>

這裏有幾個參數:

 

prviewImage:就是添加桌面控件時,我們的控件在列表中的顯示狀態,如下圖所示,下面這個醜娃娃就是我們的顯示圖標……

android:initialLayout="@layout/example_appwidget":這個就是指定初始化顯示時,應該顯示的佈局;

下面看看這個佈局文件:example_appwidget.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#33000000"
    android:gravity="center"
    android:orientation="horizontal" >
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dip"
        android:background="@drawable/car_musiccard_up"/>
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginRight="8dip"
        android:background="@drawable/car_musiccard_play"/>
    
    <TextView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/car_musiccard_down"/>
 
</LinearLayout>

這個佈局就是最上頭顯示出來的那個播放器的佈局。

2、ExampleAppWidgetProvider extends AppWidgetProvider

在佈局成功之後,下面就是根據通知實現邏輯了,這篇我們只接收通知,邏輯下篇再說。首先新建一個類ExampleAppWidgetProvider,將其派生自AppWidgetProvider;然後就會有下面的代碼:

public class ExampleAppWidgetProvider extends AppWidgetProvider {
 
	 /*
	  * 在3種情況下會調用OnUpdate()。onUpdate()是在main線程中進行,因此如果處理需要花費時間多於10秒,處理應在service中完成。
	  *(1)在時間間隔到時調用,時間間隔在widget定義的android:updatePeriodMillis中設置; 
	  *(2)用戶拖拽到主頁,widget實例生成。無論有沒有設置Configure activity,我們在Android4.4的測試中,當用戶拖拽圖片至主頁時,widget實例生成,會觸發onUpdate(),然後再顯示activity(如果有)。這點和資料說的不一樣,資料認爲如果設置了Configure acitivity,就不會在一開始調用onUpdate(),而實驗顯示當實例生成(包括創建和重啓時恢復),都會先調用onUpate()。在本例,由於此時在preference尚未有相關數據,創建實例時不能有效進行數據設置。
	  *(3)機器重啓,實例在主頁上顯示,會再次調用onUpdate()
	  */ 
	@Override
	public void onUpdate(Context context, AppWidgetManager appWidgetManager,
			int[] appWidgetIds) {
 
		super.onUpdate(context, appWidgetManager, appWidgetIds);
	}
 
	// widget被刪除時調用
	@Override
	public void onDeleted(Context context, int[] appWidgetIds) {
		Log.d(TAG, "onDeleted(): appWidgetIds.length=" + appWidgetIds.length);
 
		super.onDeleted(context, appWidgetIds);
	}
 
	// 最後一個widget被刪除時調用
	@Override
	public void onDisabled(Context context) {
		Log.d(TAG, "onDisabled");
 
		super.onDisabled(context);
	}
 
	// 第一個widget被創建時調用
	@Override
	public void onEnabled(Context context) {
 
		super.onEnabled(context);
	}
 
	// 接收廣播的回調函數
	@Override
	public void onReceive(Context context, Intent intent) {
 
		super.onReceive(context, intent);
	}
}

這裏不是繼承接口,這幾個函數並不是需要全部重寫的,根據需要,要用到哪個可以重寫哪個。

 

3、註冊ExampleAppWidgetProvider

前面我們講到AppWidgetProvider派生自BroadcastReciver,所以要提前註冊,有關BroadcastReciver的註冊有兩種方法,靜態註冊和動態註冊,因爲這裏要接收來自的消息,而且在程序啓動時就開始自動監聽,所以,這裏需要靜態註冊。

<!-- 聲明widget對應的AppWidgetProvider -->
<receiver android:name=".ExampleAppWidgetProvider" >
    <intent-filter>
	<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
    </intent-filter>
    <meta-data android:name="android.appwidget.provider"
	android:resource="@xml/example_appwidget_info" />
</receiver>

(1)接收的action定義爲:"android.appwidget.action.APPWIDGET_UPDATE"這表明接收系統發來的有關這個app的所有widget的消息(主要是增加、刪除)。

 

(2)<meta-data> 指定了 AppWidgetProviderInfo 對應的資源文件
android:name -- 指定metadata名,指定爲android.appwidget.provider表示這個data中的數據是AppWidgetProviderInfo 類型的
android:resource -- 指定 AppWidgetProviderInfo 對應的資源路徑。即,xml/example_appwidget_info.xml。

 

三、可能出現的錯誤:

1、有關佈局錯誤

在構造Widget佈局時,App Widget支持的佈局和控件非常有限,有如下幾個:

App Widget支持的佈局:

  •   FrameLayout
  •   LinearLayout
  •   RelativeLayout
  •   GridLayout

 App Widget支持的控件:

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

除此之外的所有控件(包括自定義控件)都無法顯示,無法顯示時,添加出來的widget會顯示“加載佈局出錯”

2、appwidget-provider出現錯誤

如果appwidget-provider頁面出現錯誤提示:error: No resource identifier found for attribute 'widgetCategory' in package 

'android'

這是由於build target應該在17以上,有兩種方法解決:

方法1:找到工程中的project.properties文件將target=android-14改爲target=android-17   

方法2:工程上右鍵-》properties  選擇Android,將Project Build Target改爲17或以上,如圖:(改完之後rebuild一下工程)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章