-
App Widget
2015-11-28 16:53:141. 基本信息App Widget是一种可以被放在其他应用中(如Launcher)并接收周期性更新的应用视图。这些视图在UI上就表现为Widget,并且你可以同App Widget Provider一起发布。 要创建一个App Widget,你需要完成以下...1. 基本信息
App Widget是一种可以被放在其他应用中(如Launcher)并接收周期性更新的应用视图。这些视图在UI上就表现为Widget,并且你可以同App Widget Provider一起发布。
要创建一个App Widget,你需要完成以下步骤:- AppWidgetProviderInfo对象:它描述了App
Widget的基本元素,比如说布局、更新频率、AppWidgetProvider类等。这些都是在xml文件中定义的。 - 2.AppWidgetProvider类的实现:它定义了一些基本的方法以支持通过广播事件与App Widget交互。通过它,当App Widget被更新、启用、禁用以及删除时,你将收到相应的广播信息。
- 3.View Layout:通过xml文件定义App Widget的初始视图。
2. 添加App Widget布局
另外,你还可以实现一个App Widget的配置Activity。当然,这不是强制的。
要创建你的App Widget的初始布局,你可以使用以下View对象。
创建布局不是很麻烦,重点是,你必须记住,这个布局是基于RemoteViews的,不是所有的布局类型与View都支持。
一个RemoteViews对象可以支持以下布局类:
以及一下widget类FrameLayout LinearLayout RelativeLayout AnalogClock Button Chronometer ImageButton ImageView ProgressBar TextView ViewFlipper 注:这些类的子类是不支持的。
res/layout文件夹下创建widget.xml文件<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="当前时间" android:textColor="@android:color/white" android:textSize="18sp" android:id="@+id/tv_weather"/> </LinearLayout>
3. 添加AppWidgetProviderInfo元数据
res/xml文件夹下创建weather.xml文件
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="86400000" android:previewImage="@drawable/preview" android:initialLayout="@layout/widget" android:configure="com.example.android.ExampleAppWidgetConfigure" android:resizeMode="horizontal|vertical"> </appwidget-provider>
minWidth与minHeight属性表示了App Widget所需的最小布局区域。
默认的主屏中,App Widget要想确认其位置,需要通过基于网格的具有固定宽度和高度的单元。如果App Widget的最小宽度和高度无法匹配给定的单元,它将会自动扩展到最接近的单元大小。
由于主屏的布局方向是可变的,你应该考虑最坏的情况(每单元的宽和高都是74dp)。然而,为了防止在扩展时产生整数计算错误,你还需要减去2。因此,你可以用以下公式来计算最小宽度和高度(单位dp):(单元数量×74)-2。
同时,为了保证你的App Widget能够在各种设备上正常使用,它们的宽度和高度必须不超过4×4个单元。updatePeriodMillis属性定义了App
Widget框架调用AppWidgetProvider的onUpdate方法的频率。对于实际的更新,我们不建议采用该值进行实时处理。最好是越不频繁越好——为了保证电量,一小时不超过一次为好。当然,你也可以允许用户对更新频率进行设置。
注意,如果更新触发时设备正处于休眠状态,设备将唤醒以执行该操作。如果你的更新频率不超过一小时一次,这不会对电池的寿命产生多大的影响。但如果你需要更频繁地更新却又不想要在设备休眠时执行,那你可以使用定时器来执行更新。要达到这种目的,可以在AlarmManager中设置一个AppWidgetProvider能接收的Intent。将类型设为ELAPSED_REALTIME或RTC。由于AlarmManager只有当设备处于唤醒状态时才会被调用,我们只要设updatePeriodMillis为0即可。- linitialLayout属性标识了初始布局文件。
- configure属性定义了当用户添加App Widget时调用的Activity。(这是可选的)
- previewImage定义了App
Widget的缩略图,当用户从widget列表中选择时,显示的就是这张图。如果没设置,用户将看见的是你的应用的默认图标。 - autoAdvanceViewId属性是在Android3.0引入的,用于标识需要被host(launcher)自动更新的widget的子视图。
- resizeMode属性标识了widget重新布局的规则。你可以使用该属性来让widget能够在水平、竖直、或两个方向上均可变化。可用的值包括horizontal、vertical、none。如果是想在两个方向上均能拉伸,可设置为horizontal|vertical,当然,需要Android3.1以上版本。
4. 使用AppWidgetProvider类
public class ClockProvider extends AppWidgetProvider { @Override public void onEnabled(Context context) { super.onEnabled(context); Intent _intent = new Intent(context, ClockService.class); context.startService(_intent); } @Override public void onDisabled(Context context) { super.onDisabled(context); Intent _intent = new Intent(context, ClockService.class); context.stopService(_intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { super.onUpdate(context, appWidgetManager, appWidgetIds); } }
onUpdate()
由updatePeriodMills定义的时间间隔触发。当然,添加Widget的时候也会,因此,应该在此处执行一些必要的配置,如定义View的事件处理handler,有必要的话,还会启动一个临时的Service。然而,如果你声明了一个配置Activity,该方法将不会在此时被调用。onDelete(Context, int[])
当App Widget从host中移除时会被调用。- onEnabled(Context)
当App Widget的实例被第一次创建时,该方法将被调用。如果你建了两个实例,那该方法也只会被调用一次。 onDisabled(Context)
当最后一个App Widget的实例被删除时,该方法被调用。你可以在此处清除之前在onEnabled里执行的操作。onReceive(Content, Intent)
每次接收到广播都会被调用,而且执行的顺序在上述方法之前。通常,你不需要实现该方法,因为AppWidgetProvider已经对各种不同类型的广播进行了过滤及分发。
注:在Android1.5中,有一个已知的问题,使得在某些情况下,onDeleted不会被调用。这时,你就需要实现onReceive()了。
5. 使用Service更新数据
public class ClockService extends Service implements AMapLocalWeatherListener { private LocationManagerProxy mLocationManagerProxy; public SimpleDateFormat sdf; public Timer timer; @Override public IBinder onBind(Intent intent) { return null; } @Override public void onCreate() { super.onCreate(); System.out.println("start"); sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { String time = sdf.format(new Date()); updateViews(time); } },0,1000); } private void updateViews(String info) { Intent _intent = new Intent(this, MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, _intent, 0); RemoteViews views = new RemoteViews(getPackageName(), R.layout.widget); views.setTextViewText(R.id.tv_weather, info); views.setOnClickPendingIntent(R.id.tv_weather, pendingIntent);//点击跳到主页 AppWidgetManager manager = AppWidgetManager.getInstance(this); ComponentName name = new ComponentName(this, ClockProvider.class); manager.updateAppWidget(name,views); } @Override public void onDestroy() { super.onDestroy(); timer.cancel(); } }
通过RemoteViews类和AppWidgetManager类发送广播更新界面数据
6.在AndroidManifest中声明一个App Widget
<service android:name=".ClockService"></service> <receiver android:name=".ClockProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"></action> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/weather"></meta-data> </receiver>
meta-data标签标识了AppWidgetProviderInfo资源,它需要以下属性:
android:name:使用android.appwidget.provider来标识AppWidgetProviderInfo。
android:resource:标识AppWidgetProviderInfo的资源位置。 - AppWidgetProviderInfo对象:它描述了App
-
AppWidget
2016-04-28 01:33:59什么是AppWidget?AppWidget就是我们平常在桌面上见到的那种一个个的小窗口,利用这个小窗口可以给用户提供一些方便快捷的操作。本篇打算从以下几个点来介绍AppWidget: 1.如何创建一个简单的AppWidget 2....什么是AppWidget?AppWidget就是我们平常在桌面上见到的那种一个个的小窗口,利用这个小窗口可以给用户提供一些方便快捷的操作。本篇打算从以下几个点来介绍AppWidget:
1.如何创建一个简单的AppWidget
2.如何使得AppWidget与客户端程序交互
下面我们来创建一个简单的AppWidget
1、定义AppWidgetProviderInfor:在res/xml文件夹中定义一个名为 :example_appwidget_info.xml,这个名字随便取。它是提供AppWidget元数据;设置在桌面上显示的大小
example_appwidget_info.xml
- < appwidget-provider xmlns:android = "http://schemas.android.com/apk/res/android"
- android:minWidth = "294dp"
- android:minHeight = "72dp"
- android:updatePeriodMillis = "86400000"
- android:initialLayout = "@layout/example_appwidget" >
- <!-- initiallayout设置引用 的布局文件 -->
- </ appwidget-provider >
2、为App Widget指定样式和布局;在桌面上显示的内容,布局,就像main.xml布局一样,做为example_appwidget_info.xml的 initialLayout参数的值,用这个布局文件来初始化example_appwidget_info.xml。
- <?xml version= "1.0" encoding= "utf-8" ?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- >
- <TextView
- android:id="@+id/widgetTextId"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="firstWidgetText"
- android:background="#000000"
- />
- </LinearLayout>
3、实现继承AppWidgetProvider这个类;
这个类有五个方法:都需要继承:(下面按照当第一次加载Widget到删除的时候,这些方法运行的顺序)
1、onReceive (Context context, Intent intent) Implements
onReceive(Context, Intent)
to dispatch calls to the various other methods on AppWidgetProvider.2、onEnabled (Context context) Called in response to the
ACTION_APPWIDGET_ENABLED
broadcast when the a AppWidget for this provider is instantiated. Override this method to implement your own AppWidget functionality.3、onUpdate (Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) Called in response to the
ACTION_APPWIDGET_UPDATE
broadcast when this AppWidget provider is being asked to provideRemoteViews
for a set of AppWidgets. Override this method to implement your own AppWidget functionality.4、onDeleted (Context context, int[] appWidgetIds) Called in response to the
ACTION_APPWIDGET_DELETED
broadcast when one or more AppWidget instances have been deleted. Override this method to implement your own AppWidget functionality.5、onDisabled (Context context) Called in response to the
ACTION_APPWIDGET_DISABLED
broadcast, which is sent when the last AppWidget instance for this provider is deleted. Override this method to implement your own AppWidget functionality.基中onReceive负责进行接受广播,控制运行哪一个函数,每一个操作都会首先运行这个方法,再调用其它的方法。所以在Widget一次加载到删除过程中,onReceive会执行4次;
如下图:注意message
下面看代码: ExampleAppWidgetProvider.java
- public class ExampleAppWidgetProvider extends AppWidgetProvider {
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager,
- int [] appWidgetIds) {
- System.out.println("onupdate" );
- super .onUpdate(context, appWidgetManager, appWidgetIds);
- }
- @Override
- public void onDeleted(Context context, int [] appWidgetIds) {
- System.out.println("onDeleted" );
- super .onDeleted(context, appWidgetIds);
- }
- @Override
- public void onDisabled(Context context) {
- System.out.println("onDisabled" );
- super .onDisabled(context);
- }
- @Override
- public void onEnabled(Context context) {
- System.out.println("onEnabled" );
- super .onEnabled(context);
- }
- }
在这个实例中,因为与Activity脱离关系,所以Activity不用更改,只是在应用系统中注册了一个与这个应用程序相关的AppWidget而已:结果:
下面再来看看如何在AppWidget中添加按钮,添加监听事件。
1、在example_appwidget_info.xml文件里添加Button迫使
2、添加TargetActivity
只是用来响应点击事件,在此例中没有实际意义
- public class TargetActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super .onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
- }
3、在AndroidManifest.xml文件注册TargetActivity
4、重写ExampleAppWidgetProvider类的onUpdate方法,在第一次创建WidGet的时候,向按钮添加监听。并用PendingIntent,和RemoteView两个类,对事件进行处理;
- public void onUpdate(Context context, AppWidgetManager appWidgetManager,
- int [] appWidgetIds) {
- System.out.println("onupdated" );
- for ( int i = 0 ; i <appWidgetIds.length; i++) {
- System.out.println(appWidgetIds[i]);
- //创建一个Intent对象
- Intent intent = new Intent(context,TargetActivity. class );
- //创建一个PendingIntent(有四种方法获取)
- PendingIntent pendingIntent = PendingIntent.getActivity(context, 0 , intent, 0);
- RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.example_appwidget);
- //为按钮绑定事件处理器
- //第一个参数用来指定被绑定处理器的控件的ID
- //第二个参数用来指定当事件发生时,哪个PendingIntent将会被执行
- remoteViews.setOnClickPendingIntent(R.id.widgetButton, pendingIntent);
- //更新AppWidget
- //第一个参数用于指定被更新AppWidget的ID
- appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews);
- }
- super .onUpdate(context, appWidgetManager, appWidgetIds);
- }
Called in response to the
ACTION_APPWIDGET_DELETED
broadcast when one or more AppWidget instances have been deleted. Override this method to implement your own AppWidget functionality.在实际应用在AppWidget更多的是利用广播机制Action进行处理的;下面我们来看看如何利用广播机制,单击改变AppWidget的内容;在上例 的基础上进行扩展:
1、AppWidget的布局文件:widget01.xml
- <? xml version = "1.0" encoding = "utf-8" ?>
- < LinearLayout xmlns:android = "http://schemas.android.com/apk/res/android"
- android:orientation = "vertical"
- android:layout_width = "fill_parent"
- android:layout_height = "fill_parent"
- >
- < Button android:id = "@+id/widgetButton"
- android:layout_width = "fill_parent"
- android:layout_height = "wrap_content"
- android:text = "@string/widget_button" />
- < TextView android:id = "@+id/test_text"
- android:layout_width = "fill_parent"
- android:layout_height = "wrap_content"
- android:text = "@string/test_text"
- android:gravity = "center"
- android:textColor = "#fff" />
- </ LinearLayout >
其中的Button控件是测试按钮,TextView用来反应单击Button之后显示的内容变化;(这是给Button添加监听器,再利用Action广播。收onRecerve接收,做出动作)
2、修改AndroidManifest.xml
在Reservi里添加action,注册事件
- < receiver android:name = "ExampleAppWidgetProvider" > <!--如果action匹配成功,就在此类中进行处理-->
- < intent-filter >
- <!--利用广播机制接收,onUpdate会接收广播。查看源码可收得知 Called in response to the ACTION_APPWIDGET_UPDATE
- broadcast when this AppWidget provider is being asked to provide RemoteViews
- for a set of AppWidgets. Override this method to implement your own AppWidget
- functionality. 这个也必须要,不然onRecerve不会调用 。-->
- <!--这是自定义的Action事件--> < action android:name = "android.appwidget.action.APPWIDGET_UPDATE" />
- < action android:name = "learn.test.UPDATE_APP_WIDGET" />
- </ intent-filter >
- < meta-data android:name = "android.appwidget.provider" android:resource = "@xml/widget_test" />
- </ receiver >
3、修改ExampleAppWidgetProvider.java代码文件,如下:
- public class ExampleAppWidgetProvider extends AppWidgetProvider {
- //定义一个常量字符串,该常量用于命名Action
- private static final String UPDATE_ACTION = "learn.test.UPDATE_APP_WIDGET" ;
- @Override
- public void onDeleted(Context context, int [] appWidgetIds) {
- // TODO Auto-generated method stub
- System.out.println("onDeleted" );
- super .onDeleted(context, appWidgetIds);
- }
- @Override
- public void onDisabled(Context context) {
- // TODO Auto-generated method stub
- System.out.println("onDisabled" );
- super .onDisabled(context);
- }
- @Override
- public void onEnabled(Context context) {
- // TODO Auto-generated method stub
- System.out.println("onEnabled" );
- super .onEnabled(context);
- }
- @Override
- public void onReceive(Context context, Intent intent) {
- // TODO Auto-generated method stub
- System.out.println("onReceive" );
- String action = intent.getAction();
- if (UPDATE_ACTION.equals(action)) {
- RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
- R.layout.widget01);
- remoteViews.setTextViewText(R.id.test_text, "this is OnReceive" );
- //getInstance(Context context) Get the AppWidgetManager instance to use for the supplied Context object.静态方法。
- AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
- ComponentName componentName = new ComponentName(context,ExampleAppWidgetProvider.class );
- appWidgetManager.updateAppWidget(componentName, remoteViews);
- } else {
- super .onReceive(context, intent); 这里一定要添加,eles部分,不然,onReceive不会去调用其它的方法。但是如果把这条语句放在外面,就会每次运行 onUpdate,onDeleted等方法,就会运行两次,因为UPDATE_ACTION.equals(action)配置成功会运行一 次,uper.onReceive(context, intent)配置成功又会运行一次,后都是系统自定义的。
- }
- }
- @Override
- public void onUpdate(Context context, AppWidgetManager appWidgetManager,
- int [] appWidgetIds) {
- // TODO Auto-generated method stub
- System.out.println("onUpdated" );
- //创建一个Intent对象
- Intent intent = new Intent();
- //为Intent对象设置Action
- intent.setAction(UPDATE_ACTION);
- //使用getBroadcast方法,得到一个PendingIntent对象,当该对象执行时,会发送一个广播
- PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0 ,
- intent, 0 );
- RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
- R.layout.widget01);
- remoteViews.setOnClickPendingIntent(R.id.widgetButton, pendingIntent);
- appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
- super .onUpdate(context, appWidgetManager, appWidgetIds);
- }
- }
-
APP Widget
2014-04-12 18:23:301} App Widget1} App Widget
1) 什么是App Widget?
效果想当于电脑的系统托盘.
1> AppWidgetProviderInfo对象:
为App Widget提供元数据,包括布局,更新频率等数据.这个对象被定义在XML文件当中.(元数据:描述数据的数据,如xml)
2> AppWidgeProvider:
定义了App Widget的基本生命周期函数
2)定义AppWidgetProviderInfo
在res/xml文件夹中定义一个名为 example_appwidget.xml 的文件.<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="294dp" android:minHeight="72dp" android:updatePeriodMillis="86400000" android:initialLayout="@layout/example_appwidget" ></appwidget-provider>
在这个文件中 主要定义 App Widget 的一些属性.
3) 为App Widget 指定样式和布局
定义一个新的布局文件example_appwidget.xml.本例只是简单定义一个TextView.
这个布局就是 app widget在桌面上显示的效果.
4) 实现AppWidgetProvider
onUpdate:在到达指定的更新时间之后或者当用户向桌面添加 App Widget 时会调用该方法
onDeleted: 当App Widget 衩删除时,会调用该方法
onEnabled: 当一个 App Widget 的实例第一次被创建时,会调用该方法
onDisabled: 当最后一个App Widget 被删除时,会调用该方法
onReveice: 接收广播事件
5) 在AndroidManifest.xml 加入receiver在AndroidManifest.xml 中注册这个 App Widget:
<intent-filter> 符合这个的内容才会接收<receiver android:name="ExampleAppWidgetProvider"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/example_appwidget_info" /> </receiver>
<meta-data> 为 AppWidgetProviderInfo 提供数据.
6) 实现ExampleAppWidgetProvider.java
见下面一个程序第6点.
运行之后,就可以在桌面上添加 一个App Widget. 需要注意的是 App Widget 和我们写的程序并不运行在同一进程中.
2} 在App Widget中使用控件1) Pending Intent
Pending Intent 是创建后并不马上使用,Mars老师用了诸葛亮送锦囊给赵云的故事来打比喻很贴切.Pending Intent 是进程A创建,但给进程B用. A是诸葛亮,B是赵云.Pending Intent 就是锦囊. 进程B 遇到某个事件之后,就去Pending Intent 中取出 Intent. Pending Intent 想当于给 Intent 做了个包装.
2) 创建 Pending Intent
有3种方法:
1. getActivity(Context context, int requestCode, Intent intent, int flags) //创建一个vfActivity
2. getBroadcast(Context context, int requestCode, Intent intent, int flags) //创建广播
3. getService(Context context, int requestCode, Intent intent, int flags) //创建服务3) RemoteViews
1. RemoteViews 对象表示一系列的View对象2. RemoteViews 所表示的对象运行在另外的进行当中.
4) 向App Widget 添加一个 Button
在layout的example_appwidget.xml 中加入一个Button:
5) 为Button绑定处理器<Button android:id="@+id/widgetButtonId" android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="测试用按钮" />
注意:由于 App Widget 和我们的应用程序运行在不同的进程当中(App Widget 当中的View运行在Home Screen进程当中),所以无法按照之前惯用的方法绑定监听 器.remoteViews.setOnClickPendingIntent(R.id.widgetButtonId, pendingIntent);
当按下按钮时,会引起pendingIntent中的Intent执行.
6)实现ExampleAppWidgetProvider.java
appWidgetIds 屏幕上的每们app Widget 都分配了一个ID.package mars.appwidget02; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.widget.RemoteViews; public class ExampleAppWidgetProvider extends AppWidgetProvider{ @Override public void onDeleted(Context context, int[] appWidgetIds) { // TODO Auto-generated method stub super.onDeleted(context, appWidgetIds); } @Override public void onDisabled(Context context) { // TODO Auto-generated method stub super.onDisabled(context); } @Override public void onEnabled(Context context) { // TODO Auto-generated method stub super.onEnabled(context); } @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub super.onReceive(context, intent); } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { for (int i = 0; i < appWidgetIds.length; i++) { System.out.println(appWidgetIds[i]); //创建一个Intent对象 Intent intent = new Intent(context,TargetActivity.class); //创建一个PendingIntent PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.example_appwidget); //为按钮绑定事件处理器 //第一个参数用来指定被绑定处理器的控件的ID //第二个参数用来指定当事件发生时,哪个PendingIntent将会被执行 remoteViews.setOnClickPendingIntent(R.id.widgetButtonId, pendingIntent); //更新AppWidget //第一个参数用于指定被更新AppWidget的ID appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews); } super.onUpdate(context, appWidgetManager, appWidgetIds); } }
RemoteViews remoteViews 就代表了 app Widget 中所有的控件.运行后:
点击这个 App Widget 中的 Button,就会跳到 targetActivity 界面.
-
Appwidget
2012-10-12 15:29:30什么是AppWidget?AppWidget就是我们平常在桌面上见到的那种一个个的小窗口,利用这个小窗口可以给用户提供一些方便快捷的操作。本篇打算从以下几个点来介绍AppWidget: 1.如何创建一个简单的AppWidget 2....什么是AppWidget?AppWidget就是我们平常在桌面上见到的那种一个个的小窗口,利用这个小窗口可以给用户提供一些方便快捷的操作。本篇打算从以下几个点来介绍AppWidget:
1.如何创建一个简单的AppWidget
2.如何使得AppWidget与客户端程序交互
创建简单的AppWidget在介绍之前给大家看一下程序运行的最后结果和项目结构图,以便大家有个整体的印象。
运行结果图:
项目结构图:
第一步:
首先在res文件夹下新建一个名字为xml的文件夹,然后在xml目录下创建一个名为appwidget01的xml文件(如上图所示)。这个appwidget01中的内容如下:
123456789<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
appwidget-provider
android:minWidth
=
"294dp"
android:minHeight
=
"72dp"
android:updatePeriodMillis
=
"86400000"
android:initialLayout
=
"@layout/appwidgetlayout"
>
</
appwidget-provider
>
这个xml是用来描述你所要创建的appWidget的一些描述信息的,比如高度、宽度、刷新间隔、布局文件等等。仅仅这个描述文件还不够,我们看到的appWidget可都是有界面元素的呀,比如说文本,图片,按钮等等,这些东西的定义都需要放到layout文件夹下面。这个文件就是上面代码中写到的那个appwidgetlayout。
第二步:
在layout文件夹下面新建一个appwidgetlayout.xml文件,在这个文件中描述了appWidget的控件和布局等等信息,就和我们平常创建的一个activity的布局文件没什么两样,因为只是简单的演示,所以仅用一个文本和一个按钮。xml的内容如下:
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
>
<
TextView
android:id
=
"@+id/txtapp"
android:text
=
"test"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:background
=
"#ffffff"
></
TextView
>
<
Button
android:id
=
"@+id/btnSend"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"Send"
></
Button
>
</
LinearLayout
>
第三步:
既然appWidget中存在按钮等等控件,那么就肯定少不了处理这些控件事件的处理代码啦。这些代码被放在一个继承于AppWidgetProvider的类中,在本例子中我新建了一个AppWidget的类,该类继承于AppWidgetProvider,以后所有的AppWidget上面的控件事件都会在这个类中处理。看一下类的内容:
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354public
class
AppWidget
extends
AppWidgetProvider
{
private
final
String broadCastString =
"com.qlf.appWidgetUpdate"
;
/**
* 删除一个AppWidget时调用
* */
@Override
public
void
onDeleted(Context context,
int
[] appWidgetIds)
{
super
.onDeleted(context, appWidgetIds);
}
/**
* 最后一个appWidget被删除时调用
* */
@Override
public
void
onDisabled(Context context)
{
super
.onDisabled(context);
}
/**
* AppWidget的实例第一次被创建时调用
* */
@Override
public
void
onEnabled(Context context)
{
super
.onEnabled(context);
}
/**
* 接受广播事件
* */
@Override
public
void
onReceive(Context context, Intent intent)
{
super
.onReceive(context, intent);
}
/**
* 到达指定的更新时间或者当用户向桌面添加AppWidget时被调用
(当用户修改appwidget内容并刷新时,并不调用此函数)
* */
@Override
public
void
onUpdate(Context context, AppWidgetManager appWidgetManager,
int
[] appWidgetIds)
{
}
}
各个方法的作用大家一看上面的注释就明白了。我们暂时不需要实现里面的方法。
第四步:
在AndroidManifest.xml中定义一些创建AppWidget必要的东西,先看代码:
1234567891011121314151617181920<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
package
=
"com.qlf.widget"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
application
android:icon
=
"@drawable/icon"
android:label
=
"@string/app_name"
>
<
activity
android:name
=
".MainActivity"
android:label
=
"@string/app_name"
>
<
intent-filter
>
<
action
android:name
=
"android.intent.action.MAIN"
/>
<
category
android:name
=
"android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
<
receiver
android:name
=
"AppWidget"
>
<
intent-filter
>
<
action
android:name
=
"android.appwidget.action.APPWIDGET_UPDATE"
></
action
>
</
intent-filter
>
<
meta-data
android:name
=
"android.appwidget.provider"
android:resource
=
"@xml/appwidget01"
/>
</
receiver
>
</
application
>
<
uses-sdk
android:minSdkVersion
=
"8"
/>
</
manifest
>
可以看到我们在配置文件里面定义了一个receiver,他的名字是上面创建处理控件代码的那个类,下面那个intent-filter中的action是系统自带的用于更新所有appwidget的广播动作。然后meta-data标签是一个描述我们创建appwidget的元数据,那个android:name="android.appwidget.provider"是固定的,android:resource="@xml/appwidget01"指定创建的appWidget的描述信息的位置。这样程序就知道到哪里去初始化这些appWidget啦。
经过上面四个步骤,我想您已经能够成功在桌面上添加小工具了,效果就是我们最前面发出的样子。AppWidget与程序交互前面我们只是简单的介绍了如何创建一个appWidget,但是目前这个appWidget还没有任何的交互功能。下面我们介绍一下appWidget如何与程序进行交互。首先要介绍一个对象,这个对象在appwidget和程序的交互中很重要,他就是RemoteViews。因为appwidget运行的进程和我们创建的应用不在一个进程中,所以我们也就不能像平常引用控件那样来获得控件的实例。这个时候RemoteViews出场了,从字面上看他的意思是远程的视图,也就是说通过这个东西我们能够获得不在同一进程中的对象,这也就为我们编写appwidget的处理事件提供了帮助。我们使用一下代码来创建一个RemoteViews :
123RemoteViews remoteViews =
new
RemoteViews(context.getPackageName(),R.layout.appwidgetlayout);
remoteViews.setOnClickPendingIntent(R.id.btnSend, pendingIntent);
//为小工具上的按钮绑定事件
可以看到上面又出现了一个陌生的对象pendingIntent,这个又是用来干嘛的呢?我们知道在一般的程序中绑定按钮的点击事件是直接在实现了OnClickListener接口的类中中完成的。不过因为appwidget并不在我们应用的进程中,所以当然他也访问不到我们在应用中设置的onclick代码啦。而PendingIntent就是被用来解决这个问题的。PendingIntent可以看成是一个特殊的Intent,如果我们把Intent看成一封信,那么PendingIntent就是一封被信封包裹起来的信。这封信在remoteViews.setOnClickPendingIntent()中被“邮寄”到了appwidget, 当appwidget中的按钮单击时他知道将这封信打开,并执行里面的内容。这样就避免了直接从appwidget中执行本地代码。我们来看看PendingIntent是如何定义的:
123456//创建一个Intent对象
Intent intent =
new
Intent();
intent.setAction(broadCastString);
//这一步相当于写信,说明这个信的作用到底是什么,在这里表示将发送一个广播
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0
, intent,
0
);
有了上面的介绍,我们在创建appwidget的交互应用时就简单不少了。我们剩下要做的工作就是在appwidget在创建的时候调用上面说到的方法为appwidget中的控件绑定事件,也就是在AppWidget类下的onUpdate方法中完成这个过程。123456789101112131415161718192021222324/**
* 到达指定的更新时间或者当用户向桌面添加AppWidget时被调用
* */
@Override
public
void
onUpdate(Context context, AppWidgetManager appWidgetManager,
int
[] appWidgetIds)
{
//创建一个Intent对象
Intent intent =
new
Intent();
intent.setAction(broadCastString);
//设置pendingIntent的作用
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0
, intent,
0
);
RemoteViews remoteViews =
new
RemoteViews(context.getPackageName(),R.layout.appwidgetlayout);
//绑定事件
remoteViews.setOnClickPendingIntent(R.id.btnSend, pendingIntent);
//更新Appwidget
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
通过上面的代码我们就为button按钮绑定了一个事件,这个事件的作用是发送一个广播便于其他应用接收、更新信息。这是appwidget发送广播,那么appwidget如何接受来自其他程序发送的广播呢?这就是public void onReceive(Context context, Intent intent)的功能啦。这个方法会接收来自其他应用发出的广播,我们只要在这个程序中过滤我们需要的广播就能响应其他应用的操作来更新appwidget的信息了。要注意的是,因为appwidget运行的进程和我们创建的应用不在一个进程中的限制,所以更新的appwidget的时候也要通过远程对象来操作,具体代码如下:
12345678910111213141516171819202122232425/**
* 接受广播事件
* */
@Override
public
void
onReceive(Context context, Intent intent)
{
if
(intent.getAction().equals(broadCastString))
{
//只能通过远程对象来设置appwidget中的控件状态
RemoteViews remoteViews =
new
RemoteViews(context.getPackageName(),R.layout.appwidgetlayout);
//通过远程对象将按钮的文字设置为”hihi”
remoteViews.setTextViewText(R.id.btnSend,
"hihi"
);
//获得appwidget管理实例,用于管理appwidget以便进行更新操作
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
//相当于获得所有本程序创建的appwidget
ComponentName componentName =
new
ComponentName(context,AppWidget.
class
);
//更新appwidget
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
super
.onReceive(context, intent);
}
总结下就是appwidget上的操作都必须借助远程对象来操作。最后看一下运行的图片吧:
按之前:
按之后:
而如果Activity要与Appwidget交互的话
只需要获得相应的appwidget的view,然后修改这个view,并更新这个view(注:更新内容并不会调用onUpdate方法)
public void onClick(View v) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.main);
remoteViews.setTextViewText(R.id.text, "config");
//相当于获得所有本程序创建的appwidget
//更新appwidget
appWidgetManager.updateAppWidget(new ComponentName(AppwidgetDemoActivity.this, MyAppWidgetProvider.class), remoteViews);
}
-
appwidget
2012-04-18 17:03:28什么是AppWidget?AppWidget就是我们平常在桌面上见到的那种一个个的小窗口,利用这个小窗口可以给用户提供一些方便快捷的操作。本篇打算从以下几个点来介绍AppWidget: 1.如何创建一个简单的AppWidget 2.如何... -
AppWidget-源码
2021-03-17 14:34:33AppWidget -
Android App Widget
2021-04-07 18:14:50Android通知系统是它的一大特色,而其中,AppWidget是其中一个亮点。在开发应用的中,很多时候可以为其添加一个AppWidget显示在桌面中,及时方便的与用户进行 交互。这里就简单的熟悉一下开发一个AppWidget的流程吧... -
AppWidget应用(一)---创建一个appWidget
2019-07-07 13:58:15appWidget是显示的桌面上的小窗口程序,通过它可以达到用户与程序之间的交互。 下面我们来看下创建一个appWidget的步骤 一、首先在layout文件夹下创建一个appWidget的布局文件appwidgetlayout.xml, 在这里你可以... -
Android桌面组件App Widget用法入门教程
2021-01-20 10:05:31本文实例讲述了Android桌面组件App Widget用法。分享给大家供大家参考。具体如下: Android开发应用除了程序应用,还有App Widget应用。好多人会开发程序应用而不会开发App Widget应用。本帖子就是帮助大家学习如何... -
Android中的AppWidget入门教程
2021-01-05 02:49:16什么是AppWidget?AppWidget就是我们平常在桌面上见到的那种一个个的小窗口,利用这个小窗口可以给用户提供一些方便快捷的操作。本篇打算从以下几个点来介绍AppWidget: 1.如何创建一个简单的AppWidget 2.如何使得App...