app小部件流程

来源:互联网 发布:linux下jdk的卸载 编辑:程序博客网 时间:2024/06/09 23:39

1.定义类继承AppWidgetProvider(广播接收器)
2.定义小组件的布局文件
3.在res/xml文件夹中创建一个xml文件作为AppWidgetProviderInfo
是小组件的内容描述对象,用来设置小组件的大小,布局,更新频率
等。
4.在清单文件配置使用receiver节点,配置小组件的参数
   --小组件订阅的广播 android.appwidget.action.APPWIDGET_UPDATE
   --小组件的描述文件。android.appwidget.provider
小组件的回调方法的执行机制
  --onUpdate方法
    --更新组件的时间间隔到来的时候
    --用户每次往桌面上添加同种类型的小组件的时候。
  --onEnabled
    --同种类型的小组件的第一个实例被添加到桌面上的时候
  --onDisabled
    --同种类型的小组件的最后一个实例从桌面上被删除的时候
  --onDeleted
    --桌面上的同种类型的每一个小组件被删除的时候
  --onReceive
    --但凡小组件订阅的广播发来的时候都会回调该方法,
       以上几个方法的回调都是经由该方法的分发。


//===================================================

Widget是一种小巧但是功能强大的程序,使用户能够方便快捷的获取信息,在PC上被广泛的 使用,现在随着OPhone的推出,widget也进入到了手机领域,为用户带来了方便的同时也为开发者实现更多很酷想法的可能。在OPhone中有两种 widget开发方式,一种是以HTML+CSS+JavaScript的开发方式,另一种是沿用Android平台的开发方式,本文介绍的是后面一种, 在OPhone平台上开发App widget。

widget一般开发方式介绍

下面以编写一个时钟的小程序来介绍如何编写widget。

(1)创建一个类,让其继承类AppWidgetProvider,在AppWidgetProvider类中有许多的方法,例如 onDelete(Context, int[]),onEnable(Context)等等,一般情况下我们纸需要重写onUpdate(Context, AppWidgetManager, int[])这个方法就可以了,这个方法是当触发器更新widget时候执行的操作。

(2)在项目的AndroidMenifest.xml文件中添加一个receiver标签,让其指向前面创建的AppWidgetProvider子类,内容如下:

view plaincopy to clipboardprint?

1 <receiver android:name="widget"  2     android:label="@string/app_name"  3     android:icon="@drawable/icon">  4       <intent-filter>  5          <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />   6      </intent-filter>  7          <meta-data android:name="android.appwidget.provider"   8                android:resource="@xml/widget_setting" />   9     </receiver>  


intent-filter中过滤了APPWIDGET_UPDATE事件,这个事件是由系统触发的更新事件,每个widget必须包含这个事件;meta-data标签描述的是widget的配置文件指向,该文件描述了widget的一些基本信息。

(3)编写widget的provider文件信息,本例中该文件名叫做widget_setting.xml,开发者可以随便取名,只要在AndroidMenifest.xml中写正确就行。

view plaincopy to clipboardprint?

10 <?xml version="1.0" encoding="utf-8"?>  11 <appwidget-provider  12  xmlns:android="http://schemas.android.com/apk/res/android"   13  android:minWidth="100dp"   14  android:minHeight="100dp"  15  android:initialLayout="@layout/main"   16  android:updatePeriodMillis="1000" >  17 </appwidget-provider>  


minWidth和minHeight是widget的最小宽度和高度,这个值是一个参考值,系统会根据实际情况进行改 变,initialLayout属性指明了widget的视图布局文件,updatePeriodMillis属性是widget每隔多久更新一次的时 间,单位为毫秒。

(4)接下来就是界面布局,在这个示例中只需要一个TextView控件就可以,代码如下:

view plaincopy to clipboardprint?

18 <?xml version="1.0" encoding="utf-8"?>  19 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  20     android:orientation="vertical"  21     android:layout_width="fill_parent"  22     android:layout_height="fill_parent"  23     >  24 <TextView   25     android:layout_width="fill_parent"   26     android:layout_height="wrap_content"   27     android:text="@string/hello" android:id="@+id/text"/>  28 </LinearLayout>  


