Android Studio Beginner Example: Music Player and Service Learning

A simple music player implemented in a case this time

The most important points of knowledge used are: Service, handler (realize music playback progress bar update and picture rotation) and MediaPlayer for playing audio

Take a look at the case effect:

 Since Service is one of the four major components of Android, an important knowledge point of Activity, Service, etc. is the issue of life cycle. The following pictures are borrowed from W3Cschool

The diagram describes the life cycle of starting Service through startService and bindService respectively.

It can be seen that no matter which method is used, the onCreate and onDesroy methods in the life cycle must be called. Here is a brief explanation of the main difference between using startService and bindService to start the Service: startService has no necessary connection with its caller, that is Say that when the caller ends its own life cycle, but as long as stopService is not called, the Service will continue to run ; bindService is on the same boat

And the bindService used in this case

 

take a look first

Main interface

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/beij"
    android:gravity="center"
    android:orientation="vertical">
    <ImageView
        android:id="@+id/iv_music"
        android:layout_width="240dp"
        android:layout_height="240dp"
        android:layout_gravity="center_horizontal"
        android:layout_margin="15dp"
        android:src="@drawable/musics" />

    <SeekBar
        android:id="@+id/sb"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:thumb="@drawable/iconbiao"
        android:layout_marginTop="74dp" />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:paddingLeft="8dp"
        android:paddingRight="8dp">
        <TextView
            android:id="@+id/tv_progress"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="00:00" />
        <TextView
            android:id="@+id/tv_total"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentRight="true"
            android:text="00:00" />
    </RelativeLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">
        <Button
            android:id="@+id/btn_play"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="8dp"
            android:layout_weight="1"
            android:background="@drawable/btn_bg_selector"
            android:text="播放音乐" />
        <Button
            android:id="@+id/btn_pause"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="8dp"
            android:layout_weight="1"
            android:background="@drawable/btn_bg_selector"
            android:text="暂停播放" />
        <Button
            android:id="@+id/btn_continue_play"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="8dp"
            android:layout_weight="1"
            android:background="@drawable/btn_bg_selector"
            android:text="继续播放" />
        <Button
            android:id="@+id/btn_exit"
            android:layout_width="0dp"
            android:layout_height="40dp"
            android:layout_margin="8dp"
            android:layout_weight="1"
            android:background="@drawable/btn_bg_selector"
            android:text="退出" />
    </LinearLayout>
</LinearLayout>

Followed by the Activity code

import android.animation.ObjectAnimator;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;

