运用Service服务通信制作音乐播放器

先看一下效果图:

图片是可以旋转的,有进度条、计时时间、播放、暂停、退出等功能
在这里插入图片描述

界面布局

音频文件一般存放在res/raw文件夹,raw文件夹中的文件会被映射到R.java文件中,访问文件是直接使用资源id,如R.raw.music

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
	xmlns:tools="http://schemas.android.com/tools"
	android:layout_width="match_parent"
	android:layout_height="match_parent"
	 tools:context=".MainActivity">

<ImageView
    android:id="@+id/music"
    android:layout_width="240dp"
    android:layout_height="240dp"
    android:layout_centerHorizontal="true"
    android:layout_marginBottom="10dp"
    android:src="@drawable/music" />

<TextView
    android:id="@+id/tvCurrent"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/music"
    android:layout_marginLeft="15dp"
    android:text="00:00"
    android:textSize="24sp" />

<TextView
    android:id="@+id/tvFinal"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_below="@id/music"
    android:layout_alignParentRight="true"
    android:layout_marginRight="15dp"
    android:text="00:00"
    android:textSize="24sp" />

<SeekBar
    android:id="@+id/seekbar"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/tvCurrent" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_below="@id/seekbar"
    android:layout_marginTop="20dp">

    <Button
        android:id="@+id/play"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="播放" />

    <Button
        android:id="@+id/pause"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="暂停播放" />

    <Button
        android:id="@+id/continuePlay"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="继续播放" />

    <Button
        android:id="@+id/exit"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:text="退出" />
</LinearLayout>
</RelativeLayout>

创建MusicService服务,音乐的加载、播放、暂停以及进度条的更新这些耗时操作,一般在Service中处理

package com.fangkuai.musicplayer;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;

import androidx.annotation.Nullable;

import java.util.Timer;
import java.util.TimerTask;

public class MusicService extends Service {
	  private MediaPlayer player;
 	private Timer timer;
	@Nullable
	@Override
public IBinder onBind(Intent intent) {
    return new MusicController();
}

@Override
public void onCreate() {
    super.onCreate();
    player=new MediaPlayer();
}

@Override
public void onDestroy() {
    super.onDestroy();
    if (player==null)return;
    if (player.isPlaying())player.pause();
    player.release();
    player=null;
}
class MusicController extends Binder{
    public void play(){
        player.reset();             //重置MediaPlayer,从头播放
        //导入音频资源
        player=MediaPlayer.create(getApplicationContext(),R.raw.summertime);
        player.start();
        addTimer();
    }
    public void pause(){
        player.pause();
    }
    public void continuePlayer(){
        player.start();
    }
    public void seekTo(int progress){
        player.seekTo(progress);
    }
}
//添加计时器
private void addTimer() {
    if (timer==null){
        timer=new Timer();
        TimerTask task=new TimerTask() {
            @Override
            public void run() {
                //获取播放时长、播放位置
                int duration=player.getDuration();
                int currentposition=player.getCurrentPosition();
                Message message=MainActivity.handler.obtainMessage();
                //将消息封装在Bunndle中发送到消息队列
                Bundle bundle=new Bundle();
                bundle.putInt("duration",duration);
                bundle.putInt("currentposition",currentposition);
                message.setData(bundle);
                MainActivity.handler.sendMessage(message);
            }
        };
        //开启计时器,0.005s后开始,每0.5s执行一次
        timer.schedule(task,5,500);
    }
}
}

界面交互代码

package com.fangkuai.musicplayer;

import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements
 View.OnClickListener {


private ImageView music;
private static TextView tvCurrent;
private static TextView tvFinal;
private static SeekBar seekbar;
private Button play;
private Button pause;
private Button continuePlay;
private Button exit;
private ObjectAnimator animator;
private MusicService.MusicController musicController;
private MyConn conn;
private Intent intent;
private boolean isUnbind=false;



@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    initView();

}


	//在主线程中处理子线程发来的消息
static Handler handler = new Handler() {
    @Override
    public void handleMessage(@NonNull Message msg) {
        Bundle bundle=new Bundle();
        bundle=msg.getData();
        int duration=bundle.getInt("duration");
        int currentposition=bundle.getInt("currentposition");
        //给进度条设置总长度、当前位置进度
        seekbar.setMax(duration);
        seekbar.setProgress(currentposition);
        //将时间转换成00:00的String格式添加到组件
        int minute=duration/1000/60;
        int second=duration/1000%60;
        String strMinute=null;
        String strSecond=null;
        if (minute<10){
            strMinute="0"+minute;
        }else {
            strMinute=minute+"";
        } if (second<10){
            strSecond="0"+second;
        }else {
            strSecond=second+"";
        }
        tvFinal.setText(strMinute+":"+strSecond);
        minute=currentposition/1000/60;
        second=currentposition/1000%60;
        if (minute<10){
            strMinute="0"+minute;
        }else {
            strMinute=minute+"";
        } if (second<10){
            strSecond="0"+second;
        }else {
            strSecond=second+"";
        }
        tvCurrent.setText(strMinute+":"+strSecond);

    }
};


private void initView() {
    music = (ImageView) findViewById(R.id.music);
    tvCurrent = (TextView) findViewById(R.id.tvCurrent);
    tvFinal = (TextView) findViewById(R.id.tvFinal);
    seekbar = (SeekBar) findViewById(R.id.seekbar);
    play = (Button) findViewById(R.id.play);
    pause = (Button) findViewById(R.id.pause);
    continuePlay = (Button) findViewById(R.id.continuePlay);
    exit = (Button) findViewById(R.id.exit);


    conn=new MyConn();
    intent=new Intent(MainActivity.this, MusicService.class);
    bindService(intent,conn,BIND_AUTO_CREATE);
    seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
    	//滑动进度条时调用
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
        //滑动到末端,停止播放动画
            if (progress==seekBar.getMax()){
                animator.pause();
            }
        }

        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {

        }
            //停止移动时触发
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        //根据拖动进度条改变音乐播放进度
            int progress=seekBar.getProgress();
            musicController.seekTo(progress);
        }
    });
    animator=ObjectAnimator.ofFloat(music,"rotation",0f,360.0f);
    animator.setDuration(10000);
    animator.setInterpolator(new LinearInterpolator());
    animator.setRepeatCount(-1);            //设置为无限循环
    play.setOnClickListener(this);
    pause.setOnClickListener(this);
    continuePlay.setOnClickListener(this);
    exit.setOnClickListener(this);
}

@Override
public void onClick(View v) {
    switch (v.getId()) {
        case R.id.play:
            animator.start();
            musicController.play();
            break;
        case R.id.pause:
            animator.pause();
            musicController.pause();
            break;
        case R.id.continuePlay:
            animator.start();
            musicController.continuePlayer();
            break;
        case R.id.exit:
            unbind(isUnbind);
            isUnbind=true;
            finish();
            break;
    }
}
class MyConn implements ServiceConnection{

    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        musicController= (MusicService.MusicController) service;
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {

    }

}
private void unbind(boolean isUnbind){
    if (!isUnbind){
        musicController.pause();
        unbindService(conn);
        stopService(intent);
    }
}
@Override
protected void onDestroy() {
    super.onDestroy();
    unbind(isUnbind);
}
	}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值