最近因为项目的原因学习了一下Widget的开发,Widget开发的中文资料,网上的确不是很多,原版的只有那么几份,大家都是抄来抄去的。由于本人接触android仅有半月之久,所以在不了解android的很多机制下,开发APPWidget的开发实在是令人头皮发麻的事情,建议如果是初学android又急于要上手写急于桌面组件的widget程序童鞋,多看看android的activity,service,intent,BroadcastReceiver等这些东东。比如widget中AppWidgetProvider这个关键点东东就是派生自BroadcastReceiver,这样或许能少走一点弯路。

不说其他的了,直接进入正题这个工程主要是为了实现两个功能:USB设备的卸载装载和任务管理器。

1.预实现功能

如图所示:


最首先我们来看看我们的工程目录结构:


2.桌面组件的布局文件和配置文件

从图中可以看出我们使用了三个ImageButton控件,由文件my_app_widget.xml布局而成,代码如下:

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:orientation="horizontal"    android:layout_width="fill_parent"    android:layout_height="fill_parent"android:layout_marginLeft="50dp"><ImageButton  xmlns:android="http://schemas.android.com/apk/res/android"  android:id="@+id/SD_ImgView"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:clickable="true"></ImageButton><ImageButton  xmlns:android="http://schemas.android.com/apk/res/android"  android:id="@+id/Task_ImgView"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:src="@drawable/taskmanager"  android:clickable="true"></ImageButton><ImageButton  xmlns:android="http://schemas.android.com/apk/res/android"  android:id="@+id/USB_ImgView"  android:layout_width="wrap_content"  android:layout_height="wrap_content"  android:clickable="true"></ImageButton></LinearLayout

我们还可以调整图标的位置和按钮的大小,这些我们就不讲述了。再直接看widget的部署文件,我这里取名也是my_app_widget.xml但是该文件放在src目录的XML文件中,代码如下:

<?xml version="1.0" encoding="utf-8"?><appwidget-provider  xmlns:android="http://schemas.android.com/apk/res/android"  android:minWidth="250dp"   android:minHeight="140dp"android:updatePeriodMillis="86400000" android:initialLayout="@layout/my_app_widget"></appwidget-provider>

上面的这些属性简单介绍下,appwidget-provider:是定义这个xml文件是桌面组件的属性的配置文件

minWidth:是定义这个桌面组件需要显示的最小宽度
minHeight:是定义这个桌面组件需要显示的最小高度
updatePeriodMillis:这个是定义桌面组件刷新的时间,单位是毫秒,定义很大意思是基本不刷新,如果是一些实时性有要求的,那么这个就可以定义成几秒刷新一次,具体根据自己的需求
initialLayout:这个是桌面组件的布局文件的路径,这里意思是该文件在src的layout目录的my_app_widget文件为布局文件(也就是上面那个列出来的源码文件)

3.AppWidgetProvider类的编写

好,完成以上两项以后,也就是我们这个项目的显示部分做完了,那么如何让显示东西能产生点击动作呢,对于桌面组件widget来讲,最重要最关键的AppWidgetProvider这个类,首先我们新建一个AppWidgetProvider类取名EquipmentTaskOperationProvider,然后继承其中的onupdate这个回调函数,代码如下:

EquipmentTaskOperationProvider.java

