本地音乐播放器——界面和服务的初始化

Posted xingxing_yan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了本地音乐播放器——界面和服务的初始化相关的知识,希望对你有一定的参考价值。

一. 主界面的初始化(MainActivity.java):
开始前先说一下,项目中所有的Activity都是继承BaseActivity,此类是一个abstract,里边有三个虚方法,子类继承需要实现:

 /**
     * 初始化布局
     */
    protected abstract void setLayout();

    /**
     * 初始化控件
     */
    protected abstract void initView();

    /**
     * 初始化监听器
     */
    protected abstract  void setListener();

setLayout比较简单,主要就是设置一下此界面要显示的布局,而setListener中只是注册按钮的监听,所以我们主要看MainActivity中的InitView方法:

@Override
protected void initView() 
        mMusicImage = (XCRoundImageView) findViewById(R.id.main_music_image);
        mPlayedTime = (TextView) findViewById(R.id.main_music_play_time);
        mTotalTime = (TextView) findViewById(R.id.main_music_total_time);
        mMusicSeekBar = (SeekBar) findViewById(R.id.main_music_seekbar);
        mPlayMode = (ImageView) findViewById(R.id.main_play_mode);
        mMusicNext = (ImageView) findViewById(R.id.main_music_next);
        mMusicPrev = (ImageView) findViewById(R.id.main_music_previous);
        mMusicPlay = (ImageView) findViewById(R.id.main_music_play);
        mTvMusicName = (TextView) findViewById(R.id.main_music_name);
        mTvMusicList = (TextView) findViewById(R.id.main_music_list);
        mTvMusicName.setText("未知");

        initAnimation();

        //注册广播接收器
        mMusicReceiver = new MusicReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Contants.ACTIVITY_RECEIVER_ACTION);
        registerReceiver(mMusicReceiver, filter);

        if (!Utils.isMusicServerRunning(this)) 
            startMusicServer(); //启动服务
         else 
            Intent intent = getIntent();
            if (intent.hasExtra(Contants.MUSIC_POS))   //从歌曲列表进入此页面
                int position = intent.getIntExtra(Contants.MUSIC_POS, -1);
                sendBroadcastToServer(Contants.REPLAY, position);
             else     //如果服务在运行,则发广播让服务更新界面
                sendBroadcastToServer(Contants.UPDATE_PLAY_ACTIVITY, -1);
            
        

    

首先我们初始化了所有的控件,然后初始化了一个动画,此动画主要是要来控制mMusicImage 的旋转,这个后边会介绍。然后是注册广播,这没什么说的,记得一个要给filter添加一个action,否则activity就不知道广播要发给谁了。接下来才是重要的,先判断MusicServer是不是在运行,如果没有就启动服务,否则我们需要判断是不是从音乐列表界面跳转到此界面中的,如果是,则将传过来的position的信息发给服务,告诉它需要播放这首音乐。最后,如果是从桌面启动的应用,则进入主界面后给服务发送广播来更新当前界面的信息。

二. 初始化服务(MusicServer):
先来看onCreate方法:

    @Override
    public void onCreate() 
        super.onCreate();
        //申请电源锁,已在锁屏后,手机不清理后台服务(然并卵)
        acquireWakeLock();
        //注册接收器
        mReceiver = new ServiceReceiver();
        IntentFilter filter = new IntentFilter();
        filter.addAction(Contants.SERVER_RECEIVER_ACTION);
     filter.addAction(AudioManager.ACTION_AUDIO_BECOMING_NOISY);
        registerReceiver(mReceiver, filter);

        mBundle = new Bundle();

        //从本地读取之前保存的音乐,模式和播放的位置(初始化界面用)
        mMusicPosition = MusicInfo.getMusicPosition(this);
        mMusicMode = MusicInfo.getMusicMode(this);
        mMusicPlayPos = MusicInfo.getMusicPlayPosition(this);

        //获取音乐列表和当前的音乐对象
        mMusicFiles = Utils.getMusicFile(this);
        if (mMusicFiles != null &&
                (mMusicPosition >= 0 && mMusicPosition < mMusicFiles.size())) 
            mPlayingMusic = mMusicFiles.get(mMusicPosition);
        

        Uri uri = Uri.parse(mPlayingMusic.getUrl());
        mMediaPlayer = MediaPlayer.create(this, uri);

        mTimer = new Timer();
        mTimer.schedule(new UpdateProgressTask(), 0);

        mAmanager = (AudioManager) getApplicationContext().
                getSystemService(Context.AUDIO_SERVICE);
        mListener = new MyOnAudioFocusChangeListener();

        setListener();

    

