上一章讲述了Android界面开发中的Widget,Service,BroadcastReceiver基本知识点,本章以一个实际案例-后台音乐播放器解析各个知识点之间的关系。
1.功能需求
做一个Android音乐播放器
- 用到Service、Broadcast Receiver、Widget
- 使用后台服务播放音乐
- 做一个音乐播放的Widget
- 显示歌曲名
- 显示上一首、下一首、播放、暂停
2.软件实现
图1
图2
图3
简易说明
长按手机界面出现如图2所示信息,弹出小部件选项,点击进入小部件如图1。选择极客班-作业四,根据提示拖放界面到桌面,出现如图3所示音乐播放界面。点击按钮可实现音乐切换播放歌曲功能。
3.实现流程
后台音乐播放器主要是通过Widget的特性,用广播为通道,完成Widget与Service之间的交互。
Widget:更新桌面信息,发送广播信息,接收用户操作事件。
Service:注册服务,接收广播信息,发送广播信息。
4.界面布局
音乐播放器在界面布局和配置文件中主要包括以下方面:
- appwidget-provider提供了桌面widget的初始化显示状态、默认图标、大小等功能,它放在res/xml文件夹下,参考项目中的music_app_widget_info.xml文件。
- android:initialLayout="@layout/music_app_widget":这个就是指定初始化显示时,应该显示的布局,参考项目中的music_app_widget.xml文件。
- 项目应用了服务,广播,须在AndroidManifest.xml中配置相应的标签。具体信息参考项目中的AndroidManifest.xml文件。
5.核心代码分析
(1)Widget函数-onUpdate()
在用户添加Widget时,会调用OnUpdate()函数,在OnUpdate()中要实现绑定RemoteView和更新Widget的操作。在绑定控件时,主要应用了PendingIntent的方式。
PendingIntent 是Intent的封装,在构造PendingIntent前,也要先构造一个Intent,并可以利用Intent 的属性传进去action,Extra等,同样,在接收时,对方依然是接收Intent的,而不是接收PaddingIntent。
PendingIntent.getBroadcast(context, 0,intent, 0);指从系统中获取一个用于可以发送BroadcastReceiver广播的PendingIntent对象。PendingIntent这个类用于 处理即将发生的事情。比如在通知Notification中用于跳转页面,但不是马上跳转。所以可以将它理解成
一个封装成消息的intent的。即这个intent并不是立即start,而是像消息一样被发送出去,等接收方接到以后,再分析里面的内容。项目相关代 码摘抄如下:
1 private PendingIntent getPendingIntent(Context context, int buttonId) { 2 Intent intent = new Intent(); 3 intent.setClass(context, ExampleAppWidgetProvider.class); 4 intent.addCategory(Intent.CATEGORY_ALTERNATIVE); 5 intent.setData(Uri.parse("harvic:" + buttonId)); 6 PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0); 7 return pi; 8 } 9 10 // 更新所有的 widget 11 private void pushUpdate(Context context,AppWidgetManager appWidgetManager,String songName,Boolean play_pause) { 12 13 RemoteViews remoteView = new RemoteViews(context.getPackageName(),R.layout.music_app_widget); 14 //将按钮与点击事件绑定 15 remoteView.setOnClickPendingIntent(R.id.play_pause,getPendingIntent(context, R.id.play_pause)); 16 remoteView.setOnClickPendingIntent(R.id.prev_song, getPendingIntent(context, R.id.prev_song)); 17 remoteView.setOnClickPendingIntent(R.id.next_song, getPendingIntent(context, R.id.next_song)); 18 19 //设置内容 20 if (!songName.equals("")) { 21 remoteView.setTextViewText(R.id.song_name, songName); 22 } 23 //设定按钮图片 24 if (play_pause) { 25 remoteView.setImageViewResource(R.id.play_pause, R.drawable.button_stop); 26 }else { 27 remoteView.setImageViewResource(R.id.play_pause, R.drawable.button_on); 28 } 29 // 相当于获得所有本程序创建的appwidget 30 ComponentName componentName = new ComponentName(context,ExampleAppWidgetProvider.class); 31 appWidgetManager.updateAppWidget(componentName, remoteView); 32 } 33 34 @Override 35 public void onUpdate(Context context, AppWidgetManager appWidgetManager, 36 int[] appWidgetIds) { 37 38 pushUpdate(context,appWidgetManager,"",false); 39 }