试着写一个音乐播放器的桌面控件,练习下前三篇的内容。
假定现在有一个 MusicService.class 来实现对音乐播放 的控制。我们需要做的是:写一个 app widget 包含当前音乐封面、歌曲名、歌手名、上下一曲、暂停播放的按钮。通过按钮发送对应的广播,然后 MusicService 接收广播消息实现对播放的控制。
分析:appwidget 监听桌面按钮,然后根据按钮的不同,发送不同的广播指令给 MusicService ,MusicService 收到指令后 按照指令的不同,实现不同的功能(如上下一曲、暂停播放等)并远程更新 appwidget 的显示(当前歌曲封面、歌曲名、歌手名、播放/暂停显示 等)。
步骤:
1. 在 layout 文件夹下创建 appwidght.xml 文件。在里面写入你的 app widght 布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <ImageView android:id="@+id/appwidget_image" android:layout_width="60dip" android:layout_height="fill_parent" android:layout_alignParentLeft="true" android:src="@drawable/ic_launcher" /> <TextView android:id="@+id/appwidget_text_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:paddingTop="6dip" android:layout_toRightOf="@id/appwidget_image" android:text="music name" /> <TextView android:id="@+id/appwidget_text_singer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:paddingBottom="6dip" android:layout_toRightOf="@id/appwidget_image" android:text="singer name" /> <Button android:id="@+id/appwidget_button_next" android:layout_width="50dip" android:layout_height="50dip" android:layout_alignParentRight="true" android:layout_centerVertical="true" android:background="@drawable/next_w" /> <Button android:id="@+id/appwidget_button_play" android:layout_width="60dip" android:layout_height="60dip" android:layout_marginLeft="15dip" android:layout_marginRight="15dip" android:layout_toLeftOf="@id/appwidget_button_next" android:layout_centerVertical="true" android:background="@drawable/play_w" /> <Button android:id="@+id/appwidget_button_last" android:layout_width="50dip" android:layout_height="50dip" android:layout_toLeftOf="@id/appwidget_button_play" android:layout_centerVertical="true" android:background="@drawable/last_w" /> </RelativeLayout>
效果如下(演示时加上了红色背景填充,最后手动换成了透明图标。):
2. 在 res 目录下创建 xml 文件夹。并在 res/xml 文件夹下创建 app_widght.xml 文件。在文件里写入如下内容:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:minWidth="300dip" android:minHeight="60dip" android:updatePeriodMillis="43200000" android:initialLayout="@layout/appwidget"> </appwidget-provider>
3. 创建类 MyAppWidget 并继承 AppWidgetProvider 。然后重写里面的 onUpdate() 方法。
@Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { for(int i = 0; i < appWidgetIds.length; i++){ RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget); Intent last_intent = new Intent(); last_intent.setAction("last"); PendingIntent last_pendingIntent = PendingIntent.getBroadcast(context, 0, last_intent, 0); remoteViews.setOnClickPendingIntent(R.id.appwidget_button_last, last_pendingIntent); Intent play_intent = new Intent(); play_intent.setAction("play"); PendingIntent play_pendingIntent = PendingIntent.getBroadcast(context, 0, play_intent, 0); remoteViews.setOnClickPendingIntent(R.id.appwidget_button_play, play_pendingIntent); Intent next_intent = new Intent(); next_intent.setAction("next"); PendingIntent next_pendingIntent = PendingIntent.getBroadcast(context, 0, next_intent, 0); remoteViews.setOnClickPendingIntent(R.id.appwidget_button_next, next_pendingIntent); appWidgetManager.updateAppWidget(appWidgetIds[i], remoteViews); } super.onUpdate(context, appWidgetManager, appWidgetIds); }
至此,监听按钮并发送给 MusicService 的功能已经实现了。(如果谁知道这段重复代码怎么消灭,请不吝赐教,谢谢。)
4. 功能写完了,但是,千万千万别忘了 在AndroidManifest.xml 里注册一下 app widget 的 revice。
<receiver android:name="MyAppWidget"> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/app_widget"/> </receiver>
至此,app widget 的使命就算是完成了。接下来就是 服务端(MusicService )的工作了。
5. MusicService 接收 并更新 app widget 的图标和文字。
(1) 首先动态注册一个 BroadcastReceiver ,用来监听 app widget 发送的三个广播 代码如下:
private Broadcast_Receiver receiver;
receiver = new Broadcast_Receiver(); IntentFilter filter = new IntentFilter(); filter.addAction("last"); filter.addAction("next"); filter.addAction("play"); this.registerReceiver(receiver, filter);
(2) 在 MusicService 里创建一个 Broadcast_Receiver extends BroadcastReceiver 的内部类(内部类可以自由使用 MusicService 的属性和方法)。代码如下:
public class Broadcast_Receiver extends BroadcastReceiver { private Context context; @Override public void onReceive(Context context, Intent intent) { this.context = context; // 获取action标记,用与区分点击事件 String ctrl_code = intent.getAction(); if ("play".equals(ctrl_code)) { 播放音乐()/暂停播放(); } }else if ("next".equals(ctrl_code)) { 下一曲(); } else if ("last".equals(ctrl_code)) { 上一曲(); } } }
汉字部分,应使用 MusicService 现成的方法。(别告诉我你音乐服务里没有具体播放的方法...)
(3) 发广播提示 app widget 更新图片和文字显示。
在 MusicService 里需要更新 ui 时,调用 uodateAppWidget() 方法,方法代码如下:
public void updateAppWidget(){ Bundle bundle = new Bundle(); bundle.putStringArray("data", musicData); bundle.putParcelable("bitmap",bmp); Intent intent = new Intent(); intent.setAction("update_appwidget"); intent.putExtras(bundle); sendBroadcast(intent); }
其中,musicData 是包含了 正在播放的歌曲名和歌手名的数组。 bmp 是当前歌曲专辑的 bitmap 图。
(4) app widget 接收广播,并实现更新。
@Override public void onReceive(Context context, Intent intent) { if("update_appwidget".equals(intent.getAction())){ //接收数据 Intent _intent = intent; Bundle b =_intent.getExtras(); Bitmap bmp = (Bitmap) b.getParcelable("bitmap"); String[] str = b.getStringArray("data"); //更新 appwidget RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget); AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context); remoteViews.setTextViewText(R.id.appwidget_text_name, str[0]); remoteViews.setTextViewText(R.id.appwidget_text_singer, str[1]); remoteViews.setImageViewBitmap(R.id.appwidget_image , bmp); appWidgetManager.updateAppWidget(new ComponentName(context, MyAppWidget.class), remoteViews); } super.onReceive(context, intent); }
(5) 切记,要在 AndroidMainIfest.xml 中注册 intent-filter
<intent-filter> <action android:name="update_appwidget"/> </intent-filter>
注册在 app widget 的 revice 里面。
至此,音乐播放器 appwidget 功能已全部实现。