准备工作完毕,接下来完善继承自AppWidgetProvider的自定义类,重写onUpdate(Context, AppWidgetManager,int[])函数,代码如下:

view plaincopy to clipboardprint?

29 package com.dt.time;  30    31 import java.util.Date;  32    33 import android.appwidget.AppWidgetManager;  34 import android.appwidget.AppWidgetProvider;  35 import android.content.Context;  36 import android.widget.RemoteViews;  37    38 public class widget extends AppWidgetProvider {  39    40    @Override  41    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {  42       // TODO Auto-generated method stub  43       super.onUpdate(context, appWidgetManager, appWidgetIds);  44         45       //1. 获取当前时间  46       Date now = new Date();  47       String strNow = now.toLocaleString();  48       //2. 获取RemoteViews对象  49       RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);  50       //3. 显示时间到widget  51       views.setTextViewText(R.id.text, strNow);  52       //4. 更新widget  53       appWidgetManager.updateAppWidget(appWidgetIds, views);  54    }  55 }  


之后运行写好的widget查看下成果,widget的启动与普通程序不同,它不会在程序列表中显示,而是要长按桌面在弹出的列表中选择Widgets项目,之后选择本示例time,下图就是widget运行时的截图:

widget的扩展更新方法

在上例中widget更新是通过定时方式实现的,在普通情况下这种更新方式已经足够了,但是对于某些应用使用定时方式更新显得就不够用了。比如短信 提示,当有新的短信到来时我们希望能够实时的更新widget,如果还是用定时更新显然是不行的,那么能不能让widget接受除 appwidget_update之外的系统消息呢?答案是可以的。

仔细查看下文档后可以发现,widget只是一个receiver,既然是receiver那么也就可以接受所有的系统消息了,接下来使用短信提醒示例来演示widget接受系统其他消息的方式,本例中将只前一示例进行修改。

(1)修改AndroidMenifest.xml文件,向其中添加android.provider.Telephony.SMS_RECEIVED监听事件,代码如下:

view plaincopy to clipboardprint?

56 <receiver android:name=".widget" >  57    <intent-filter>  58        <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />  59        <action android:name="android.provider.Telephony.SMS_RECEIVED" />   60    </intent-filter>  61    <meta-data android:name="android.appwidget.provider"  62                     android:resource="@xml/widget_provider" />  63 </receiver>  


添加了这个短信监听事件后,我们就已经向widget添加了监听短信的功能了,实际操作非常简单。

接下来需要添加一个阅读短信的权限,在AndroidMenifest.xml中任意位置添加<uses-permission android:name="android.permission.RECEIVE_SMS" />

(2)然后还需要修改下widget_setting.xml文件,将其中的updatePeriodMillis属性设为0,也就是不定时更新,这样可以展示这个widget是实时更新的。

(3)之后修改AppWidgetProvider的子类,使其将短信内容显示到widget上。在本示例中我们将不再修改 onUpdate(Context, AppWidgetManager,int[])函数,而是重写onReceive(Context context, Intent intent)函数,这个函数其实能够实现包括onUpdate在内的所有函数功能,代码如下:

view plaincopy to clipboardprint?

64 package com.dt.time;  65    66 import android.appwidget.AppWidgetManager;  67 import android.appwidget.AppWidgetProvider;  68 import android.content.ComponentName;  69 import android.content.Context;  70 import android.content.Intent;  71 import android.widget.RemoteViews;  72    73 public class widget extends AppWidgetProvider {  74      75    @Override  76    public void onReceive(Context context, Intent intent) {  77       // TODO Auto-generated method stub  78       super.onReceive(context, intent);  79         80       //1. 获取RemoteViews对象  81       RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);  82       //2. 显示新消息提醒  83       views.setTextViewText(R.id.text, "New message!");  84       //3. 更新widget  85       AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);  86       appWidgetManager.updateAppWidget(new ComponentName(context, widget.class), views);  87    }  88 }  


代码与上一示例差别不多,唯一有区别的地方便是appWidgetManager的实例化,在上一示例中由于onUpdate()方法中有一个参数 是appWidgetManager因此我们不需要单独实例化该对象,但是在onReceive()方法中并没有这个参数,因此我们需要实例化一个 appWidgetManager,通过AppWidgetManager.getInstance(Context)方法就可以获得一个 appWidgetManager实例。当然由于onReceive()函数还缺少appWidgetIds这个参数,因此我们也不能直接使用updateAppWidget(int[] appWidgetIds, RemoteViews views)这个函数,而要改用updateAppWidget(ComponentName provider, RemoteViews views)这个函数,其中provider参数是一个ComponentName类型的值,简单的说就是组件名,通过实例化一个组件便可;第二个参数是是一个视图对象,就是想要展示的widget视图。

 

通过这样简单的改动,当有新的短信息发到手机上时就能第一时间展示在widget中,做到了实时更新。

 

widget的进阶更新方法

上面的示例已经让widget可以实时的更新内容,但是如果要显示电池电量的话,上面的方法还是不行的,为什么呢?原来android中并没有为获 取电池信息设计单独的api,必须注册为一个service才能获取。按照上面的思路那也简单,只要我们写个service,然后在系统中广播更新消息就 可以了;但是根据文档中的说明,要获取电池信息的service必须是通过Context.registerReceiver()这个函数来注册一个监听 电池变化的事件才能获取,这样一来对我们设计就带来了麻烦。

解决的方法倒也很简单,就是单独写个service在里面注册一个监听事件,当电池电量发生变化的时候就更新widget,看起来与我们上面的例子 很相似,就是多了一个service,但是这里还有一个不同的是,我们更新widget的方法不再是在onUpdate()或者是onReceive中进 行,而是在service中直接对widget修改,似乎跟文档上说的出入很大,但是看看上面显示短信的例子我们会发现,在那个示例中似乎widget的 更新与appWidgetProvider已经没有什么关系了,我们即没有从参数获得appWidgetManager实例,也没从参数中获得 appWidgetIds,一切都是我们自己新建了一个,因而不再widget更新的方法完全是可行的。下面来介绍下代码:

(1)本示例中沿用第二个示例的代码,添加一个名叫service.java类

view plaincopy to clipboardprint?

89 package com.dt.time;  90    91 import android.app.Service;  92 import android.appwidget.AppWidgetManager;  93 import android.content.BroadcastReceiver;  94 import android.content.ComponentName;  95 import android.content.Context;  96 import android.content.Intent;  97 import android.content.IntentFilter;  98 import android.graphics.Color;  99 import android.os.IBinder;  100 import android.widget.RemoteViews;  101    102 public class mService extends Service {  103    104         105    @Override  106    public void onStart(Intent intent, int startId) {  107    // TODO Auto-generated method stub  108    super.onStart(intent, startId);  109    registerReceiver(this.mBR, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));  110         111    }  112      113    //声明一个广播接受对象,用接受电池信息  114    private BroadcastReceiver mBR = new BroadcastReceiver() {  115         116    @Override  117    public void onReceive(Context context, Intent intent) {  118    // TODO Auto-generated method stub  119            120    if(Intent.ACTION_BATTERY_CHANGED.equals(intent.getAction()))  121    {  122             //这里添加相关处理动作     123       bLevel = intent.getIntExtra("level", 0);    //获取当前电量  124               125       String value = String.valueOf(bLevel) + "%";   //显示电量的文字          126               127       AppWidgetManager awm = AppWidgetManager.getInstance(context);  128       RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.main);  129               130       views.setTextViewText(R.id.text, value);  131               132       awm.updateAppWidget(new ComponentName(context, widget.class), views);  133          }  134       }  135    };  136 }  


(2)修改AndroidMenifest.xml文件,向其中添加一个<service android:name=".service"/>,这样就注册了一个系统服务,当widget启动的时候这个服务也会跟着启动,而当 widget删除的时候是否也会自动删除呢?经过试验大多数情况下OPhone会自动删除这个service,如果你为了安全也可以手动删除。

之后就可以运行看看效果了,这里展示的截图是我作的一个显示电池电量的widget,目前除了能够显示电量外还添加了其他信息的显示。


http://www.360doc.com/content/12/0209/16/7724936_185331522.shtml

0 0
原创粉丝点击