Chinaunix首页 | 论坛 | 博客
  • 博客访问: 173787
  • 博文数量: 37
  • 博客积分: 2055
  • 博客等级: 大尉
  • 技术积分: 420
  • 用 户 组: 普通用户
  • 注册时间: 2009-04-02 12:34
文章分类
文章存档

2011年(4)

2010年(15)

2009年(18)

我的朋友

分类: LINUX

2009-05-12 11:46:44

Introducing home screen widgets and the AppWidget framework (翻译)

Posted by Jeff Sharkey on 20 April 2009 at 6:43 PM

One exciting new feature in the Android 1.5 SDK is the AppWidget framework which allows developers to write "widgets" that people can drop onto their home screen and interact with. Widgets can provide a quick glimpse into full-featured apps, such as showing upcoming calendar events, or viewing details about a song playing in the background.

一个比较激动的新功能将会在Android1.5SDK中提供,就是AppWidgetk框架,这个框架允许开发者在编写widgets时提供一个不在主应用程序桌面而与其交互的功能。如显示即将来临的日历事件或者显示后台播放音乐的信息。

When widgets are dropped onto the home screen, they are given a reserved space to display custom content provided by your app. Users can also interact with your app through the widget, for example pausing or switching music tracks. If you have a background service, you can push widget updates on your own schedule, or the AppWidget framework provides an automatic update mechanism.

widgets退出其界面,我们将给一个保留的空间去显示应用程序的自定内容,用户也可以通过它与你的应用程序交互。例如暂停或选择音乐。如果是后台服务,你可以根据自己的计划去更新你的widget,AppWidget也提供了一个自动更新的机制。

At a high level, each widget is a BroadcastReceiver paired with XML metadata describing the widget details. The AppWidget framework communicates with your widget through broadcast intents, such as when it requests an update. Widget updates are built and sent using

在更高的级别,任何widget都是一对BroadcastReceiver通过XML元数据描述widget的详细信息。AppWidget框架通过广播与你的widget通讯。例如当一个请求被更新,widget更新将建立。

RemoteViews which package up a layout and content to be shown on the home screen.

信息将会显示在桌面,如下图:

You can easily add widgets into your existing app, and in this article I'll walk through a quick example: writing a widget to show the Wiktionary "Word of the day." The , but I'll point out the AppWidget-specific code in detail here.

你可以很容把这个功能加入你已经有的程序中,在下面的内容中,我们将通过一个例子:写一个widget去显示Wiktionary “Word of he day” 源码可以点英文中的那个full source code is available链接,但我需要指出的这个功能的特别处将会在这里讲述。

First, you'll need some , including the home screen area you'd like to reserve, an initial layout to show, and how often you'd like to be updated. The default Android home screen uses a cell-based layout, so it rounds your requested size up to the next-nearest cell size. This can be a little confusing, so here's a quick equation to help:

第一步:你需要用XML的元数据描述一下widget.包括你在桌面保留的区域,初始化一个布局去显示,还有你多久就更新一下其中的内容。Android桌面默认的布局是cell-based.,你可以申请一个相邻的单元格。在申请时可能有些麻烦,可以通过下面的公式来计算。

Minimum size in dip = (Number of cells * 74dip) - 2dip

In this example, we want our widget to be 2 cells wide and 1 cell tall, which means we should request a minimum size 146dip x 72dip. We're also going to request updates once per day, which is roughly every 86,400,000 milliseconds. Here's what our widget XML metadata looks like:

在这个例子中,我们分别给widget2个单元格的宽度和一个单元格的高度,我们应该申请最小的大小为146dip x 72dip,我们也将要求每天更新一次。这大概是每八千六百四十〇点〇 〇万毫秒,XML的元数据配置如下:

    xmlns:android=""

    android:minWidth="146dip"

    android:minHeight="72dip"

    android:initialLayout="@layout/widget_message"

    android:updatePeriodMillis="86400000"

    />

Next, let's pair this XML metadata with a :

接下来是下一对:XML元数据

   

       

   

   

 

Finally, let's write the BroadcastReceiver code to actually handle AppWidget requests. To help widgets manage all of the various broadcast events, there is a helper class called AppWidgetProvider, which we'll use here. One very important thing to notice is that we're launching a background service to perform the actual update. This is because BroadcastReceivers are subject to the Application Not Responding (ANR) timer, which may prompt users to force close our app if it's taking too long. Making a web request might take several seconds, so we use the service to avoid any ANR timeouts.

最后,我们写一下BroadcastReceiver 代码处理AppWidget请求,去帮助widget管理所以类型的广播消息。我们需要继承的类名为AppWidgetProvider,一个需要注意的是我们需要一个后台程序去执行widget的更新,这是因为BroadcastReceivers取决于ANR时间,它可能关闭我们的程序当它运行时间比较长的时候,一个WEB请求可以需要几分钟,所以我们使用后台服务去避免任何的ANR超时。

/**

 * 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);

                updateViews.setTextViewText(R.id.word_type, matcher.group(2));

                updateViews.setTextViewText(R.id.definition, matcher.group(3).trim());

   

                // When user clicks on widget, launch to Wiktionary definition page

                String definePage = res.getString(R.string.template_define_url,

                        Uri.encode(wordTitle));

                Intent defineIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(definePage));

                PendingIntent pendingIntent = PendingIntent.getActivity(context,

                        0 /* no requestCode */, defineIntent, 0 /* no flags */);

                updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);

   

            } else {

                // Didn't find word of day, so show error message

                updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_message);

                CharSequence errorMessage = context.getText(R.string.widget_error);

                updateViews.setTextViewText(R.id.message, errorMessage);

            }

            return updateViews;

        }

 

        @Override

        public IBinder onBind(Intent intent) {

            // We don't need to bind to this service

            return null;

        }

    }

}

And there you have it, a simple widget that will show the Wiktionary "Word of the day." When an update is requested, we read the online API and push the newest data to the surface. The AppWidget framework automatically requests updates from us as needed, such as when a new widget is inserted, and again each day to load the new "Word of the day."

到现在你已经完成了,一个简单的显示Wiktionary”Word of the day”widget,当有一个更新请求,我们使用在线API推送新的数据给他。AppWidget框架的自动更新机制可以满足我们的需求。例如当一个新的widget插入,每天再次加载”Word of the day”

 

Finally, some words of wisdom. Widgets are designed for longer-term content that doesn't update very often, and updating more frequently than every hour can quickly eat up battery and bandwidth. Consider updating as infrequently as possible, or letting your users pick a custom update frequency. For example, some people might want a stock ticker to update every 15 minutes, or maybe only four times a day. I'll be talking about additional strategies for saving battery life as part of a session I'm .

One last cool thing to mention is that the AppWidget framework is abstracted in both directions, meaning alternative home screens can also contain widgets. Your widgets can be inserted into any home screen that supports the AppWidget framework.

最后一个很酷的事情提的是AppWidget框架在两个方向都是抽象的。意思是你可以任选其一,是桌面包含widgets ,,你的widget也可以插入一个桌面。这些都是AppWidget框架所支持的。

We've already written several widgets ourselves, such as the Calendar and Music widgets, but we're even more excited to see the widgets you'll write!

我已经写好了一些widget,例如日历,音乐,但我们更高兴看到你写的。

阅读(5813) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~