Android之窗口小部件详解–App Widget
本篇文章详细讲解App Widget 实现:
AppWidgetProviderInfo object
AppWidgetProviderInfo描述了App widget 的数据元,例如Widget的layout,update frequency,和AppWidgetProvider类。他应该被定义在XML文件里
AppWidgetProvider class implementation
定义最基本的方法,通过广播事件让程序与桌的APP widget交互,也就是一个桥梁在widget界面和程序,通过这个类当app widget 更新,enabled, disabled,和deleted时可以收到一个广播
- View Layout
在XML文件里定义App Widget 初始化的布局,另外在这里你可以配置一个实现App Widget configuration Activity. 这是一个可选的Activity ,当在添加一个widget时启动的就是这个类在这里可以进行一些App Widget settings 修改。
在Manifest声明一个App Widget
首先你应该创建一个类继承AppwidgetProvider,然后再manifest里声明它。这里我创建了一个WidgetProvider类。
在这里我又另加两个action 一个是刷新,另一个是widget的点击事件的action,当需要刷新或者点widget时设置为这两个action 并在WidgetProvider类里的onReceive方法里处理这两个广播事件。<receiver android:name=".appwidgetprovider.WidgetProvider" android:label="@string/app_name"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> <action android:name="action.widget.REFRESH" /> <action android:name="action.widget.onclick" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/widget"></meta-data> </receiver>
Adding the AppWidgetProviderInfo Metadata
AppWidgetProviderInfo定义了一些widget的基本条件例如桌面widget的大小,刷新时间,initialLayout桌面小部件的具体布局等(此布局建在XML文件里 个人命名为widget,并且配置了一个WidgetConfigActivity)<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:configure="com.luckyxmobile.servermonitorplus.activity.WidgetConfigActivity" android:minWidth="40dp" android:minHeight="40dp" android:initialLayout="@layout/widget_layout" android:updatePeriodMillis="100000" > </appwidget-provider>
Creating the App Widget Layout
创建一个App Widget布局(layout文件里,名为widget_layout),创建这个布局文件的时候和其他布局页的创建差不多,但是你必须要知道App widget 的布局页是基于RemoteViews的,所以并不支持所有的控件的使用,有些在这里是无法使用的,具体的使用可以参考[官方文档](https://developer.android.com/guide/topics/appwidgets/index.html#CreatingLayout)的说明. 前面有说到WidgetConfigActivity 也就是当我们在桌面添加widget项时所启动的Activity 所以在这里我们可以设置添加时的一些设置或者提供一些所要widget的选项如图所示在添加小部件的时候让其弹出一个页面选择所想要贴在桌面的site项,这里也就是一个简单listview的实现,所以我们可以在这里添加一些我们想要实现的样式或者功能,![这里写图片描述](https://img-blog.csdn.net/20160827094811042)Using the AppWidgetProvider Class
创建WidgetProvider并且继承AppWidgetProvider需要重写onUpdate方法,先来说一下这个类的作用,此类接收并处理里一些widget的广播例如updated, deleted, enabled, and disabled,当这些广播事件发什么的时候WidgetProvider类将会接收到这些广播并且去调用相应的方法。如下方法。
- onUpdate()
刷新方法,在上面的AppWidgetProviderInfo我们定义的widget的刷新时间,所以到了刷新的时间就会调用这个方法。当收到刷新的广播也是调用这个方法 - onDeleted()
每当widget从桌面删除的时候,就会发送一个删除广播,当收到这个广播的时候就会调用这个方法。注意这个删除的广播是禁止我们程序员去发送的,所以只有用户手动把widget从桌面删除的时候才会自动的发送这个广播。 - onEnabled()
当widget第一次被创建的时候才会调用,例如我们创建两个桌面小部件只有第一次创建的时候才会调用这个方法。 - onDisabled()
只有最后一个桌面小部件被删除的时候才会调用 - onReceive()
接受广播,在这里我们可以处理一些广播事件,例如当我们需要刷新widget时这时我们可以在相应的代码里设置一个广播并发送如下代码
Intent refreshIntent = new Intent(); refreshIntent.setAction(WidgetData.REFRESH_ACTION); sendBroadcast(refreshIntent);
然后在widgetProvider的onReceive()方法里这样写,这样就在你想更新widget的地方刷新了widget
if (intent.getAction() == "action.widget.REFRESH") { this.onUpdate(ctx, AppWidgetManager.getInstance(ctx), null); }
我们也可以去设置一些其他的广播,例如当我们点击桌面小部件的时候去启动我们的应用并跳到相应的页面,这时我们就要先设置一个广播,并在manifest的widgetProvider里去声明一下,如我上述讲过的声明。
<action android:name="action.widget.onclick" />
if (intent.getAction() == "action.widget.onclick") { //widget的点击时启用这里具体的启动方法代码可以 intentAction(ctx, intent); this.onUpdate(ctx, AppWidgetManager.getInstance(ctx), null); }
public class WidgetProvider extends AppWidgetProvider { public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { final int N = appWidgetIds.length; // Perform this loop procedure for each App Widget that belongs to this provider for (int i=0; i<N; i++) { int appWidgetId = appWidgetIds[i]; // 这里是点击桌面的widget启动相应的activity正如我上述所讲 也可以在这里设置action然后在onReceive方法里去隐式的启动一个Activity Intent intent = new Intent(context, ExampleActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0); // Get the layout for the App Widget and attach an on-click listener // to the button RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout); views.setOnClickPendingIntent(R.id.button, pendingIntent); // Tell the AppWidgetManager to perform an update on the current app widget appWidgetManager.updateAppWidget(appWidgetId, views); } } }
这里只是个人的总结,更具体共官方的可以点击这里查看
Creating an App Widget Configuration Activity
创建一个WidgetConfigurationActivity,在这里正如上述所说可以添加一些创建Widget时所需要的一下widget设置或选项,如上述图片所示就是实现后的展示,和我们平常的Listview的添加是一样的,因为是WidgetConfiguration 所以还要实现以下几点:
- 布局 上述提到过
- 在manifest里要声明这个类
- 在开始时我们在XML文件里的widget.xml里我们要配置这个类如下
android:configure="com.luckyxmobile.servermonitorplus.activity.WidgetLargeConfigActivity"
- 编写这个类,遵循以下几点,这里也可以做一些Preference数据保存,例如我们获取的widget的id可以以与我们程序里的ListViewitem的id对应存储,当需要做相应操作的时候可以对应取到与桌面widget对应的id.
1.First, get the App Widget ID from the Intent that launched the Activity:获取当前Widget的ID,
Intent intent = getIntent(); Bundle extras = intent.getExtras(); if (extras != null) { mAppWidgetId = extras.getInt( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); }
2.Perform your App Widget configuration.
3.When the configuration is complete, get an instance of the AppWidgetManager by calling getInstance(Context):AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
4.Update the App Widget with a RemoteViews layout by calling updateAppWidget(int, RemoteViews)刷线widget下面这段代码很重要
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_appwidget); appWidgetManager.updateAppWidget(mAppWidgetId, views);
5.Finally, create the return Intent, set it with the Activity result, and finish the Activity:
Intent resultValue = new Intent(); resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId); setResult(RESULT_OK, resultValue); finish();
最后如果我们想要动态去刷新桌面小部件可以去创建一个WidgetBackgroundService类继承 Service这里我们开一些线程去定时的刷新widget,以下是简单刷新方法,
private void updateWidget() { siteWidgetName = new ComponentName(getBaseContext(), WidgetProvider.class); int[] siteWidgetIds = AppWidgetManager.getInstance( getBaseContext()).getAppWidgetIds(siteWidgetName); for (int i = 0; i < siteWidgetIds.length; i++) { int theSelectSiteID = mSharedPreferences.getInt(WidgetData. WIDGET_SELECTED_ID + siteWidgetIds[i], -1); appWidgetManager = AppWidgetManager .getInstance(getBaseContext()); //因为具体的页面刷新在其他地方也会用到所以把它写到一个公共类里 里面实现具体的页面刷新方法。 WidgetData.upDateWidgetView(appWidgetManager, theSelectSiteID, getBaseContext(), siteWidgetIds[i]); } }
具体的widget实现比较推荐去看一下官方文档
由于是第一次写博客,会有不足,欢迎大家来指正。- onUpdate()