Android Widget 設計與開發

來源:互聯網
上載者:User

 

作者:徐建祥(netpirate@gmail.com)

時間: 2010/12/15

來自: http://www.anymobile.org

 

Widget雜談:最早Widget是指在PC的案頭上的小視窗程序;Web上的先行者似乎是Yahoo!;當然,OPhone也搞了一套Widget,HTML+CSS的東東。

 

我們這裡談的所謂Widget,就是視窗小組件,Android SDK從1.5版本開始支援AppWidget framework,返個架構允許開發人員開發Widgets,這些Widgets可以被使用者通過長按案頭進行添加,與應用程式進行資料互動。

 

需求:

在案頭上開發一個Widget,可以即時顯示IM軟體的狀態更新變化;可以通過左右按鈕,查看上次或下調更新內容。

(參考)

 

設計思路:

(參考設計順序圖表)

 

代碼:

Java:

    /src/org.anymobile.demo.Globals//Intent.action 聲明

     /src/org.anymobile.demo.service.UpdateService extends Service //同步、更新Widget布局資料的Service

     /src/org.anymobile.demo.widget.UpdateAppWidgetProvider extends AppWidgetProvider //Widget,接收器

XML:

    /res/layout/update_appwidget.xml //布局設計

    /res/values/strings.xml //常量聲明

    /res/xml/update_appwidget_info.xml//app widget定義

    AndroidManifest.xml

 

#AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?><br /><manifest xmlns:android="http://schemas.android.com/apk/res/android"<br /> package="org.anymobile.demo"<br /> android:versionCode="1"<br /> android:versionName="1.0"><br /> <application android:icon="@drawable/icon" android:label="@string/app_name"></p><p><receiver android:name=".widget.UpdateAppWidgetProvider"<br /> android:label="@string/app_widget_label" ><br /><intent-filter><br /><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /><br /></intent-filter><br /> <meta-data android:name="android.appwidget.provider"<br /> android:resource="@xml/update_appwidget_info" /><br /></receiver></p><p> <service android:name=".service.UpdateService" android:label="@string/app_name"><br /> <intent-filter><br /> <action android:name="org.anymobile.demo.service.IMM_UPDATE_SERVICE" /><br /> <category android:name="android.intent.category.DEFAULT" /><br /> </intent-filter><br /> </service><br /> </application><br /></manifest>  

 

#strings.xml

<?xml version="1.0" encoding="utf-8"?><br /><resources><br /> <string name="app_name">AnymobileDemo</string></p><p> <string name="app_widget_label">AnymobileDemo Widget</string><br /> <string name="app_widget_title">Updates</string><br /> <string name="app_widget_error_message">No messages, please check to login.</string></p><p></resources><br />  

 

#update_appwidget_info.xml

<?xml version="1.0" encoding="utf-8"?><br /><appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"<br /> android:minWidth="294dip"<br /> android:minHeight="120dip"<br /> android:updatePeriodMillis="0"<br /> android:initialLayout="@layout/update_appwidget"><br /></appwidget-provider>  

 

#update_appwidget.xml

<?xml version="1.0" encoding="UTF-8"?><br /><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"<br /> android:orientation="vertical"<br /> android:layout_width="fill_parent"<br /> android:layout_height="fill_parent"><br /> <LinearLayout<br /> android:id="@+id/app_widget_top"<br /> android:gravity="center_vertical"<br /> android:orientation="horizontal"<br /> android:background="@drawable/widget_titlebar"<br /> android:layout_width="fill_parent"<br /> android:layout_height="wrap_content"><br /> </LinearLayout> </p><p> <LinearLayout<br /> android:id="@+id/app_widget_body"<br /> android:orientation="horizontal"<br /> android:background="@drawable/widget_body"<br /> android:layout_width="fill_parent"<br /> android:layout_height="100dip"><br /> <LinearLayout<br /> android:id="@+id/app_widget_message"<br /> android:layout_width="fill_parent"<br /> android:layout_height="fill_parent"><br /> <TextView<br /> android:id="@+id/widget_message"<br /> android:text="@string/app_widget_error_message"<br /> android:paddingRight="5dip"<br /> android:paddingLeft="5dip"<br /> android:layout_width="wrap_content"<br /> android:layout_height="wrap_content"><br /> </TextView><br /> </LinearLayout><br /> </LinearLayout> </p><p> <LinearLayout<br /> android:id="@+id/app_widget_bottom"<br /> android:gravity="right"<br /> android:layout_width="fill_parent"<br /> android:layout_height="wrap_content"><br /> </LinearLayout><br /></LinearLayout>  

 

