本文翻译自Android Developers Blog:Introducing home screen widgets and the AppWidget framework
Android 1.5 SDK一个令人兴奋的新特性是AppWidget framework,这个结构答应开发者开发widgets,这些widgets能够被用户拖到用户的桌面而且能够交互。widgets能够供给一个full-featured apps的预览,例如能够显现行将到来的日历事情,或许一首后台播映的歌曲的详细信息。
当widgets被拖到桌面上,他们被指定一个保存的空间来显现运用供给的自定义内容。用户能够经过这个widget来和你的运用交互,例如暂停或切换歌曲。假如你有一个后台服务,你能够依照你自己的schedule更新你的widget,或许运用AppWidget framework供给的一个主动的更新机制。
在更高层次上,每个widget便是一个BroadcastReceiver,他们用XML metadata来描绘widget的细节。AppWidget framework经过broadcast intents和你的widget通讯,例如当需求更新的时分。Widget更新运用RemoteViews被构建和发送。这个RemoteViews被包装成一个layout和特定内容来显现到桌面上。
你能够十分简略的增加widgets到你的运用中,在这篇文章里我将给一个简略的比如:写一个widget来显现Wiktionary “Word of the day.”你能够从这儿获取一切的源代码,我将在这儿解说Appwidget相关的代码。
首要,你需求一个XML metadata描绘这个widget,包含你想在桌面上保存的区域,一个你想展现的初始的layout,和你计划何时更新。Android桌面默许运用cell-based layout,因而它会rounds你恳求的尺度为最接近的cell的尺度。这是有点疑问,不过这儿有个公式能够协助你:
Minimum size in dip = (Number of cells * 74dip) – 2dip
在这个比如中,我想使咱们的widget占用2 cells的宽度和1 cell的高度,这意味着我应该恳求的最小尺度为146dip * 72dip。咱们即将每天更新一次咱们的widget,大约是每86,400,000毫秒更新一次。以下是咱们的widget的XML metadata:
接下来,让咱们把XML metadata绑缚到AndroidManifest的BroadcasrReicever:
最终,让咱们写BroadcastReceiver的代码来处理AppWidget的恳求。为了协助widgets办理一切
broadcasr事情,有个helper class叫AppWidgetProvider,这儿咱们将运用这个类。其间需求留意的最重要的一件事是咱们将调用一个后台服务履行定时的更新。这是因BroadcastReceivers是一个Application Not Responding(ANR) timer,这意味着假如运转时刻太长,或许需求提示用户强制封闭咱们的运用。制造一个web恳求或许需求花费一些时刻,因而咱们运用服务来防止ANR timeouts.
/**
* Define a simple widget that shows the Wiktionary “Word of the day.” To build
* an update we spawn a background {@link Service} to perform the API queries.
*/
public class WordWidget extends AppWidgetProvider {
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// To prevent any ANR timeouts, we perform the update in a service
context.startService(new Intent(context, UpdateService.class));
}
public static class UpdateService extends Service {
@Override
public void onStart(Intent intent, int startId) {
// Build the widget update for today
RemoteViews updateViews = buildUpdate(this);
// Push update for this widget to the home screen
ComponentName thisWidget = new ComponentName(this, WordWidget.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
/**
* Build a widget update to show the current Wiktionary
* “Word of the day.” Will block until the online API returns.
*/
public RemoteViews buildUpdate(Context context) {
// Pick out month names from resources
Resources res = context.getResources();
String[] monthNames = res.getStringArray(R.array.month_names);
// Find current month and day
Time today = new Time();
today.setToNow();
// Build today’s page title, like “Wiktionary:Word of the day/March 21″
String pageName = res.getString(R.string.template_wotd_title,
monthNames[today.month], today.monthDay);
RemoteViews updateViews = null;
String pageContent = “”;
try {
// Try querying the Wiktionary API for today’s word
SimpleWikiHelper.prepareUserAgent(context);
pageContent = SimpleWikiHelper.getPageContent(pageName, false);
} catch (ApiException e) {
Log.e(”WordWidget”, “Couldn’t contact API”, e);
} catch (ParseException e) {
Log.e(”WordWidget”, “Couldn’t parse API response”, e);
}
// Use a regular expression to parse out the word and its definition
Pattern pattern = Pattern.compile(SimpleWikiHelper.WORD_OF_DAY_REGEX);
Matcher matcher = pattern.matcher(pageContent);
if (matcher.find()) {
// Build an update that holds the updated widget contents
updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);
String wordTitle = matcher.group(1);
updateViews.setTextViewText(R.id.word_title, wordTitle);