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>  






  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值