fengyuzhengfan的专栏

这里有一则 阿里的招聘启事 打开链接查看 ☛:http://www.devio.org/recruitment

Android开发之基于Service的音乐播放器

            这是一个基于Service组件的音乐播放器,程序的音乐将会由后台的Service组件负责播放,当后台的播放状态改变时,程序将会通过发送广播通知前台Activity更新界面;当用户单击前台Activity的界面按钮或拖动进度条时,系统通过发送广播通知后台Service来改变播放状态和播放指定音乐。

程序运行效果图:

基于Service的音乐播放器

Android音乐播放器       音乐播放器项目结构

程序代码:

程序界面类(MusicBox.java):

package com.jph.musicbox;

import com.jph.util.ConstUtil;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
/**
 * Describe:</br>
 * </br>基于Service的音乐播发器
 * </br>本应用主要实现了:
 * </br>1.通过前台Activity发出播放相关的控制信息,以广播的形式
 * </br>传递给后台的Service,后台的Service负责音乐的播放。
 * </br>并负责接收后台的广播来更新播放界面的歌曲名、歌手名。
 * </br>2.通过进度条来显示当前播放的位置,当用户拖动进度条时
 * </br>通过OnSeekBarChangeListener事件来控制
 * </br>后台的mediaPlayer播放指定位置的音乐。
 * </br>@author jph
 * </br>Date:2014.08.07
 * */
public class MusicBox extends Activity {	
	ImageButton btnPlayOrPause,btnPre,btnNext;	
	//进度条
	static SeekBar skbMusic;
	// 获取界面中显示歌曲标题、作者文本框
	TextView title, author;	
	String[] titleStrs = new String[] { "涛声依旧", "油菜花", "You Are The One" };
	String[] authorStrs = new String[] { "毛宁", "成龙", "未知艺术家" };
	//是否正在播放
	boolean isPlaying=false;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		skbMusic=(SeekBar)findViewById(R.id.skbMusic);
		skbMusic.setOnSeekBarChangeListener(sChangeListener);
		btnNext=(ImageButton)findViewById(R.id.btnNext);
		btnPlayOrPause=(ImageButton)findViewById(R.id.btnPlayOrPause);
		btnPre=(ImageButton)findViewById(R.id.btnPre);
		btnNext.setOnClickListener(listener);
		btnPlayOrPause.setOnClickListener(listener);
		btnPre.setOnClickListener(listener);
		title=(TextView)findViewById(R.id.title);
		author=(TextView)findViewById(R.id.author);
		title.setText(titleStrs[0]);
		author.setText(authorStrs[0]);		 
		//注册接收器
		MusicBoxReceiver mReceiver=new MusicBoxReceiver();
		IntentFilter filter=new IntentFilter();
		filter.addAction(ConstUtil.MUSICBOX_ACTION);
		registerReceiver(mReceiver, filter);
		//启动后台Service
		Intent intent=new Intent(this, MusicService.class);
		startService(intent);
		
	}
	OnClickListener listener=new OnClickListener() {		
		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
			
			switch (v.getId()) {
			case R.id.btnNext://下一首
				btnPlayOrPause.setBackgroundResource(R.drawable.state_pasue);
				sendBroadcastToService(ConstUtil.STATE_NEXT);				
				isPlaying=true;
				break;
			case R.id.btnPlayOrPause://播放或暂停
				if (!isPlaying) {
					btnPlayOrPause.setBackgroundResource(R.drawable.state_pasue);
					sendBroadcastToService(ConstUtil.STATE_PLAY);
					isPlaying=true;
				}else {
					btnPlayOrPause.setBackgroundResource(R.drawable.state_play);
					sendBroadcastToService(ConstUtil.STATE_PAUSE);
					isPlaying=false;
				}
				break;
			case R.id.btnPre://上一首
				btnPlayOrPause.setBackgroundResource(R.drawable.state_pasue);
				sendBroadcastToService(ConstUtil.STATE_PREVIOUS);
				isPlaying=true;
				break;
			default:
				break;
			}			
		}
	};
	/**
	   * SeekBar进度改变事件
	   */
	OnSeekBarChangeListener sChangeListener=new OnSeekBarChangeListener() {		
		@Override
		public void onStopTrackingTouch(SeekBar seekBar) {
			// TODO Auto-generated method stub
			//当拖动停止后,控制mediaPlayer播放指定位置的音乐
			MusicService.mediaPlayer.seekTo(seekBar.getProgress());
	        MusicService.isChanging=false;   
		}
		
		@Override
		public void onStartTrackingTouch(SeekBar seekBar) {
			// TODO Auto-generated method stub
			MusicService.isChanging=true;
		}
		
		@Override
		public void onProgressChanged(SeekBar seekBar, int progress,
				boolean fromUser) {
			// TODO Auto-generated method stub
			
		}
	};
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.	
		menu.add(Menu.NONE, ConstUtil.MENU_ABOUT, Menu.NONE, "关于");
		menu.add(Menu.NONE, ConstUtil.MENU_EXIT, Menu.NONE, "退出");
		return true;
	}
	/**
	 *向后台Service发送控制广播
	 *@param state int state 控制状态码
	 * */
	protected void sendBroadcastToService(int state) {
		// TODO Auto-generated method stub
		Intent intent=new Intent();
		intent.setAction(ConstUtil.MUSICSERVICE_ACTION);
		intent.putExtra("control", state);
		//向后台Service发送播放控制的广播
		sendBroadcast(intent);
	}
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		// TODO Auto-generated method stub		
		switch (item.getItemId()) {
		case ConstUtil.MENU_ABOUT:
			LayoutInflater inflater=LayoutInflater.from(this);
			LinearLayout layout=(LinearLayout) inflater.inflate(R.layout.about, null);
			AlertDialog dialog=new AlertDialog.Builder(this).create();
			dialog.setTitle("关于");
			dialog.setIcon(R.drawable.ic_launcher);
			dialog.setView(layout);
			dialog.show();
			break;
		case ConstUtil.MENU_EXIT:
			sendBroadcastToService(ConstUtil.STATE_STOP);
			this.finish();
			break;
		default:
			break;
		}
		return true;
	}

	//创建一个广播接收器用于接收后台Service发出的广播 
	class MusicBoxReceiver extends BroadcastReceiver{
		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			// 获取Intent中的current消息,current代表当前正在播放的歌曲
			int current = intent.getIntExtra("current", -1);
			title.setText(titleStrs[current]);//更新音乐标题
			author.setText(authorStrs[current]);//更新音乐作者
		}
		
	} 
}
负责音乐播放的后台Service类:

MusicService.java

package com.jph.musicbox;

import java.io.IOException;
import java.util.Timer;
import java.util.TimerTask;

import com.jph.util.ConstUtil;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.IBinder;
/**
 * Describe:</br>
 * </br>负责音乐播放的后台Service
 * </br>1.通过接收来自前台的控制播放信息的广播来播放指定音乐
 * </br>2.加载assets目录下的音乐
 * </br>3.为mediaPlayer的完成事件创建监听器当当前音乐播放
 * </br>完成后自动播放下一首音乐
 * </br>4.为每一首正在播放的音乐创建一个定时器,用于检测播放进度
 * </br>并更新进度条 
 * </br>@author jph
 * </br>Date:2014.08.07
 * */
public class MusicService extends Service {
	Timer mTimer;
    TimerTask mTimerTask;
    static boolean isChanging=false;//互斥变量,防止定时器与SeekBar拖动时进度冲突
	//创建一个媒体播放器的对象
	static MediaPlayer mediaPlayer;
	//创建一个Asset管理器的的对象
	AssetManager assetManager;
	//存放音乐名的数组
	String[]musics=new String[]{"taoshengyijiu-maoning.mp3", "youcaihua-chenglong.mp3","You Are The One.mp3" };
	//当前的播放的音乐
	int current=0;
	//当前播放状态
	int state=ConstUtil.STATE_NON;
	//记录Timer运行状态
	boolean isTimerRunning=false;
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();	
		//注册接收器
		MusicSercieReceiver receiver=new MusicSercieReceiver();
		IntentFilter filter=new IntentFilter();
		filter.addAction(ConstUtil.MUSICSERVICE_ACTION);
		registerReceiver(receiver, filter);
		mediaPlayer=new MediaPlayer();
		assetManager=getAssets();
		//为mediaPlayer的完成事件创建监听器
		mediaPlayer.setOnCompletionListener(new OnCompletionListener() {			
			@Override
			public void onCompletion(MediaPlayer mp) {
				// TODO Auto-generated method stub	
//				mTimer.cancel();//取消定时器
				current++;
				prepareAndPlay(current);				
			}
		});
		
	}	
	/**
	 * 装载和播放音乐
	 * @param index int index 播放第几首音乐的索引
	 * */
	protected void prepareAndPlay(int index) {
		// TODO Auto-generated method stub		
		if (isTimerRunning) {//如果Timer正在运行
			mTimer.cancel();//取消定时器
			isTimerRunning=false;
		}		
		if (index>2) {
			current=index=0;
		}
		if (index<0) {
			current=index=2;
		}
		//发送广播停止前台Activity更新界面
		Intent intent=new Intent();
		intent.putExtra("current", index);
		intent.setAction(ConstUtil.MUSICBOX_ACTION);
		sendBroadcast(intent);
		try {
			//获取assets目录下指定文件的AssetFileDescriptor对象
			AssetFileDescriptor assetFileDescriptor=assetManager.openFd(musics[current]);
			mediaPlayer.reset();//初始化mediaPlayer对象
			mediaPlayer.setDataSource(assetFileDescriptor.getFileDescriptor(), 
					assetFileDescriptor.getStartOffset(), assetFileDescriptor.getLength());
  			//准备播放音乐
			mediaPlayer.prepare();
			//播放音乐
			mediaPlayer.start();
			//getDuration()方法要在prepare()方法之后,否则会出现Attempt to call getDuration without a valid mediaplayer异常
			MusicBox.skbMusic.setMax(mediaPlayer.getDuration());//设置SeekBar的长度
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		//----------定时器记录播放进度---------//
        mTimer = new Timer();
        mTimerTask = new TimerTask() {
            @Override
            public void run() { 
            	isTimerRunning=true;
                if(isChanging==true)//当用户正在拖动进度进度条时不处理进度条的的进度
                    return;  
                MusicBox.skbMusic.setProgress(mediaPlayer.getCurrentPosition());
            }
        }; 
        //每隔10毫秒检测一下播放进度
        mTimer.schedule(mTimerTask, 0, 10);       
	}
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}	
	//创建广播接收器用于接收前台Activity发去的广播
	class MusicSercieReceiver extends BroadcastReceiver{
		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			int control=intent.getIntExtra("control", -1);
			switch (control) {
			case ConstUtil.STATE_PLAY://播放音乐
				if (state==ConstUtil.STATE_PAUSE) {//如果原来状态是暂停
					mediaPlayer.start();					
				}else if (state!=ConstUtil.STATE_PLAY) {
					prepareAndPlay(current);
				}
				state=ConstUtil.STATE_PLAY;
				break;
			case ConstUtil.STATE_PAUSE://暂停播放
				if (state==ConstUtil.STATE_PLAY) {
					mediaPlayer.pause();
					state=ConstUtil.STATE_PAUSE;
				}
				break;
			case ConstUtil.STATE_STOP://停止播放
				if (state==ConstUtil.STATE_PLAY||state==ConstUtil.STATE_PAUSE) {
					mediaPlayer.stop();
					state=ConstUtil.STATE_STOP;
				}
				break;
			case ConstUtil.STATE_PREVIOUS://上一首
				prepareAndPlay(--current);
				state=ConstUtil.STATE_PLAY;
				break;
			case ConstUtil.STATE_NEXT://下一首				
				prepareAndPlay(++current);
				state=ConstUtil.STATE_PLAY;
				break;
			default:
				break;
			}
		}
		
	}
}
常量工具类(ConstUtil.java):