import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.animation.LinearInterpolator;
import android.widget.ImageView;
import android.widget.SeekBar;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity implements View.OnClickListener
{
    private static SeekBar sb;
    private static TextView tv_progress, tv_total;
    private ObjectAnimator animator;
    private MusicService.MusicControl musicControl;
    MyServiceConn conn;
    Intent intent;
    private boolean isUnbind = false;//记录服务是否被解绑
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        init();
    }
    private void init() {
        tv_progress = (TextView) findViewById(R.id.tv_progress);
        tv_total = (TextView) findViewById(R.id.tv_total);
        sb = (SeekBar) findViewById(R.id.sb);
        findViewById(R.id.btn_play).setOnClickListener(this);
        findViewById(R.id.btn_pause).setOnClickListener(this);
        findViewById(R.id.btn_continue_play).setOnClickListener(this);
        findViewById(R.id.btn_exit).setOnClickListener(this);
        intent = new Intent(this, MusicService.class);//创建意图对象
        conn = new MyServiceConn();//创建服务连接对象
        bindService(intent, conn, BIND_AUTO_CREATE);  //绑定服务
        Log.i("MusicService","使用了bindService进行绑定服务");
        //为滑动条添加事件监听
        sb.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();//获取seekBar的进度
                musicControl.seekTo(progress);         //改变播放进度
            }
        });
        ImageView iv_music = (ImageView) findViewById(R.id.iv_music);
        animator = ObjectAnimator.ofFloat(iv_music, "rotation", 0f, 360.0f);
        animator.setDuration(10000);  //动画旋转一周的时间为10秒
        animator.setInterpolator(new LinearInterpolator());
        animator.setRepeatCount(-1);  //-1表示设置动画无限循环
    }
    public static Handler handler = new Handler() {//创建消息处理器对象
        //在主线程中处理从子线程发送过来的消息
        @Override
        public void handleMessage(Message msg) {
            Bundle bundle = msg.getData(); //获取从子线程发送过来的音乐播放进度
            int duration = bundle.getInt("duration");                  //歌曲的总时长
            int currentPostition = bundle.getInt("currentPosition");//歌曲当前进度
            sb.setMax(duration);                //设置SeekBar的最大值为歌曲总时长
            sb.setProgress(currentPostition);//设置SeekBar当前的进度位置
            //歌曲的总时长
            int minute = duration / 1000 / 60;
            int second = duration / 1000 % 60;
            String strMinute = null;
            String strSecond = null;
            if (minute < 10) {              //如果歌曲的时间中的分钟小于10
                strMinute = "0" + minute; //在分钟的前面加一个0
            } else {
                strMinute = minute + "";
            }
            if (second < 10) {             //如果歌曲的时间中的秒钟小于10
                strSecond = "0" + second;//在秒钟前面加一个0
            } else {
                strSecond = second + "";
            }
            tv_total.setText(strMinute + ":" + strSecond);
            //歌曲当前播放时长
            minute = currentPostition / 1000 / 60;
            second = currentPostition / 1000 % 60;
            if (minute < 10) {             //如果歌曲的时间中的分钟小于10
                strMinute = "0" + minute;//在分钟的前面加一个0
            } else {
                strMinute = minute + "";
            }
            if (second < 10) {               //如果歌曲的时间中的秒钟小于10
                strSecond = "0" + second;  //在秒钟前面加一个0
            } else {
                strSecond = second + "";
            }
            tv_progress.setText(strMinute + ":" + strSecond);
        }
    };
    class MyServiceConn implements ServiceConnection { //用于实现连接服务
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            musicControl = (MusicService.MusicControl) service;
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    }
    private void unbind(boolean isUnbind){
        if(!isUnbind){                  //判断服务是否被解绑
            musicControl.pausePlay();//暂停播放音乐
            unbindService(conn);      //解绑服务
            Log.i("MusicService","使用了unbindService进行解绑");
        }
    }
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn_play:                //播放按钮点击事件
                musicControl.play();           //播放音乐
                animator.start();               //播放动画
                break;
            case R.id.btn_pause:               //暂停按钮点击事件
                musicControl.pausePlay();     //暂停播放音乐
                animator.pause();              //暂停播放动画
                break;
            case R.id.btn_continue_play:     //继续播放按钮点击事件
                musicControl.continuePlay(); //继续播放音乐
                animator.start();              //播放动画
                break;
            case R.id.btn_exit:                //退出按钮点击事件
                unbind(isUnbind);               //解绑服务绑定
                Log.i("MusicService","使用了unbind进行解绑");
                isUnbind = true;                //完成解绑服务
                finish();                         //关闭音乐播放界面
                break;
        }
    }
    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbind(isUnbind); //解绑服务
        Log.i("MusicService","使用了unbind进行解绑");
    }
}

 Then there is the most important Service component

 and the code

public class MusicService extends Service {
    private MediaPlayer player;
    private Timer timer;
    public MusicService() {}

    @Override
    public boolean onUnbind(Intent intent) {
        Log.i("MusicService","我是onUnbind方法");
        return super.onUnbind(intent);
    }

    @Override
    public IBinder onBind(Intent intent) {
        Log.i("MusicService","我是onBind方法");
        return new MusicControl();
    }
    @Override
    public void onCreate() {
        Log.i("MusicService","我是onCreate方法");
        super.onCreate();
        player = new MediaPlayer();//创建音乐播放器对象
    }
    public void addTimer() {        //添加计时器用于设置音乐播放器中的播放进度条
        if (timer == null) {
            timer = new Timer();     //创建计时器对象
            TimerTask task = new TimerTask() {
                @Override
                public void run() {
                    if (player == null) return;
                    int duration = player.getDuration();                //获取歌曲总时长
                    int currentPosition = player.getCurrentPosition();//获取播放进度
                    Message msg = MainActivity.handler.obtainMessage();//创建消息对象
                    //将音乐的总时长和播放进度封装至消息对象中
                    Bundle bundle = new Bundle();
                    bundle.putInt("duration", duration);
                    bundle.putInt("currentPosition", currentPosition);
                    msg.setData(bundle);
                    //将消息发送到主线程的消息队列
                    MainActivity.handler.sendMessage(msg);
                }
            };
            //开始计时任务后的5毫秒,第一次执行task任务,以后每500毫秒执行一次
            timer.schedule(task, 5, 500);
        }
    }
    class MusicControl extends Binder {
        public void play() {
            try {
                player.reset();//重置音乐播放器
                //加载多媒体文件
                player = MediaPlayer.create(getApplicationContext(), R.raw.music);
                player.start();//播放音乐
                addTimer();     //添加计时器
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        public void pausePlay() {
            player.pause();//暂停播放音乐
        }
        public void continuePlay() {
            player.start();//继续播放音乐
        }
        public void seekTo(int progress) {
            player.seekTo(progress);//设置音乐的播放位置
        }
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.i("MusicService","我是onDestroy方法");
        if (player == null) return;
        if (player.isPlaying()) player.stop();//停止播放音乐
        player.release();//释放占用的资源
        player = null;//将player置为空
    }
}

Guess you like

Origin blog.csdn.net/m0_59558544/article/details/131081336