逐个分析:
1. 申请电源锁,这个方法主要是获取手机锁屏后的一个锁,防止手机锁屏后会清掉我们的服务(有些手机锁屏后会自动清理应用)。不过试过后好像没有什么作用,其实一般手机中设置手机锁屏后不清理哪些应用,所以可以忽略。
2. 注册接收器,在接收器中接收来自界面的广播,并做相应的处理。
3. 读取本地保存信息:在我们每次启动服务时,服务都需要知道之前我们播放的音乐的一下信息,用来初始化界面,所以我们需要在本地保存音乐在列表中的位置mMusicPosition, 播放模式mMusicMode,以及音乐之前播放的位置mMusicPlayPos。
4. 获取音乐列表, MusicServer中需要存储SD卡中所有的音频文件,然后根据mMusicPosition的值来初始化当前音乐mPlayingMusic,mPlayingMusic中有当前音乐的所有信息,这样从音乐列表选择播放某个音乐时,只需要传递position就可以了。
5. 初始化MediaPlayer,根据当前音乐的URL来初始化mMediaPlayer。
6. 定时器:这个定时器主要是用来改变音乐播放进度的,后边会详细解说。
7. 获取音频管理器mAmanager,后边在监听耳机拔出的时候会用到,然后初始化耳机的监听器
8. 设置监听,主要是音乐播放完成后的监听

当启动服务时,服务还需要主动发送一个广播时初始化界面,我们在onStartCommand中做这件事:

 @Override
    public int onStartCommand(Intent intent, int flags, int startId) 
        sendBroadcastToActivity();
        return super.onStartCommand(intent, flags, startId);
    

以上就是主界面和服务的所有初始化操作,接下来,就是服务和界面之间通过广播来进行逻辑业务的实现。

三. 对服务和界面发送广播一些数据的封装:
1.MainActivity中封装的发送广播的方法:

    /**
     * 给服务发送广播
     * @param state
     *
     */
    private void sendBroadcastToServer(int state) 
        Intent intent = new Intent();
        intent.setAction(Contants.SERVER_RECEIVER_ACTION);
        intent.putExtra(Contants.SERVER_SIGNAL, state);
        sendBroadcast(intent);
    

    private void sendBroadcastToServer(int state, Bundle bundle)
        Intent intent = new Intent();
        intent.setAction(Contants.SERVER_RECEIVER_ACTION);
        intent.putExtra(Contants.SERVER_SIGNAL, state);
        if (bundle != null) 
            intent.putExtras(bundle);
        
        sendBroadcast(intent);
    

第一个方法是用来发送给服务,告诉它界面当前执行的是什么动作,如:播放暂停,上一首,下一首,切换模式等。第二个方法除了告诉服务当前的动作外,还要额外带一些数据的广播。

  1. 服务封装的发送广播的方法:
    /**
     * 更新界面的数据
     */
    private void setUpdateActivityParam() 
        mBundle.clear();
        mBundle.putInt(Contants.ACTIVITY_SIGNAL, Contants.UPDATE_PLAY_ACTIVITY);
        mBundle.putInt(Contants.MUSIC_STATE, mMusicState);
        mBundle.putInt(Contants.MUSIC_MODE, mMusicMode);
        mBundle.putInt(Contants.MUSIC_PLAY_POS, mMusicPlayPos);
        mBundle.putSerializable(Contants.CURRENT_MUSIC, mPlayingMusic);

    

    /**
     * 向界面发送广播
     */
    private void sendBroadcastToActivity() 
        setUpdateActivityParam();

        Intent intent = new Intent();
        intent.setAction(Contants.ACTIVITY_RECEIVER_ACTION);
        if (mBundle != null) 
            intent.putExtras(mBundle);
        
        sendBroadcast(intent);
    

setUpdateActivityParam方法封装更新界面所需的所有数据(当前音乐状态,当前播放模式,当前播放位置,当前播放的音乐),就是说,不论界面执行的时那个动作,这些返回的数据是一致的,方便界面统一做处理。而sendBroadcastToActivity则封装了发送给界面的广播。

所有用到的常量都封装在Contants.java中,此篇就介绍到这里,这些所有的铺垫做完后,下一篇正式开始现实逻辑业务,界面和服务项目通信传递数据并处理。

以上是关于本地音乐播放器——界面和服务的初始化的主要内容,如果未能解决你的问题,请参考以下文章

微信公众号文章音乐自动播放

Android使用FFmpeg播放视频(二):音频播放

qq音乐网络异常获取音频失败怎么办

iOS开发拓展篇—音频处理(音乐播放器2)

iOS音频播放之AudioQueue:播放本地音乐

iOS音频播放之AudioQueue:播放本地音乐