package com.jph.util;
/**
 * Describe:</br>
 * </br>常量工具类
 * </br>主要用于为其它类提供程序所用到的常量
 * </br>@author jph
 * </br>Date:2014.08.07
 * */
public class ConstUtil {
	//MusicBox接收器所能响应的Action
	public static final String MUSICBOX_ACTION="com.jph.musicbox.MUSICBOX_ACTION";
	//MusicService接收器所能响应的Action
	public static final String MUSICSERVICE_ACTION="com.jph.musicbox.MUSICSERVICE_ACTION";
	//初始化flag
	public static final int STATE_NON=0x122;
	//播放的flag
	public static final int STATE_PLAY=0x123;
	//暂停的flag
	public static final int STATE_PAUSE=0x124;
	//停止放的flag
	public static final int STATE_STOP=0x125;
	//播放上一首的flag
	public static final int STATE_PREVIOUS=0x126;
	//播放下一首的flag
	public static final int STATE_NEXT=0x127;
	//菜单关于选项的itemId
	public static final int MENU_ABOUT=0x200;
	//菜单退出选的项的itemId
	public static final int MENU_EXIT=0x201;
	
	public ConstUtil() {
		// TODO Auto-generated constructor stub
	}

}
项目清单配置文件:AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.jph.musicbox"
    android:versionCode="1"
    android:versionName="1.0" >
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="18" />
    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <!-- 去掉主界面的标题栏 -->
        <activity
            android:name="com.jph.musicbox.MusicBox"
            android:label="@string/app_name" 
            android:theme="@android:style/Theme.Black.NoTitleBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <!-- 注册MusicService -->
        <service android:name="com.jph.musicbox.MusicService"></service>
    </application>

</manifest>





阅读更多
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fengyuzhengfan/article/details/38419091
个人分类: Android开发
所属专栏: Android开发成长之路
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