package com.roadrover.lyf.equipmentTask;import java.io.BufferedReader;import java.io.File;import java.io.IOException;import java.io.InputStreamReader;import com.roadrover.lyf.equipmentTask.Configuration.ConfigurationException;import android.app.PendingIntent;import android.appwidget.AppWidgetManager;import android.appwidget.AppWidgetProvider;import android.content.Context;import android.content.Intent;import android.content.SharedPreferences;import android.content.SharedPreferences.Editor;import android.util.Log;import android.widget.RemoteViews;public class EquipmentTaskOperationProvider extends AppWidgetProvider {private static final String SD_CLICK_ACTION = "com.roadrover.lyf.equipmentTask.widgetAppProvider.action.sd.click";private static final String USB_CLICK_ACTION = "com.roadrover.lyf.equipmentTask.widgetAppProvider.action.usb.click";private static RemoteViews rv;// 更新单元@Overridepublic void onReceive(Context context, Intent intent) {// TODO Auto-generated method stubsuper.onReceive(context, intent);Log.d("myDebug", intent.getAction());}@Overridepublic void onUpdate(Context context, AppWidgetManager appWidgetManager,int[] appWidgetIds) {// TODO Auto-generated method stub// super.onUpdate(context, appWidgetManager, appWidgetIds);sharedPreferences=context.getSharedPreferences("setting", Context.MODE_PRIVATE);final int N = appWidgetIds.length;for (int i = 0; i < N; i++) {int appWidgetId = appWidgetIds[i];Log.d("myDebug", "onUpdate is called!");updateAppWidget(context, appWidgetManager, appWidgetId);}}/** Called when the activity is first created. */public static void updateAppWidget(Context context,AppWidgetManager appWidgeManger, int appWidgetId) {Log.d("myDebug", "updateAppWidget is called!");if (rv == null) {//第一次创建该组件时实例化更新单元rv = new RemoteViews(context.getPackageName(),R.layout.my_app_widget);//initEquipmentListStatus(appWidgetId, appWidgeManger);}Intent taskClick = new Intent(context, TasksManager.class);Intent sdClick = new Intent(SD_CLICK_ACTION);Intent usbClick = new Intent(USB_CLICK_ACTION);PendingIntent pendingIntent1;PendingIntent pendingIntent2;PendingIntent pendingIntent3;pendingIntent2 = PendingIntent.getService(context, 0, usbClick, 0);pendingIntent1 = PendingIntent.getService(context, 0, sdClick, 0);pendingIntent3 = PendingIntent.getActivity(context, 0, taskClick, 0);rv.setOnClickPendingIntent(R.id.SD_ImgView, pendingIntent1);rv.setOnClickPendingIntent(R.id.Task_ImgView, pendingIntent3);rv.setOnClickPendingIntent(R.id.USB_ImgView, pendingIntent2);appWidgeManger.updateAppWidget(appWidgetId, rv);}}

这里比较关键的代码我用紫色的字体标记起来,从上面给出的设计效果图来看,我们需要实现上面三个按键的点击事件。首先这里我要讲下为什么我们主要的方法是在onupdate中实现的,因为桌面组件第一次创建首先会调用onenable然后onupdate然后onrecieve,如果有多个该组件被创建了,那么第二次onenable就不会调用了,而只会调用onupdate,所以我们所有的初始化工作在onupdate中进行,代码中有usb点击、sd卡点击和查看已运行的程序点击三个事件,在这里我们使用一个service来处理sd卡和usb设备的点击事件,而使用activity来处理任务管理器事件。查文档可知,通过widget启动servcie可以使用PendingIntent.getService方法,(如果通信方式我们选择不将消息加入到目标servcie的intent-filter中,我们选择PendingIntent.getBroadCast方法),而启动activity则使用getActivity方法,最后通过setOnClickPendingIntent方式进行事件绑定。

4、布局文件与AppWidgetProvider关联

那么如何将xml布局文件与AppWidgetProvider关联起来呢,我们需要在AndroidManifest中加入receiver
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.roadrover.lyf.equipmentTask" android:versionCode="1"android:versionName="1.0"><application android:icon="@drawable/log" android:label="@string/app_name" android:theme="@android:style/Theme.Translucent"><receiver android:name=".EquipmentTaskOperationProvider"><meta-data android:name="android.appwidget.provider"android:resource="@xml/my_app_widget" /><intent-filter><action android:name="android.appwidget.action.APPWIDGET_UPDATE" /></intent-filter></receiver><activity android:name=".TasksManager"></activity><service android:name=".EpOperaService"><intent-filter><actionandroid:name="com.roadrover.lyf.equipmentTask.widgetAppProvider.action.sd.click" /><actionandroid:name="com.roadrover.lyf.equipmentTask.widgetAppProvider.action.usb.click" /></intent-filter></service><activity android:name=".EpTaskConf"></activity></application><uses-sdk android:minSdkVersion="8" /><uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" /></manifest> 
如源码所示,紫色部分的receiver定义了一个APPWIDET_UPDATE的过滤器,这个就是说当桌面组件创建时发出receiver对象会收到update消息,也就是说EquipmentTaskOperationProvider会调用onupdate回调函数。
那么按钮如何触发的消息如何传递呢,我们可以看到manifest文件中有加入了.EpOperaService这个Service,而且加入了两个action一个是sd卡click消息另外一个是usb设备click消息,(注意这里的两个消息必须与AppWidgetProvider中定义的两个消息一致)如此当按钮发送了消息之后,便将消息发送至EpOperaService中,我们便可以在service中intent对象中取得传递过来的消息。

更多相关文章

  1. NPM 和webpack 的基础使用
  2. 【阿里云镜像】使用阿里巴巴DNS镜像源——DNS配置教程
  3. 想抢先体验Android操作系统的魅力吗?那就使用Android(安卓)LiveCD
  4. Android编程简单实现拨号器功能的方法
  5. android如何开发流量监控软件
  6. Android周学习Step By Step(5)--常用widget组件
  7. Android开发指南-框架主题-资源和资产
  8. 二、Android工程的编译过程
  9. Android(安卓)GPIO LED 驱动与HAL分析

随机推荐

  1. Android(安卓)- 小功能 - android手动开
  2. Android开发小知识点集锦
  3. android动态给view设置可见、不可见属性
  4. android 更新ADT之后 报java.lang.NoClas
  5. Android必备软件
  6. Android中ButterKnife框架
  7. Android(安卓)中多点触摸协议
  8. Android(安卓)API开发之OpenGL开发之Andr
  9. 从jdk1.7.0获取MD5认证指纹方法
  10. Android(安卓)笔记