文章参照自:<wbr style="line-height:22px"><a href="http://developer.android.com/guide/topics/appwidgets/index.html" target="_blank" rel="nofollow" style="line-height:22px">http://developer.android.com/guide/topics/appwidgets/index.html</a><wbr><div><strong><span style="font-size:16px">六、如何使用AppWidgetProvider</span></strong></div> <div> <span style="font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html" rel="nofollow">AppWidgetProvider</a></span><span style="color:#003366">继承于BroadcastReceiver,它对App Widget的广播进行了简单分类,并封装了处理的统一接口,以方便使用。</span> </div> <div> <span style="color:#003366"></span> <div>AppWidgetProvider只接受和App Widget相关的广播,比如App Widget更新, 被删除, enabled, 和disabled的广播.</div> <div>当收到以上广播后,将分别调用以下的函数:</div> <div><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onUpdate%28android.content.Context,%20android.appwidget.AppWidgetManager,%20int%5B%5D%29" rel="nofollow">onUpdate()</a></code></div> <span style="color:#000080">当系统以AppWidgetProviderInfo中的updatePeriodMillis定义的频率请求更新App Widget时,将调用该函数。</span> <div> <span style="color:#000080">如果没有定义configuration Activity ,当用户添加该App Widget时,也会调用该函数,此时可以做些初始化工作,比如设置View的事件监听者,启动一个临时Service。</span><span style="color:rgb(0,0,128)">如果定义了configuration Activity的话,你需要在configuration Activity完成时,发送Intent到AppWidgetProvider来进行该函数的调用.</span> </div> </div> <div><span style="color:rgb(0,0,128)"><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onDeleted%28android.content.Context,%20int%5B%5D%29" rel="nofollow">onDeleted(Context, int[])</a></code></span></div> <div><span style="color:rgb(0,0,128)">当App Widget在App Widget Host(比如Home Screen)移除时,将调用该函数.</span></div> <div><span style="color:#000080"><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onEnabled%28android.content.Context%29" rel="nofollow">onEnabled(Context)</a></code></span></div> <div><span style="color:#000080">如果用户向App Widget Host(比如Home Screen)加入App Widget时,在App widget Host中还没有你的App Widget实例,就会调用该函数.。在该函数中可以做些初始话工作,如果你想打开一个数据库连接或其它对多个App Widget实例,只执行一次的操作。</span></div> <div><span style="color:#000080"><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onDisabled%28android.content.Context%29" rel="nofollow">onDisabled(Context)</a></code></span></div> <div> <span style="color:#000080">如果用户把App Widget从App Widget Host(比如Home Screen)中移除时,它是App widget Host中的唯一的该App Widget实例的话,就会调用该函数.在该函数你可以清理在</span><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onEnabled%28android.content.Context%29" rel="nofollow">onEnabled(Context)</a></code><span style="color:rgb(0,0,128)">中做的工作,比如清理临时的数据库。</span> </div> <div><span style="color:#000080"><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive%28android.content.Context,%20android.content.Intent%29" rel="nofollow">onReceive(Context, Intent)</a></code></span></div> <div> <span style="color:rgb(0,0,128)">在收到任何广播时,</span><span style="color:#000080">该函数都会被调用,而且在以上几个函数被调用前进行。一般来说你不用重载该函数。AppWidgetProvider已经提供了默认的实现,它对广播进行分类,并调用上面几个其对应的回调函数(即上面的onUpdate()等)。</span> </div> <div> <strong>注意</strong><span style="color:#000080">:在Android1.5中,有onDeleted()函数不能被调用的BUG。为解决这个BUG,你可以参照</span><a href="http://groups.google.com/group/android-developers/msg/e405ca19df2170e2" rel="nofollow">Group post</a><span style="color:#000080">中的描述,重写</span><code><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive%28android.content.Context,%20android.content.Intent%29" rel="nofollow">onReceive()</a><span style="color:#000080">方法以便</span></code><span style="color:#000080">onDeleted()函数能经常正常调用。其代码请参照<strong>示例</strong></span><strong>2.1.</strong> </div> <div><strong>示例2.1:</strong></div> <div> <div><span style="color:#3366ff">@Override</span></div> <div><span style="color:#3366ff">public void onReceive(Context context, Intent intent) {</span></div> <div><span style="color:#3366ff"> final String action = intent.getAction();</span></div> <div><span style="color:#3366ff"> if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) {</span></div> <div><span style="color:#0000ff"> final int appWidgetId = extras.getInt</span></div> <div><span style="color:#0000ff">(AppWidgetManager.EXTRA_APPWIDGET_ID,</span></div> <div><span style="color:#0000ff"> AppWidgetManager.INVALID_APPWIDGET_ID);</span></div> <div><span style="color:#0000ff"> if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) {</span></div> <div><span style="color:#0000ff"> this.onDeleted(context, new int[] { appWidgetId });</span></div> <div><span style="color:#0000ff"> }</span></div> <div><span style="color:#3366ff"> } else {</span></div> <div><span style="color:#3366ff"> super.onReceive(context, intent);</span></div> <div><span style="color:#3366ff"> }</span></div> <div><span style="color:#3366ff"><br></span></div> <div><span style="color:#3366ff">}</span></div> </div> <div> <span style="color:#0000ff">onUpdate()</span><span style="color:#003366">是AppWidgetProvider中最重要的回调函数。因为如果你没定义configuration Activity的话,在App Widget被加入到App Widget Host时该函数就会被调用。如果你的App Widget还要与用户进行交互的话,那么才需要设置用户事件的监听者,并处理其事件。如果你的App Widget不需要创建临时的文件或数据库的话,或其他一些需要清理的工作的话,onUpdate()函数可能是唯一的一个需要你重载的回调函数。</span> </div> <div><span style="color:#003366">如果你想在App Widget中,让用户点击一个按钮就启动一个Activity的话,可以参照如下的代码:</span></div> <div><strong>示例3</strong></div> <div> <div><span style="color:#3366ff">public class ExampleAppWidgetProvider extends AppWidgetProvider {</span></div> <div><span style="color:#3366ff"><br></span></div> <div><span style="color:#3366ff"> public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {</span></div> <div><span style="color:#3366ff"> final int N = appWidgetIds.length;</span></div> <div><span style="color:#3366ff"><br></span></div> <div><span style="color:#3366ff"> // Perform this loop procedure for each App Widget that belongs to this provider</span></div> <div><span style="color:#3366ff"> for (int i=0; i<N; i++) {</span></div> <div><span style="color:#3366ff"> int appWidgetId = appWidgetIds[i];</span></div> <div><span style="color:#3366ff"><br></span></div> <div><span style="color:#3366ff"> // Create an Intent to launch ExampleActivity</span></div> <div><span style="color:#3366ff"> Intent intent = new Intent(context, ExampleActivity.class);</span></div> <div><span style="color:#3366ff"> PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);</span></div> <div><span style="color:#3366ff"><br></span></div> <div><span style="color:#3366ff"> // Get the layout for the App Widget and attach an on-click listener</span></div> <div><span style="color:#3366ff"> // to the button</span></div> <div> <span style="color:#3366ff"> </span><span style="color:#ff6600">RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);</span> </div> <div><span style="color:#ff6600"> views.setOnClickPendingIntent(R.id.button, pendingIntent);</span></div> <div><span style="color:#3366ff"><br></span></div> <div><span style="color:#3366ff"> // Tell the AppWidgetManager to perform an update on the current app widget</span></div> <div> <span style="color:#3366ff"> </span><span style="color:#ff6600"> appWidgetManager.updateAppWidget(appWidgetId, views);</span> </div> <div><span style="color:#3366ff"> }</span></div> <div><span style="color:#3366ff"> }</span></div> <div><span style="color:#3366ff">}</span></div> </div> <div> <span style="color:#003366">在这个AppWidgetProvider中我们只重载了onUpdate()一个回调函数。在该函数中,我们定了一个用于启动一个Activity的<code><a href="http://developer.android.com/reference/android/app/PendingIntent.html" rel="nofollow">PendingIntent</a></code>,并通过</span><code><a href="http://developer.android.com/reference/android/widget/RemoteViews.html#setOnClickPendingIntent%28int,%20android.app.PendingIntent%29" rel="nofollow">setOnClickPendingIntent(int, PendingIntent)</a>把</code><span style="color:rgb(0,51,102)">该PendingIntent附在App Widget的一个按钮上 。注意我们是在一个循环中</span><span style="color:#003366">对</span><span style="font-family:monospace"><span style="color:#0000ff">appWidgetIds</span><span style="color:#003366">这个数组的每项依次进行操作的,该数组包括了通过该</span></span><span style="color:rgb(0,51,102)">AppWidgetProvider创建的所有App Widget实例的id.通过该方法用户可以创建App Widget的多个实例,并同时对它们进行更新。然而,只有一个App Widget实例的updatePeriodMillis的schedule来对所有的该App Widget的实例的更新进行管理。比如,一个App Widget的更新schedue是2小时一次,我首先添加了它的一个实例,然后隔了一个小时,又添加它的一个实例,这时它的更新还是通过第一个App Widget的更新schedue来处理,第二个将被忽略掉(他们将每隔两小时更新,而不是两个更新schedue叠加变成每隔一小时)</span> </div> <div> <div> <strong style="color:rgb(0,51,102)">注意</strong><span style="color:#003366">:因为</span><span style="color:#ff9900">AppWidgetProvider</span><span style="color:#003366">扩展自</span><span style="color:#ff9900">BroadcastReceiver</span><span style="color:#003366">, 所以,你不能保证回调函数完成调用后,</span><span style="color:#ff9900">AppWidgetProvider</span><span style="color:#003366">还在继续运行。</span> </div> <div style="color:rgb(0,51,102)">(关于BroadcastReceiver的生命周期的更多内容请参考<span style="font-size:13px; color:rgb(0,112,0); line-height:13px; font-family:monospace"><a href="http://developer.android.com/reference/android/content/BroadcastReceiver.html" rel="nofollow" style="color:rgb(0,102,153)">BroadcastReceiver</a></span>),如果你的App Widget的初始化需要多达几秒的时间(比如需要进行WEB请求),而且希望AppWidgetProvider的进程能够长久运行,那么你可以考虑在onUpdate() 中启动一个Service。</div> <div style="color:rgb(0,51,102)">在这个Service,你可以更新你的App Widget,这样就不用担心AppWidgetProvider因为ANR错误而被迫关闭。</div> <div style="color:rgb(0,51,102)">关于在App Widget中使用Service的示例请参考《<span style="font-weight:bold; color:rgb(0,0,0); line-height:24px; font-family:Arial,Helvetica,simsun,u5b8bu4f53; white-space:nowrap"><a class="ztag m2a fc03" title="阅读全文" href="http://hubingforever.blog.163.com/blog/static/17104057920116263377397/" target="_blank" style="color:rgb(207,121,28); text-decoration:none">Widgets基础篇附件1(WordWidget.java)</a></span>》</div> </div> <div> <span style="color:#000080">关于App Widget的简单使用请参考<span style="font-size:13px; line-height:16px; font-family:arial,sans-serif">《</span></span><span style="font-weight:bold; line-height:24px; font-family:Arial,Helvetica,simsun,u5b8bu4f53; white-space:nowrap"><a title="阅读全文" href="http://hubingforever.blog.163.com/blog/static/171040579201162635755859/" target="_blank" style="color:rgb(207,121,28); text-decoration:underline">Widgets基础篇附件2(ExampleAppWidgetProvider.java)</a></span><span style="font-size:13px; color:rgb(0,0,128); line-height:16px; font-family:arial,sans-serif">》</span> </div> <div><strong><span style="font-size:16px">七、接收App Widget的broadcast Intents广播</span></strong></div> <div><span style="color:#000080"><span style="line-height:22px; font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html" rel="nofollow" style="line-height:22px">AppWidgetProvider</a>扩展自</span><span style="line-height:22px">BroadcastReceiver,它对App Widget的广播进行了简单分类,并封装了处理的统一接口,以方便使用。</span></span></div> <div> <span style="color:#000080"><span style="line-height:22px">你可以自己实现一个</span></span><span style="color:rgb(0,0,128)">BroadcastReceiver,重写它的</span><span style="font-size:13px; color:rgb(51,51,51); line-height:16px; font-family:arial,sans-serif"><code style="color:rgb(0,112,0); line-height:1em; font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetProvider.html#onReceive(android.content.Context,%20android.content.Intent)" rel="nofollow" style="color:rgb(0,102,153)">onReceive(Context, Intent)</a></code></span><span style="font-size:13px; line-height:16px; font-family:arial,sans-serif"><span style="color:#000080">方法,在里面处理以下的几个Intent:</span></span> </div> <div> <span style="font-size:13px; color:rgb(51,51,51); line-height:normal; font-family:arial,sans-serif"></span> <ul style="border-top-width:0px; padding-right:0px; padding-left:2em; border-left-width:0px; border-bottom-width:0px; padding-bottom:0px; margin:0px 0px 0.8em; line-height:1.3em; padding-top:0px; border-right-width:0px"> <li style="border-top-width:0px; padding-right:0px; padding-left:0px; border-left-width:0px; border-bottom-width:0px; padding-bottom:0.5em; margin:0px; line-height:1.3em; padding-top:0px; border-right-width:0px"> <code style="color:rgb(0,112,0); line-height:1em; font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetManager.html#ACTION_APPWIDGET_UPDATE" rel="nofollow" style="color:rgb(0,102,153)">ACTION_APPWIDGET_UPDATE</a></code> </li> <li style="border-top-width:0px; padding-right:0px; padding-left:0px; border-left-width:0px; border-bottom-width:0px; padding-bottom:0.5em; margin:0px; line-height:1.3em; padding-top:0px; border-right-width:0px"> <code style="color:rgb(0,112,0); line-height:1em; font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetManager.html#ACTION_APPWIDGET_DELETED" rel="nofollow" style="color:rgb(0,102,153)">ACTION_APPWIDGET_DELETED</a></code> </li> <li style="border-top-width:0px; padding-right:0px; padding-left:0px; border-left-width:0px; border-bottom-width:0px; padding-bottom:0.5em; margin:0px; line-height:1.3em; padding-top:0px; border-right-width:0px"> <code style="color:rgb(0,112,0); line-height:1em; font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetManager.html#ACTION_APPWIDGET_ENABLED" rel="nofollow" style="color:rgb(0,102,153)">ACTION_APPWIDGET_ENABLED</a></code> </li> <li style="border-top-width:0px; padding-right:0px; padding-left:0px; border-left-width:0px; border-bottom-width:0px; padding-bottom:0.5em; margin:0px; line-height:1.3em; padding-top:0px; border-right-width:0px"> <code style="color:rgb(0,112,0); line-height:1em; font-family:monospace"><a href="http://developer.android.com/reference/android/appwidget/AppWidgetManager.html#ACTION_APPWIDGET_DISABLED" rel="nofollow" style="color:rgb(0,102,153)">ACTION_APPWIDGET_DISABLED</a></code> </li> </ul> </div> </wbr></wbr>