本片将将不以代码为重 ,从另外一个侧面给大家讲述一下Widget的开发。
1.开始
对于什么是Widget ,以及Android的Widget大家通过以前的文章基本上已经了解了。而本次调查哦报告将带大家更好得认识Android的Widget。让大家更加熟练Widget的开发。
那么刚开始,希望大家回顾一下第四期的第一篇文章《让我们再次从Widget的Helloworld开始》。
当时我将代码全部贴出,我们可以看到这个Widget非常简单,他的结构就是Mainfest注册文件,一些布局信息,再加上最后一个集成了appWidget的类,类中东西也非常简单,就是一个RemoteViews!
而对于Widget来说,RemoteViews就是Widget表现层的最核心的要素!
也因此,Android平台的Widget表现力就这样被判了重刑。Widget为什么弱,到底弱到了什么程度,我们接下来通过对SDK的分析来继续。
2.探究Appwidget还有Widget之间的关系
当下载好了Android的SDK后,将你的路径中的这个地址/android-sdk-windows-1.5_r2/docs/index.html,复制到你的浏览器,或者直接打开就可以进入离线版的SDK了。
然后我们点击Reference,看到左边的类的列表,我们就会看到Appwidget这个就是我们要来分析的。
这里我想特别说明一下,虽然都是Widget,但是在Android平台却存在两种不同的Widget
在SDK目录中,我们也可以看到这里有一个android.appwidget,还有一个android.widget。前者就是我们本期的主题widget。而后者则是小部件的意思,我们可以打开ImageView还有textview的SDK中来看,会发现,他们全都是继承这个类。
其实我们app中的每一个UI层的表现元素,都是以widget的名义存在的。
但是后来Google发现当初这样做不太好,因为大家公认的widget发展越来越好,可是widget名称已经被占用了,所以只能做一个Appwidget了。
所以在你看SDK并且希望将相关的内容应用到你自己的程序中的时候一定要分析清楚,也许平时可以直接用Widget指代我们所说的appWidget,但是在SDK中,两者必须区分开。
那我们打开Appwidget以后,我们会出现
AppWidgetHost
AppWidgetHostView
AppWidgetManager
AppWidgetProvider
AppWidgetProviderInfo
这几个类中,我们最常用的是AppwidgetProvider。这各类提供了我们最基本的一个widget。AppwidgetHost 和AppwidgetHostView可以帮助我们来承载Appwidget 。进入程序管理,我们可以发现,Home其实是以一个程序的形式出现,当然这个是不可卸载的。而我们普通点的Widget都是以Home为依托的,Home便使用了AppwidgetHost这个类。那么我们的自己的Activity也可以添加Widget,在你的程序内部只要使用这个Host,然后就可以再你的Activity挂载你需要的appwidget了。
而AppwidgetProviderinfo则可以定义widget的信息,比如说appwidget的大小等等,当然我们通过xml文件也可以达到同样的效果。
另一个AppwidgetManager可以让我们用外部方法来管理Appwidget。我们最常用的就是使用AppwidgetManager来进行appwidget的更新。
最后一个AppwidgetProvider则是我们最重要的类了,因为他决定了我们的widget可以达到什么样的表现效果。
因为这些内容SDK中都有,而且本篇的重点并不是简单罗列SDK,如果大家有什么方法的需要,最有效的方法还是去翻SDK中的相关内容。
所以呢,大家大部分人所说的Widget都是指的是Appwidget,因为大家都默认了,我们也不用关心具体的名称使用了。当然本篇为了区别,当然还是会使用Appwidget指代当前的Widget。
3. Appwidget贫弱的真正罪魁祸首
而我们现在着重分析一下 Appwidgetprovider这各类。首先打开SDK,我们在最左上角的地方就可以看到这个类继承与BroadcastReceiver。BroadcastReceiver是Android平台接受广播的方法。那就是说什么呢?
也许Google一开始就没想过让appWidget有什么表现力,限制他做输出,继承BroadcastReceiver更加有利于Appwidget进行数据的接受。
也许有朋友会说了,这下好了啊,甚至都不用引入了BroadcastReceiver了,那你就大错特错了。因为Appwidget继承这个只是为了给自己图方便。
他是Appwidget,他不是我们平常所用的Activity。
也就是说,很多适用于Activity的东西,Appwidget绝大多数都无法使用。这是真的,就拿一点简单的来说吧每次我们从app引入东西,我们最常用的获取控件Id的方式,就是findviewbyid。
而我们可以很明确的告诉大家,Appwidget不支持这种方法!而且这个方法很重要,没了他很多东西基本上就类似判了死刑。
这里首先来探讨一下控件与我们后台代码之间的关系
~~~~~~~~~~~~~~~
可能有些朋友会认为,起码之前我是这么认为的。就是所有的控件都是被后台代码获取,然后后台代码来进行对屏幕的输出。但实际并不是这样的,只要后台代码声明了布局中的控件,只告诉屏幕有这个东西,但是如何控制它则是另外一种方法。
这样来说吧!假如说Android是一个大饭店的老板,我们的UI控件相当于老板点的菜。 我们的后台代码则像是服务生。
有的时候,我们之需要让服务生通知到老板要这个菜就可以了,然后菜就直接被送到了。这里服务生可以不对这些菜品做任何变动,老板也满意。也就是之前所说的直接声明控件。
但有的时候,为了让老板满意,服务生必须对菜品进行控制,比如过热的菜需要冷却一下,不太好的东西要去掉。等等。但是服务生怎么知道是那些菜品呢?这里就需要一个findviewbyid了。
他就像是超市中的读取条形码的那个设备。我们的动画效果,图片切换,等等都是通过这个来做到的。
而appWidget很明确不支持这个方法。就像是这个老板很苛刻,如果菜品不好,他也不愿让服务生来加一些作料进行调整。
~~~~~~~~~~~~~~~~~~
在Appwidget上,你可以让一个 ImageView显示出来,但是你没办法控制它。
Android的Appwidget简直就和一个聋子一样,改变它的唯一方法,就是更新整个Widget,这个类似于让厨房重新做菜。
我真感觉Android真的是给Widget安了只猪耳朵(Android谐音)!
不支持findviewbyid,这让很多特效就这样和你的widget,say goodbye了
当然我和兽兽在做我们的Widget的时候,也不甘心与就那么放纵大好的Animation效果不用,但是试了很多的方法,但是最后除了惨痛的教训什么都没有获得!
Appwidget最支持什么呢?是RemoteViews,这个是Appwidget支持最好的一个控件了,所以你无论如何得保证你的Appwidget中至少有一个RemoteViews。
RemoteViews可以支持你将Widget自由拖动。
4.不要对UI说无所谓
也许有朋友会对此不屑一顾,但是我想特别声明一下,如果手机平台不去关注UI,不去考虑表现,他还应该考虑些什么呢?界面层是手机最总要的一层,手机屏幕狭小,不像PC。所以一个明了的界面会给你的app带来
和那的提升。
现在的手机很想当年的PC,性能已经不算数特别大的问题了。这是事实,而手机的品种越来越多,而现在的消费者角度,普通的消费者(除了那些技术出身的发烧友),他们才不会管你是用了什么技术、什么系统。
他们只在乎自己的使用体验。
如果一个手机app,功能再强大,没有一个号的UI,没有一个强大的表现层,用户还是不买账的。那些山寨系统能获得消费者的青睐也是抓住了消费者的这一心里。
5. Widget的救命稻草 Service
Appwidget的贫弱 不仅仅是在已经被我们无奈的布局上。appWidget还被Android做了很多限制,甚至Widget不能调用线程!不知道是我和兽兽之前没做好,还是其他的,反正我们一直没能成功调用线程。
如果你要在AppwidgetProvider里面写东西,你所能调用的资源相当有限。
我感觉apwidget像是寄生在Home程序中的,所以也受相应的很多限制。我们的经验告诉我们,除了在RemoteViews中方一些固定的东西,不要指望你的widget能自己做什么,最好的方法是让他当一个被动接受的傀儡。
既然Widget成了傀儡了,那么我们就应该把更多的事务交给别人。Service就是个很好的选择,他可以让Widget重焕生机。
其实Service 是Activity还有Appwidget都可以调用的东西。而且他也有很高的灵活度。
而且更加重要的是,你甚至可以存在于你的Widget里面作为一个内部类。因为Service占用了进程,他可以完成很多Widget无法做到的事情。
Service在做好了自己的工作以后,可以用广播的形式发送给Widget,因为appWidgetManager可以在Widget之外调用,那么我们完全可以在Service里面控制Widget的更新。
Widget的接受方法解释使用BroadcastReceiver原声的继承方法,在本篇调用系统时钟那个例子就很好的讲述了这个方法。
6. 从Widget逃出来的信息
如果什么事情都让别人来做,也不好,appwidget虽然被限制很多,但是我们还是有办法从Widget分出点东西来。RemoteViews给我们提供了原生的 setOnClickPendingIntent方法。
PendingIntent这个想必大家都应该很清楚。因为RemoteViews没有按键时间,所以这个方法就可以出发PendingIntent。
而Widget的点击事件很有特点,之前点击我们Activity的控件,会有专门的按键监听,他会根据案件的ID,来控制按键范围,比如你的ImageViewButton的id 是 R.id.imagebutton。
在下面你只要引入将这个id,按钮事件发出只会在你点击这个区域以后才会发生。
下面这个例子就是点击整个Widget的时候会触发时间。
updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_word);
updateViews.setOnClickPendingIntent(R.id.widget, pendingIntent);
PendingIntent被出发后,发出信息,所以送出送出的消息全部在Intent里面。
至于Android上的传值,大家可以去这个地址来学习一下。
http://www.eoeandroid.com/viewthread.php?tid=967&extra=page%3D1
我觉得我讲的还算是很明白的。
PendingIntent提供了三种方法,一个事getActivity()另一个是getBroadcast()最后一个事getService()
从字面上我们就可以看出这三种方法是启动一个新的Activity、发送一个广播、还有启动一个服务。getService启动的服务如果已经启动了,执行这个语句将会保持服务的运行。
一些具体编程细节问题,本片的 AppWidget 编程实战三部曲已经给打击很明确的答案了。这里不再编码赘述。
文章的初始地址:http://www.eoeandroid.com/viewthread.php?tid=1029