这次的练习项目是桌面组件播放器,用到Widget、Service、Broadcast的内容。
做好的界面如图所示
就只是简单的开始、上一首、下一首的按钮,开始按钮身兼开始和暂停两个功能,由于是自己切的图,所以就突出一个丑字。
本播放器目前有两个功能缺失,一个是没有根据Service的状态来更新开始按钮的图片,应该是开始后改成暂停的;另一个是没有做出当前歌曲播放完之后自动播放下一首的功能。
首先贴出Widget的设置XML
<appwidget-provider
xmlns:android="http://schemas.android.com/apk/res/android"
//设置宽度
android:minWidth="230dp"
//设置高度
android:minHeight="280dp"
//设置更新间隔时间
android:updatePeriodMillis="20000"
//设置图标
android:previewImage="@drawable/last"
//设置布局资源
android:initialLayout="@layout/appwidget"
//设置在桌面可见
android:widgetCategory="home_screen"
>
</appwidget-provider>
布局太过简单就无须贴出了。
接下来看MyWidgetProvider的支持类
public class MyAppWidgetProvider extends AppWidgetProvider {
//初始化Appwidget
private MyAppWidgetProvider mProvider = null;
private boolean mStop = true;
//延时意图的初始化方法
private PendingIntent getPendingIntent(Context context,int buttonId){
Intent intent = new Intent();
intent.setClass(context, MyAppWidgetProvider.class);
//添加识别信号
intent.addCategory(Intent.CATEGORY_ALTERNATIVE);
//设置按钮id信号
intent.setData(Uri.parse("jianyufeichen:" + buttonId));
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
return pi;
}
private void pushUpdate(Context context,AppWidgetManager appWidgetManager) {
//获取视图
RemoteViews remoteView = new RemoteViews(context.getPackageName(),R.layout.appwidget);
//将按钮与点击事件绑定
remoteView.setOnClickPendingIntent(R.id.start_button, getPendingIntent(context, R.id.start_button));
remoteView.setOnClickPendingIntent(R.id.last_button, getPendingIntent(context, R.id.last_button));
remoteView.setOnClickPendingIntent(R.id.next_button, getPendingIntent(context, R.id.next_button));
// 相当于获得所有本程序创建的appwidget(这本该是用来根据service来更新UI的)
ComponentName componentName = new ComponentName(context,MyAppWidgetProvider.class);
appWidgetManager.updateAppWidget(componentName, remoteView);
}
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.d("harvic", "action:" + action);
//辨别信号来源
if (intent.hasCategory(Intent.CATEGORY_ALTERNATIVE)) {
//获取信号中带有的按钮id
Uri data = intent.getData();
int buttonId = Integer.parseInt(data.getSchemeSpecificPart());
//根据不同的按钮id执行不同的反应
switch (buttonId) {
case R.id.start_button:
pushAction(context, MusicService.ACTION_PLAY_PAUSE);
if (mStop){
Intent startIntent = new Intent(context,MusicService.class);
context.startService(startIntent);
mStop = false;
}
break;
case R.id.last_button:
pushAction(context, MusicService.ACTION_LAST);
break;
case R.id.next_button:
pushAction(context, MusicService.ACTION_NEXT);
}
}
super.onReceive(context, intent);
}
//根据不同按钮id发送广播给MusicService
private void pushAction(Context context, int ACTION) {
Intent actionIntent = new Intent(MusicService.ACTION);
actionIntent.putExtra(MusicService.KEY_USR_ACTION,ACTION);
context.sendBroadcast(actionIntent);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
pushUpdate(context,appWidgetManager);
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
}
该类主要做的就是为按钮设置点击事件,分辨按钮点击的Id,根据不同的按钮点击来发送携带不同数据的广播,以便于Service接受来采取不同的措施。
本作业很大程度上参考了另外一篇文章,链接如下http://blog.csdn.net/harvic880925/article/details/41754477
接下里贴出MusicService类的代码
public class MusicService extends Service {
//初始化MediaPlay类
private MediaPlayer mediaPlayer;
//设置播放列表
private int[] mArrayList=new int[3];
//设置初始播放歌曲位置
private int mindex = 0;
//设置MyAppWidgetProvider类传递来的动作信息
public static String ACTION = "to_service";
public static String KEY_USR_ACTION = "key_usr_action";
public static final int ACTION_PLAY_PAUSE = 1,ACTION_NEXT = 2,ACTION_LAST = 3;
private boolean mPlayState = false;
//MusicService的广播接收器
private BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//获取广播中的动作信息
String action = intent.getAction();
if (ACTION.equals(action)){
int widget_action = intent.getIntExtra(KEY_USR_ACTION,-1);
//根据动作信息执行
switch (widget_action){
case ACTION_LAST:
lastSong(context);
break;
case ACTION_PLAY_PAUSE:
if (mPlayState){
pause(context);
}else {
play(context);
}
break;
case ACTION_NEXT:
nextSong(context);
break;
default:
break;
}
}
}
};
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
//动态注册广播接收器
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION);
registerReceiver(receiver,intentFilter);
//初始化播放列表
initlist();
//开始播放
mediaPlayerStart();
}
//开始播放方法
private void mediaPlayerStart(){
mediaPlayer = new MediaPlayer();
mediaPlayer=MediaPlayer.create(getApplicationContext(),mArrayList[mindex]);
mediaPlayer.start();
mPlayState = true;
}
//初始化播放列表的方法
private void initlist(){
mArrayList[0]=R.raw.first;
mArrayList[1]=R.raw.ki;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
mediaPlayer.stop();
}
//播放下一首的方法
public void nextSong(Context context){
if (++mindex>1){
mindex=0;
}
mPlayState = true;
playSong(context,mArrayList[mindex]);
}
//播放上一首的方法
public void lastSong(Context context){
if (--mindex<0){
mindex = 1;
}
mPlayState = true;
playSong(context,mArrayList[mindex]);
}
//开始播放方法
public void play(Context context){
mPlayState = true;
mediaPlayer.start();
}
//暂停方法
public void pause(Context context){
mPlayState = false;
mediaPlayer.pause();
}
//当播放上一首下一首的方法
public void playSong(Context context,int resid){
AssetFileDescriptor afd = context.getResources().openRawResourceFd(mArrayList[mindex]);
try {
mediaPlayer.reset();
mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getDeclaredLength());
mediaPlayer.prepare();
mediaPlayer.start();
afd.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
这里MusicService是根据MyWidget类发送的广播中携带的信息来进行操作的,收到的信息有三个,分别是开始、下一首、上一首。当然,开始信号要结合当前是否在播放来决定是开始播放还是暂停播放。这里还有一个没有完成的地方就是暂停后无法继续播放,而是直接从当前歌曲的开头播放。在MusicService中用一个泛型数组来对歌曲资源进行整理,当播放下一首的时候就在该泛型数组中寻找下一首的资源来进行播放,如果将列表里的最后一首歌也播放完了就轮回地播放第一手,播放上一首的方法同上。
总体该项目的主要思想就是在桌面上的组件UI通过用户点击按钮来发送广播让Service接受,然后Service根据广播内容来进行操作。
最后,对于新手来说,在AndroidManifest里注册也是挺麻烦的,我在该项目的注册如下。
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.administrator.mywidget" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
//widget的注册
<receiver android:name=".MyAppWidgetProvider">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="@layout/appwidget_provider">
</meta-data>
</receiver>
<service android:name=".MusicService"
android:enabled="true"
android:exported="true">
</service>
</application>
</manifest>
需要注册就是Widget的资源和更新。