上一节已经写了一个可以在桌面显示的widget,但是还有一些问题是没有解决的,主要包括以下:
1.widget最小更新的时间也是半个小时,那么如何让它实时的进行更行来完成与用户的交互?
2.widget上如果有点击事件或其他,如何响应其点击事件,与用户进行交互?
要解决这两个问题,就要回到MyWidget这个类,这个类继承了AppWidgetManager,一切从这里入手,便可以进行分析了。
在AppWidgetManager中,重写以下几个方法:
1)
只要对widget操作,就会回调这个方法
2)
当appWidget更新时会回调,也就是说最少半个小时调用一次。
以上两个方法都用不太到,主要介绍后两种方法:
3)
在AppWidget第一次被拉入到桌面时调用,appWidget可以被多次拖入到桌面,但是只有第一次被拖入到桌面时会回调,其他时候都是不会回调的。
4)
在AppWidget最后一次从桌面删除时调用。
了解了以上的几个基本方法,我们解决第一个问题的思路就是:
1.在第一次将widget拖入到桌面时,开启一个服务,在服务中定时的更新widget控件。当最后一个widget从桌面删除后,关闭这个服务。
因此要在onEnable中开启注册一个服务,在onDisable中停止这个服务.而在这个服务中用来进行定时的更新widget操作,代码如下:
@Override
public void onEnabled(Context context) {
startUpdateService(context);
//第一次把widget加入到桌面时
super.onEnabled(context);
//第一次拖过来时开启
Log.d(TAG, "onEnabled");
}
/**
* 开启更新widget服务
*/
private void startUpdateService(Context context) {
Intent intents = new Intent(context,UpdateWidgetService.class);
context.startService(intents);
Log.d(TAG, "intent.."+intents);
}
@Override
public void onDisabled(Context context) {
Intent intents = new Intent(context,UpdateWidgetService.class);
context.stopService(intents);
//最后一次把widget删除桌面
super.onDisabled(context);
Log.d(TAG, "onDisabled intent.."+intents);
// intent = null;
Log.d(TAG, "onDisabled");
}
2.那么我们就需要一个服务,在服务中进行相应的操作,因此要定义一个类UpdateWidgetService继承Service,并在清单文件注册。
那么如何在服务中进行定时更新呢?我们不用去考虑什么更新widget操作,只需要抽象的去考虑如何可以做到定期更新就好了,有许多种方式,在这里我们选用timer,timerTask.
在服务调用onCreate()方法时,调用timer.scheduleAtFixedRate(timerTask, 0, 3*1000),就开启了循环的timerTask的服务。
在服务回调onDestory时,进行timer.cancel(),task.cancel();
如下所示:
A.
B.
C.
D.
.
3.到上面已经解决了第一个问题,如何解决widget最短更新时间的问题,思路就是在widget第一次被拖入桌面时开启一个服务,在服务中利用Timer定时更新。那么接下来的问题是如何控制widget控件?
这里面的难点是widget是在桌面上显示的,不再我们的程序中,如何远程控制这个控件呢?
android的api给我们提供了一个类,叫做AppWidgetManager,通过调用它的方法就可以了。
AppWidgetManager awm = AppWidgetManager.getInstance(this);//这个方法是实例化这个对象
awm.updateAppWidget(componentName,RemotoViews);//利用这个方法可以更新widget,在timerTask中调用此即可。
这个方法有两个参数,第一个是ComponentName,代表的是继承了AppWidgetProvider的那个类,也就是MyWidget.java.
第二个参数是remoteViews,这个view是一个远程view,专门用来显示在其他process中的,在更新widget的操作中,它取代view,成为我们操作的对象。
4.生成的代码如下:
实例化ComponentName和RemoteViews.
ComponenetName(上下文,关联的appWidgetProvider.class);
RemoteViews("包名",“widget在桌面显示的布局文件”);
5.得到了RemoteViews,就可以得到布局文件中的各个控件,进行各种操作了。不过操作的方式与普通的view有些不一样,看下:
第一个参数是要操作的空间的id,第二个参数是内容,相当于findViewById(R.id.process_count).setText(list.toString);但由于是远程操控,只能用上述,其实上述也是通过内部反射来实现的。
6.那么到这里只剩最后一步了,如何点击Widet中的button后可以响应点击事件呢?代码如下:
定义一个PendingIntent,使它延迟发送一个广播,第二个参数随便写。那么既然是延迟发送,延迟到何时呢?应该是BUTTON被点击后,因此:
这样就响应了点击widget中的按钮后发送广播,在广播中处理点击事件。
那根据上述我们也得定义一个发送广播的Intent,放到PendingIntent的第三个参数去:
设置一个Action,以便广播接收者接收过滤,注意:不用写sendBroadCast(),因为在PendIngIntent中已经封装好了。
7.那么最后一步就是定义一个广播接收者,用来处理想要的点击事件了。代码就不写了。
第一次写,以前认为很简单的东西没想到操作起来很困难,写的一片浆糊,有些博客功能还不会,希望再接再厉吧。