这一篇主要是记录,在initialLayout(加载到桌面对应的布局文件),如果布局文件中有按钮,想要实现点击事件,这个时候不再是平常一样了。以下记录单个按钮的点击事件,多个按钮的点击事件,以及点击按钮如何实现跳转客户端。
一、首先,要先简单了解一下两部分知识
(一)关于PendingIntent
1.那么PendingIntent是什么?我的理解是可以让外部程序执行当前程序的意图。
因为PendingIntent持有当前app的context引用,所以,它与Intent的区别有,它可以在外部执行PendingIntent里面的Intent。
Intent是立即执行,PendingIntent不是立刻执行的。
2.如何使用PendingIntent?
可以通过PendingIntent.getActivity(Context context,int RequestCode,Intent intent,int flags),或者getBroadcast()、getService()去获取实例。更多详细的参考以下文章
《PendingIntent详解》
《PendingIntent详解 》
《Android开发陷阱:利用PendingIntent传递唯一的Intent》
(二)关于RemoteView
RemoteView描述一个view,而这个view是在另外一个进程显示的。它inflate于layout资源文件。并且提供了可以修改过view内容的一些简单基础的操作.
《Android widget 之RemoteView》
二、单个按钮的点击事件
1.在initialLayout中添加一个按钮以及一个ImageView图片,通过点击widget按钮实现更换ImageView的图片,布局文件如下
<?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">
<ImageView
android:id="@+id/img"
android:layout_width="wrap_content"
android:layout_height="200dp"
android:layout_gravity="center"
android:src="@drawable/preview"/>
<Button
android:id="@+id/btn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="改变图片"
/>
</LinearLayout>
2.在AppWidget中,先在onUpdate方法中去创建RemoteView以及绑定Id。代码如下
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
//分别绑定id
remoteViews.setOnClickPendingIntent(R.id.btn,getPendingIntent(context,R.id.btn));
//更新widget
appWidgetManager.updateAppWidget(appWidgetIds,remoteViews);
}
private PendingIntent getPendingIntent(Context context, int resID){
Intent intent = new Intent();
intent.setClass(context, AppWidget.class);//如果没有这一句,表示匿名的。加上表示是显式的。在单个按钮的时候是没啥区别的,但是多个的时候就有问题了
intent.setAction("btn.text.com");
//设置data域的时候,把控件id一起设置进去,
// 因为在绑定的时候,是将同一个id绑定在一起的,所以哪个控件点击,发送的intent中data中的id就是哪个控件的id
intent.setData(Uri.parse("id:" + resID));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,intent,0);
return pendingIntent;
}
3.通过上面的操作发送了广播,那么在AppWidget的onReceive方法中就可以去做接收部分的操作了
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("btn.text.com")){
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Uri data = intent.getData();
int resId = -1;
if (data!=null){
resId = Integer.parseInt(data.getSchemeSpecificPart());
}
switch (resId){
case R.id.btn:
remoteViews.setImageViewResource(R.id.img, R.drawable.logo);
break;
}
//获得appwidget管理实例,用于管理appwidget以便进行更新操作
AppWidgetManager manger = AppWidgetManager.getInstance(context);
// 相当于获得所有本程序创建的appwidget
ComponentName thisName = new ComponentName(context,AppWidget.class);
//更新widget
manger.updateAppWidget(thisName,remoteViews);
}
三、多个按钮的点击事件
基本步骤大致相同,关键是在onUpdate方法中,如果说Intent 没有显示调用的话
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { RemoteViews remoteViews = new RemoteViews(context.getPackageName(),R.layout.widget_layout);
//分别绑定id
remoteViews.setOnClickPendingIntent(R.id.btn,getPendingIntent(context,R.id.btn));//第一个按钮
remoteViews.setOnClickPendingIntent(R.id.btn2,getPendingIntent(context,R.id.btn2));//第二个按钮
//更新widget
appWidgetManager.updateAppWidget(appWidgetIds,remoteViews);
}
private PendingIntent getPendingIntent(Context context, int resID){
Intent intent = new Intent();
//intent.setClass(context, AppWidget.class);//此时这句代码去掉
intent.setAction("btn.text.com");
//设置data域的时候,把控件id一起设置进去,
// 因为在绑定的时候,是将同一个id绑定在一起的,所以哪个控件点击,发送的intent中data中的id就是哪个控件的id
intent.setData(Uri.parse("id:" + resID));
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0,intent,0);
return pendingIntent;
}
会发现点击第一个按钮的时候会发生变化,但是点击第二个按钮的时候,接收不到消息。详情参见《Android开发陷阱:利用PendingIntent传递唯一的Intent》、PendingIntent传递值分析。
对了,这边还有个问题需要注意的是,设置data域的时候,即Intent.setData(Uri.parse("id:"+ID)),如果少了“:”冒号的话,在onReceive方法中去解析对应的控件id的时候 Integer.parseInt(data.getSchemeSpecificPart()),会报java.lang.NumberFormatException异常;
四、关于如何点击widget上的按钮跳转到主程序
前面的步骤一致,区别在onReceive方法中的操作
@Override
public void onReceive(Context context, Intent intent) {
// 接收到任意广播时触发,在其他方法之前被调用。
if (intent.getAction().equals("btn.text.com")){
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
Uri data = intent.getData();
int resId = -1;
if (data!=null){
resId = Integer.parseInt(data.getSchemeSpecificPart());
}
switch (resId){
case R.id.btn3:
String flag = "i am comming!";//可以传递一些数据到主客户端
Intent startAcIntent = new Intent();
startAcIntent.setComponent(new ComponentName("admin.example.com.myapplication","admin.example.com.myapplication.MainActivity"));//第一个是包名,第二个是类所在位置的全称
startAcIntent.putExtra("flag",flag);
startAcIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startAcIntent);
break;
}
//获得appwidget管理实例,用于管理appwidget以便进行更新操作
AppWidgetManager manger = AppWidgetManager.getInstance(context);
// 相当于获得所有本程序创建的appwidget
ComponentName thisName = new ComponentName(context,AppWidget.class);
//更新
manger.updateAppWidget(thisName,remoteViews);
}
Log.i(TAG, "onReceive: 执行");
super.onReceive(context, intent);
}