Android桌面小部件AppWidget:音乐播放器桌面控制部件Widget(3)
Android桌面小部件AppWidget比较常用的场景就是音乐播放器,音乐播放器虽然通常在后台播放,但需要在桌面提供一个可以控制播放状态的APP widget,为用户提供播放、暂停、停止音乐播放器的功能。
在附录文章1、2的基础上,本文以一个简单的例子加以说明,如何通过桌面小部件实现音乐播放器的播放、停止。简单期间,本例只提供对音乐播放器的两种控制功能:播放和停止。播放,进入后台service播放给定的音乐mp3文件;停止,则直接stopService关闭播放服务即可。
为此,需要在桌面的小部件布局中增加两个按钮,这两个按钮暂时就以Android系统默认的播放(@android:drawable/ic_media_play)和暂停(@android:drawable/ic_media_pause)图片作为按钮使用。当按了播放按钮后,就开始启动后台服务播放mp3音乐文件(暂时以我放置在SDCard根目录下名为zhangphil.mp3的音乐文件为音频源文件);当按了停止按钮后,就stopService,即停止播放。
和附录文章1,2相比,本例不需要更新桌面小部件的表现形式,仅需要处理由桌面小部件传导过来的点击事件,这些响应点击事件,均放置在onReceive里面处理。
(1)
在Androidmanifest.xml里面定义的widget:
<receiver android:name="zhangphil.widget.AppWidget" > <intent-filter> <action android:name="action_play" /> </intent-filter> <intent-filter> <action android:name="action_stop" /> </intent-filter> <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/appwidget" /> </receiver>
涉及到res/xml目录下的appwidget.xml代码文件:
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/appwidget_layout" android:minHeight="20dip" android:minWidth="300dip" android:previewImage="@drawable/ic_launcher" android:resizeMode="horizontal|vertical" android:updatePeriodMillis="0" android:widgetCategory="home_screen" > </appwidget-provider>
(2)service播放音乐。也在Androidmanifest.xml里面定义:
<service android:name="zhangphil.widget.MyService" > </service>
(3)核心关键的AppWidget.java代码文件:
package zhangphil.widget; import android.app.PendingIntent; import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetProvider; import android.content.Context; import android.content.Intent; import android.util.Log; import android.widget.RemoteViews; public class AppWidget extends AppWidgetProvider { @Override public void onReceive(Context context, Intent intent) { super.onReceive(context, intent); // Log.d(this.getClass().getName(), "onReceive"); if (intent == null) return; String action = intent.getAction(); // 停止播放 if (action.equals(Constants.ACTION_STOP)) { Intent serviceIntent = new Intent(context, MyService.class); context.stopService(serviceIntent); } // 点击了按钮,启动一个后台服务播放 if (action.equals(Constants.ACTION_PLAY)) { Intent serviceIntent = new Intent(context, MyService.class); context.startService(serviceIntent); } } @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { Log.d(this.getClass().getName(), "onUpdate"); RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout); // 播放图片作为按钮,绑定播放事件 Intent intentPlay = new Intent(Constants.ACTION_PLAY); PendingIntent pendingIntentPlay = PendingIntent.getBroadcast(context, Constants.REQUEST_CODE_PLAY, intentPlay, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.play, pendingIntentPlay); // 停止图片作为按钮,绑定停止事件 Intent intentStop = new Intent(Constants.ACTION_STOP); PendingIntent pendingIntentStop = PendingIntent.getBroadcast(context, Constants.REQUEST_CODE_STOP, intentStop, PendingIntent.FLAG_UPDATE_CURRENT); remoteViews.setOnClickPendingIntent(R.id.stop, pendingIntentStop); // 更新AppWidget appWidgetManager.updateAppWidget(appWidgetIds, remoteViews); } /** * 删除AppWidget */ @Override public void onDeleted(Context context, int[] appWidgetIds) { super.onDeleted(context, appWidgetIds); Log.d(this.getClass().getName(), "onDeleted"); } @Override public void onDisabled(Context context) { super.onDisabled(context); Log.d(this.getClass().getName(), "onDisabled"); } /** * AppWidget首次创建调用 */ @Override public void onEnabled(Context context) { super.onEnabled(context); Log.d(this.getClass().getName(), "onEnabled"); } }
AppWidget.java里面RemoteViews用到的布局文件appwidget_layout.xml:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#33000000" android:orientation="horizontal" > <ImageView android:id="@+id/play" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_media_play" > </ImageView> <ImageView android:id="@+id/stop" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@android:drawable/ic_media_pause" > </ImageView> </LinearLayout>
(4)service后台服务MyService.java,该部分代码将负责在后台播放或者停止音播放:
package zhangphil.widget; import java.io.File; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.os.Environment; import android.os.IBinder; public class MyService extends Service { // 播放器 private MediaPlayer mMediaPlayer; // 音频文件 private File audioFile; @Override public void onCreate() { super.onCreate(); mMediaPlayer = new MediaPlayer(); // 根目录 File sdcard = Environment.getExternalStorageDirectory(); audioFile = new File(sdcard, "zhangphil.mp3"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 重置 mMediaPlayer.reset(); // 设置播放器的声音源 try { mMediaPlayer.setDataSource(audioFile.getAbsolutePath()); } catch (Exception e) { e.printStackTrace(); } // 也可以从一个静态资源文件中加载音频数据源 // mMediaPlayer.create(this, R.raw.xxx); if (!mMediaPlayer.isPlaying()) { try { mMediaPlayer.prepare(); } catch (Exception e) { e.printStackTrace(); } mMediaPlayer.start(); // 如果设置循环true,那么将循环播放 // mMediaPlayer.setLooping(true); } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); mMediaPlayer.stop(); mMediaPlayer.release(); mMediaPlayer = null; } @Override public IBinder onBind(Intent intent) { return null; } }
(5)定义的公共静态变量Constants.java:
package zhangphil.widget; public class Constants { public static final String ACTION_PLAY = "action_play"; public static final String ACTION_STOP = "action_stop"; public static final int REQUEST_CODE_PLAY = 0xd05; public static final int REQUEST_CODE_STOP = 0xd06; }
代码运行结果如图所示:
附录文章:
1,《Android桌面小部件AppWidget(1)》链接地址:http://blog.csdn.net/zhangphil/article/details/50457355
2,《Android桌面小部件AppWidget(2)》链接地址:http://blog.csdn.net/zhangphil/article/details/50461944