android widget 开发
因为项目中需要用到widget,所以在这里大致记录一下widget的使用流程。因为没有深入的研究,所以仅仅是做一个大概的解析,因为需求简单,这里就不介绍RemoteViewService和RemoteViewFactory了,如果需要的不要浪费时间看下去,抱歉各位。widget也叫小部件,是一个微型视图,其实在手机launcher中的表就是个widget。在开始流程之前需要明白两个概念:
AppWidgetProviderInfo
描述小部件的元数据元素,包括描述了部件的布局和更新频率,以及AppWidgetProvider的信息
AppWidgetProvider
基于广播事件,,在这里可以对widget进行一些操作,包括widget的启用,更新,删除等操作。因为继承自BroadcastReceiver,因此也可以根据最基本的广播操作来进行事件的处理。
接下来就是开始创建widget,其实过程比较简单,studio提供了很多帮助:
在这里直接创建widget,填写细节之后,就会生成一个继承自AppWidgetProvider的类,
public class MyWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
//在这里进行部件的更新。需要怎样操控部件都可以再这里通过RemoteViews实现。
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
//这里会遍历所有的部件,然后都进行更新。
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
@Override
public void onEnabled(Context context) {
// 当widget被创建的时候调用。
}
@Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
//这里可以接收自定义的一些广播,进行处理。
}
}
同时在androidManifest文件中也会生成MyWidget的注册内容
<receiver
android:name=".widget.MyWidget"
android:enabled="true"
android:exported="true">
<intent-filter>
<!-- 在这里还可以添加其他自定义的广播 -->
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<!-- widget的配置信息文件 -->
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/new_app_widget_info" />
</receiver>
其中name属性表明类名,intent-filter表示的是接收的广播action,meta中的属性name表示meta-data的名称,这里必须是android.appwidget.provider, resource这里是表示资源文件的目录。接下来看资源文件:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:initialKeyguardLayout="@layout/new_app_widget"
android:initialLayout="@layout/new_app_widget"
android:minHeight="170dp"
android:minWidth="250dp"
android:previewImage="@drawable/example_appwidget_preview"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="86400000"
android:widgetCategory="home_screen"></appwidget-provider>
initialkeyguardlayout表示了一个资源文件,在widget创建的时候可以立刻出现。4.2以后引入的。
initialLayout 表示了widget的资源文件。
minHeight和minWidth定义了widget的最小高和宽,低于这个值widget不可以用。
previewImage这个就是一个预览图的效果。就像app的桌面logo,默认是applogo。
resizeMode:指定widget大小在哪个方向调整。
updatePerionMillis:这个只的是部件的更新频率,最小是半小时,设置的很小也会默认为半小时。
widgetCategory:表示部件是否可以显示在主屏上,默认home_screen,还有power属性。
到这里就可以通过new_app_widget这个布局文件来写小部件的布局了。需要注意的是这个布局文件支持的控件是有限制的, 首先自定义的控件不支持, 支持的布局控件如下:
布局:FrameLayout,RelativeLayout,Linearlayout,GridLayout
控件:Button,ImageButton, ImageView,TextView,ListView,GridView,AnalogClock,Progressbar,ViewFlpper,StackView
更新部件的功能都是通过RemoteView来实现的,至于怎样更新可以根据自己的需求来定。如果用到listview,gridview等布局可以通过RemoteviewService来实现这个部件的更新,在我的项目里比较简单,直接通过启动一个service进行来更新:在MyWidget中的onenable中通过启动一个service来实现更新,
private void updateWidget(Context context, WeatherWrap weatherWrap) {
if (weatherWrap == null) {
return;
}
ComponentName componentName = new ComponentName(context, WeatherWidget.class);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
remoteViews.setTextViewText(R.id.temperature, weatherWrap.getNow().getTemp()+"°C");
remoteViews.setTextViewText(R.id.weather_status, DBHelper.getInstance().getWeatherTypeByCode(
weatherWrap.getNow().getWeatherType()));
remoteViews.setTextViewText(R.id.city, weatherWrap.getRegion());
remoteViews.setTextViewText(R.id.air_quality, weatherWrap.getAqi().getAqi() + " "
+ weatherWrap.getAqi().getQuality());
if (weatherWrap.getSuggestion().getDressing() != null) {
remoteViews.setTextViewText(R.id.clothing_index, weatherWrap.getSuggestion().getDressing().getBrief());
}
remoteViews.setTextViewText(R.id.humidity, weatherWrap.getNow().getHumidity() + "%");
if(weatherWrap.getSuggestion().getHongfans() != null){
remoteViews.setTextViewText(R.id.env_status,weatherWrap.getSuggestion().getHongfans().getDetails());
}
remoteViews.setImageViewResource(R.id.weather_bg, Utils.weatherCode2BG(weatherWrap.getNow().getWeatherType()));
//在这里添加一个点击事件,当点击id为city的按钮会跳转到制定activity
Intent intent = new Intent(context, WeatherActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.city, pendingIntent);
AppWidgetManager awm = AppWidgetManager.getInstance(context.getApplicationContext());
awm.updateAppWidget(componentName, remoteViews);
}
可以看到remoteVIew的设置控件内容的方式,以及点击跳转的方式。最后都需要通过AppWidgetManager来进行更新。在MyWidget文件的updateAppWidget()函数中也需要添加好更新widget的方法。至于具体的更新方式要根据自己的项目需求而定。