#Globals.java

package org.anymobile.demo;<br />public final class Globals<br />{<br />public static final String ACTION_APP_WIDGET_SERVICE= "org.anymobile.demo.service.IMM_UPDATE_SERVICE";</p><p>public static final String ACTION_APP_WIDGET_PREV= "org.anymobile.demo.intent.action.APP_WIDGET_PREV";<br />public static final String ACTION_APP_WIDGET_NEXT= "org.anymobile.demo.intent.action.APP_WIDGET_NEXT";</p><p>public static final String ACTION_APP_WIDGET_RELOAD= "org.anymobile.demo.intent.action.APP_WIDGET_RELOAD";</p><p>}<br /> 

 

#UpdateService.java

package org.anymobile.demo.service;<br />import java.util.ArrayList;<br />import android.app.Service;<br />import android.appwidget.AppWidgetManager;<br />import android.content.BroadcastReceiver;<br />import android.content.ComponentName;<br />import android.content.Context;<br />import android.content.Intent;<br />import android.content.IntentFilter;<br />import android.os.IBinder;<br />import android.util.Log;<br />import android.view.View;<br />import android.widget.RemoteViews;<br />import org.anymobile.demo.Globals;<br />import org.anymobile.demo.R;<br />import org.anymobile.demo.widget.UpdateAppWidgetProvider;<br />public class UpdateService extends Service<br />{<br />public static final String TAG = "ANYMOBILE-DEMO--UpdateService";</p><p>private ArrayList<String> mList;<br />private int mCount;<br />private int mId;</p><p>private BroadcastReceiver mIntentReceiver = new BroadcastReceiver()<br />{<br /> @Override<br /> public void onReceive(Context context, Intent intent)<br /> {<br /> String action = intent.getAction();<br /> Log.d(TAG, "onReceive() " + action);</p><p> if (action.equals(Globals.ACTION_APP_WIDGET_RELOAD))<br /> {<br /> doReload();<br /> }<br /> }<br />};<br />@Override<br />public void onCreate()<br />{<br /> Log.d(TAG, "onCreate()");<br />super.onCreate();</p><p>reloadQueue();</p><p>IntentFilter filter = new IntentFilter();<br />filter.addAction(Globals.ACTION_APP_WIDGET_RELOAD);<br />registerReceiver(mIntentReceiver, filter);<br />}</p><p>@Override<br />public void onStart(Intent intent, int startId)<br />{<br />super.onStart(intent, startId);<br /> String action = intent.getAction();<br /> Log.d(TAG, "onStart() " + action);<br /> if (action.equals(Globals.ACTION_APP_WIDGET_PREV))<br /> {<br /> doPrev();<br /> }<br /> else if (action.equals(Globals.ACTION_APP_WIDGET_NEXT))<br /> {<br /> doNext();<br /> }<br /> else// if (action.equals(Globals.ACTION_APP_WIDGET_SERVICE))<br /> {<br /> notifyWidget();<br /> }<br />}</p><p>private void notifyWidget()<br />{<br /> Log.d(TAG, "notifyWidget()");</p><p>ComponentName widget = new ComponentName(this, UpdateAppWidgetProvider.class);<br />RemoteViews updateViews = buildUpdate(this);</p><p>AppWidgetManager manager = AppWidgetManager.getInstance(this);<br />manager.updateAppWidget(widget, updateViews);<br />}<br />@Override<br />public void onDestroy()<br />{<br /> Log.d(TAG, "onDestroy()");</p><p> unregisterReceiver(mIntentReceiver);</p><p>super.onDestroy();<br />}<br />@Override<br />public IBinder onBind(Intent intent)<br />{<br /> Log.d(TAG, "onBind()");<br />return null;<br />}</p><p>private RemoteViews buildUpdate(Context context)<br />{<br />RemoteViews updateViews =<br />new RemoteViews(context.getPackageName(), R.layout.update_appwidget);<br />String item = null;</p><p>if (mCount > 0)<br />{<br />item = mList.get(mId);<br />if (item != null)<br />{<br />updateViews.setViewVisibility(R.id.app_widget_content, View.GONE);<br />updateViews.setViewVisibility(R.id.app_widget_message, View.VISIBLE);</p><p>//updateViews.setViewVisibility(R.id.app_widget_content, View.VISIBLE);<br />//updateViews.setViewVisibility(R.id.app_widget_message, View.GONE);<br />//<br />//updateViews.setImageViewResource(R.id.update_appwidget_icon, item.getTypeIconId());<br />//updateViews.setTextViewText(R.id.update_appwidget_name, item.getNickName());<br />//updateViews.setTextViewText(R.id.update_appwidget_time, item.getModifyTime());<br />//updateViews.setTextViewText(R.id.update_appwidget_content, item.getMessage());</p><p>updateViews.setTextViewText(R.id.widget_message, item);<br />}<br />}<br />if (item == null)<br />{<br />updateViews.setViewVisibility(R.id.app_widget_content, View.GONE);<br />updateViews.setViewVisibility(R.id.app_widget_message, View.VISIBLE);</p><p>updateViews.setTextViewText(R.id.widget_message,<br />context.getText(R.string.app_widget_error_message));<br />}<br /> Log.d(TAG, "buildUpdate: layoutId = " + updateViews.getLayoutId() +<br /> "; count = " + mCount + "; id = " + mId);</p><p>return updateViews;<br />}</p><p>private void doReload()<br />{<br /> Log.d(TAG, "doReload()");<br />reloadQueue();</p><p>notifyWidget();<br />}</p><p>private void reloadQueue()<br />{<br />mList = new ArrayList<String>();<br />String[] arr = {"aa", "bb", "cc", "dd"};<br />for (int i = 0; i < arr.length; i++)<br />{<br />mList.add(arr[i]);<br />}</p><p>if (mList != null)<br />{<br />mCount = mList.size();<br />}<br />else<br />{<br />mCount = 0;<br />}<br />mId = 0;</p><p>//TODO check login and poll updates from buddie list<br />}</p><p>private void doPrev()<br />{<br /> Log.d(TAG, "doPrev()");<br />mId -= 1;<br />if (mId < 0)<br />{<br />mId = mCount - 1;<br />}<br />notifyWidget();<br />}</p><p>private void doNext()<br />{<br /> Log.d(TAG, "doNext()");<br />mId += 1;<br />if (mId > mCount - 1)<br />{<br />mId = 0;<br />}<br />notifyWidget();<br />}<br />}<br /> 

 

#UpdateAppWidgetProvider.java

package org.anymobile.demo.widget;</p><p>import android.app.PendingIntent;<br />import android.appwidget.AppWidgetManager;<br />import android.appwidget.AppWidgetProvider;<br />import android.content.ComponentName;<br />import android.content.Context;<br />import android.content.Intent;<br />import android.util.Log;<br />import android.view.View;<br />import android.widget.RemoteViews;</p><p>import org.anymobile.demo.Globals;<br />import org.anymobile.demo.R;<br />import org.anymobile.demo.service.UpdateService;</p><p>public class UpdateAppWidgetProvider extends AppWidgetProvider<br />{<br />public static final String TAG = "ANYMOBILE-DEMO-UpdateAppWidgetProvider";</p><p> public static final String APP_WIDGET_UPDATE = "appwidgetupdate";<br /> public static final ComponentName APPWIDGET_COMPONENT_NAME =<br /> new ComponentName("org.anymobile.demo",<br /> "org.anymobile.demo.widget.UpdateAppWidgetProvider");<br />@Override<br />public void onReceive(Context context, Intent intent)<br />{<br /> Log.d(TAG, "onReceive() " + intent.getAction());<br />super.onReceive(context, intent);<br />}<br />@Override<br />public void onEnabled(Context context)<br />{<br /> Log.d(TAG, "onEnabled()");<br />super.onEnabled(context);<br />}<br />@Override<br />public void onDisabled(Context context)<br />{<br /> Log.d(TAG, "onDisabled()");<br />super.onDisabled(context);<br />}<br />@Override<br />public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)<br />{<br /> Log.d(TAG, "onUpdate()");</p><p> defaultAppWidget(context, appWidgetIds);</p><p> context.startService(new Intent(Globals.ACTION_APP_WIDGET_SERVICE));<br />}</p><p>private void defaultAppWidget(Context context, int[] appWidgetIds)<br />{<br /> final RemoteViews views =<br /> new RemoteViews(context.getPackageName(), R.layout.update_appwidget);</p><p>views.setViewVisibility(R.id.app_widget_content, View.GONE);<br />views.setViewVisibility(R.id.app_widget_message, View.VISIBLE);</p><p> // Link actions buttons to intents<br /> linkButtons(context, views);</p><p> pushUpdate(context, appWidgetIds, views);<br />}</p><p>private void linkButtons(Context context, RemoteViews views)<br />{<br /> Intent intent;<br /> PendingIntent pendingIntent;<br /> final ComponentName serviceName = new ComponentName(context, UpdateService.class);</p><p> intent = new Intent(Globals.ACTION_APP_WIDGET_PREV);<br /> intent.setComponent(serviceName);<br /> pendingIntent = PendingIntent.getService(context,<br /> 0 /* no requestCode */, intent, 0 /* no flags */);<br /> views.setOnClickPendingIntent(R.id.widget_btn_prev_page, pendingIntent);<br /> intent = new Intent(Globals.ACTION_APP_WIDGET_NEXT);<br /> intent.setComponent(serviceName);<br /> pendingIntent = PendingIntent.getService(context,<br /> 0 /* no requestCode */, intent, 0 /* no flags */);<br /> views.setOnClickPendingIntent(R.id.widget_btn_next_page, pendingIntent);<br />}</p><p>private void pushUpdate(Context context, int[] appWidgetIds, RemoteViews views)<br />{<br />final AppWidgetManager gm = AppWidgetManager.getInstance(context);<br /> if (appWidgetIds != null)<br /> {<br /> gm.updateAppWidget(appWidgetIds, views);<br /> }<br /> else<br /> {<br /> gm.updateAppWidget(APPWIDGET_COMPONENT_NAME, views);<br /> }<br />}</p><p>void notifyChange(UpdateService service, String what)<br />{<br />//<br />}<br />}<br />   

 

日誌:

#init

12-15 19:23:09.479 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider(  585): onReceive() android.appwidget.action.APPWIDGET_UPDATE

12-15 19:23:09.509 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider(  585): onUpdate()

12-15 19:23:09.549 D/ANYMOBILE-DEMO--UpdateService(  585): onCreate()

12-15 19:23:09.579 D/ANYMOBILE-DEMO--UpdateService(  585): onStart()

 

#add widget

12-15 19:24:23.780 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider(  585): onReceive() android.appwidget.action.APPWIDGET_UPDATE

12-15 19:24:23.780 D/ANYMOBILE-DEMO--UpdateAppWidgetProvider(  585): onUpdate()

12-15 19:24:23.850 D/ANYMOBILE-DEMO--UpdateService(  585): onStart()

 

#receive software event, reload and update widget

12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService(  585): onReceive() Activation

12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService(  585): doReload()

12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService(  585): notifyWidget()

12-15 19:24:58.200 D/ANYMOBILE-DEMO--UpdateService(  585): buildUpdate: layoutId = 2130903068; count = 11; id = 0

 

#click widget button, new start the bind service

12-15 19:25:49.260 D/ANYMOBILE-DEMO--UpdateService(  585): onStart()

12-15 19:24:58.150 D/ANYMOBILE-DEMO--UpdateService(  585): notifyWidget()

12-15 19:24:58.200 D/ANYMOBILE-DEMO--UpdateService(  585): buildUpdate: layoutId = 2130903068; count = 11; id = 0

 

OVER!

參考:

com.android.music/.MediaAppWidgetProvider

com.android.music/.MediaPlaybackService

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.