通过service的使用完成简单的音乐播放器

Demo需求:简单的音乐播放器,上一曲下一曲的切换,用户拖拽进度条调节音乐播放进度,歌曲信息的获取和歌曲进度的时间刷新等等

开发工具:Android studio

效果图:

通过service的使用完成简单的音乐播放器_第1张图片

布局:




    

首先是歌曲列表,使用listview完成

package com.example.leaven.demo;

import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.provider.MediaStore.Audio.Media;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private AudiolistAdapter adapter;

    public static final int MSG_POSITION = 0;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_POSITION:
                    initdata();
                    break;
            }
        }
    };

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

    private void initview() {
        ListView listview = (ListView) findViewById(R.id.listview);
        adapter = new AudiolistAdapter(this,null);
        listview.setAdapter(adapter);
        listview.setOnItemClickListener(new OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView parent, View view, int position, long id) {
                Cursor cursor = (Cursor) adapter.getItem(position);
                ArrayList audioItems = AudioItem.parseListFromCursor(cursor);
                //跳转到播放界面
                Intent intent = new Intent(getApplicationContext(),AudioPlayActivity.class);
                intent.putExtra("audioItems",audioItems);
                intent.putExtra("position",position);
                startActivity(intent);
            }
        });

    }
}
listview的adapter代码:
package com.example.leaven.demo;

import android.content.Context;
import android.database.Cursor;
import android.provider.MediaStore.Audio.Media;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import android.widget.TextView;

/**
 * Created by leaven on 2016/12/23.
 */
public class AudiolistAdapter extends CursorAdapter {
    public AudiolistAdapter(Context context, Cursor c) {
        super(context, c);
    }

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) {
        View view = View.inflate(context, R.layout.audiolist_item, null);
        ViewHolder Holder = new ViewHolder();
        Holder.tv_title = (TextView) view.findViewById(R.id.audiolist_item_tv_title);
        Holder.tv_artist = (TextView) view.findViewById(R.id.audiolist_item_tv_artist);
        view.setTag(Holder);
        return view;
    }

    @Override
    public void bindView(View view, Context context, Cursor cursor) {
        ViewHolder holder = (ViewHolder) view.getTag();
        holder.tv_title.setText(cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME)));
        holder.tv_artist.setText(cursor.getString(cursor.getColumnIndex(Media.ARTIST)));
    }

    private class ViewHolder{
        TextView tv_title,tv_artist;
    }
}
歌曲列表以及播放界面都需要显示歌曲信息,歌曲信息的获取

package com.example.leaven.demo;

import android.database.Cursor;
import android.provider.MediaStore.Audio.Media;

import java.io.Serializable;
import java.util.ArrayList;

/**
 * Created by Ding on 2016/12/3.
 */
public class AudioItem implements Serializable {

    private String title;
    private String path;
    private String artist;


    // 解析 cursor 当前行的数据,生成一个对象
    public static AudioItem parseFromCursor(Cursor cursor) {
        // 健壮性检查
        if (cursor == null || cursor.getCount() == 0) {
            return null;
        }

        AudioItem videoItem = new AudioItem();
        videoItem.title = cursor.getString(cursor.getColumnIndex(Media.DISPLAY_NAME));
//        videoItem.title = StringUtils.formatDispayName(videoItem.title);
        videoItem.path = cursor.getString(cursor.getColumnIndex(Media.DATA));
        videoItem.artist = cursor.getString(cursor.getColumnIndex(Media.ARTIST));

        return videoItem;
    }

    /**
     * 从 cursor 里解析出完整的播放列表
     *
     * @param cursor
     * @return
     */
    public static ArrayList parseListFromCursor(Cursor cursor) {
        // 健壮性检查
        if (cursor == null || cursor.getCount() == 0) {
            return null;
        }

        // 遍历所有行,解析数据
        ArrayList videoItems = new ArrayList<>();
        cursor.moveToPosition(-1);// 解析之前要将游标移动到第一行之前
        while (cursor.moveToNext()) {
            AudioItem videoItem = parseFromCursor(cursor);
            videoItems.add(videoItem);
        }

        return videoItems;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public String getArtist() {
        return artist;
    }

    public void setArtist(String artist) {
        this.artist = artist;
    }

    @Override
    public String toString() {
        return "AudioItem{" +
                "title='" + title + '\'' +
                ", path='" + path + '\'' +
                ", artist='" + artist + '\'' +
                '}';
    }
}

listview的布局代码完成后便是音乐播放器界面的跳转代码

package com.example.leaven.demo;

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.annotation.NonNull;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;

import com.example.leaven.demo.service.AudioPlayerService;

import java.util.ArrayList;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class AudioPlayActivity extends AppCompatActivity {

    @BindView(R.id.audioplayer_tv_position)
    TextView audioplayerTvPosition;
    @BindView(R.id.audioplayer_sk_position)
    SeekBar audioplayerSkPosition;
    @BindView(R.id.audioplayer_iv_pre)
    Button audioplayerIvPre;
    @BindView(R.id.audioplayer_iv_pause)
    Button audioplayerIvPause;
    @BindView(R.id.audioplayer_iv_next)
    Button audioplayerIvNext;
    @BindView(R.id.audioplayer_tv_title)
    TextView audioplayerTvTitle;

    public static final int MSG_POSITION = 0;
    private ServiceConnection conn;
    private AudioPlayerService.AudioBinder mAudioBinder;
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what){
                case MSG_POSITION:
                    startupdate();
                    break;
            }
        }
    };
    private ArrayList audioItems;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_audio_player);
        ButterKnife.bind(this);
        initdata();
        initlistener();
    }

    private void initlistener() {
        audioplayerSkPosition.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (!fromUser) return;
                mAudioBinder.seekto(progress);
            }

            @Override
            public void onStartTrackingTouch(SeekBar seekBar) {

            }

            @Override
            public void onStopTrackingTouch(SeekBar seekBar) {

            }
        });
    }

    private void initdata() {

        // 开启后台播放服务
        Intent intent = new Intent(getIntent());// 复制当前 Activity 的启动意图
        intent.setClass(this, AudioPlayerService.class);
        startService(intent);// 退出当前界面后,音乐服务还是要继续存活
        conn = Audioplaycoon();
        bindService(intent, conn,BIND_AUTO_CREATE);
//        Log.e(TAG,"gettitle"+mAudioBinder.audioItem.getTitle());
        audioItems = (ArrayList) intent.getSerializableExtra("audioItems");
        int position = intent.getIntExtra("position", -1);
        audioplayerTvTitle.setText(audioItems.get(position).getTitle());
    }

    private void startupdate() {
        int getduration = mAudioBinder.getduration();
        int currentPosition = mAudioBinder.getCurrentPosition();
        String s1 = StringUtils.formatDuration(getduration);
        String s2 = StringUtils.formatDuration(currentPosition);
        audioplayerTvPosition.setText(s2+"/"+s1);
        audioplayerSkPosition.setMax(getduration);
        audioplayerSkPosition.setProgress(currentPosition);

        handler.sendEmptyMessageDelayed(MSG_POSITION,500);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        unbindService(conn);
        handler.removeCallbacksAndMessages(null);
    }

    @OnClick({R.id.audioplayer_tv_position, R.id.audioplayer_sk_position, R.id.audioplayer_iv_pre, R.id.audioplayer_iv_pause, R.id.audioplayer_iv_next})
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.audioplayer_tv_position:
                break;
            case R.id.audioplayer_sk_position:
                break;
            case R.id.audioplayer_iv_pre:
                mAudioBinder.playpre();
                audioplayerTvTitle.setText(audioItems.get(mAudioBinder.playpre()).getTitle());
                break;
            case R.id.audioplayer_iv_pause:
                mAudioBinder.swichpausestate();
                break;
            case R.id.audioplayer_iv_next:
                mAudioBinder.playnext();
                audioplayerTvTitle.setText(audioItems.get(mAudioBinder.playnext()).getTitle());
                break;
        }
    }

    @NonNull
    private ServiceConnection Audioplaycoon() {
        return new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                mAudioBinder = (AudioPlayerService.AudioBinder) service;
                //更新播放进度
                startupdate();
            }

            @Override
            public void onServiceDisconnected(ComponentName name) {

            }
        };
    }
}
这里使用到service,通过Ibinder绑定,在服务中完成上一曲下一曲以及暂停等功能的实现,其中service的具体代码为:

package com.example.leaven.demo.service;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.Toast;

import com.example.leaven.demo.AudioItem;

import java.util.ArrayList;

/**
 * Created by Ding on 2016/12/6.
 */
public class AudioPlayerService extends Service {

    private AudioBinder mAudioBinder;
    private ArrayList audioItems;
    private int position;

    @Override
    public void onCreate() {
        super.onCreate();
        mAudioBinder = new AudioBinder();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return mAudioBinder;
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        audioItems = (ArrayList) intent.getSerializableExtra("audioItems");
        position = intent.getIntExtra("position", -1);
        mAudioBinder.playitem();
        return super.onStartCommand(intent, flags, startId);
    }

    public class AudioBinder extends Binder {

        private MediaPlayer mediaPlayer;

        //播放当前歌曲
        public void playitem(){
            // 播放音乐
            AudioItem audioItem = audioItems.get(position);

            try {
                if (mediaPlayer!=null){
                    mediaPlayer.reset();
                }else {
                    mediaPlayer = new MediaPlayer();
                }
                // 设置文件路径
                mediaPlayer.setDataSource(audioItem.getPath());
                // 加载资源
                mediaPlayer.prepare();

                mediaPlayer.start();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        //播放状态的选择
        public void swichpausestate(){
            if (mediaPlayer.isPlaying()){
                mediaPlayer.pause();
            }else {
                mediaPlayer.start();
            }
        }

        //当前音频总时长
        public int getduration(){
            return mediaPlayer.getDuration();
        }

        //当前音频当前时长
        public int getCurrentPosition(){
            return mediaPlayer.getCurrentPosition();
        }

        //更新进度条
        public void seekto(int msec){
            mediaPlayer.seekTo(msec);
        }

        //上一个
        public int playpre(){
            if (position!=0){
                position--;
                playitem();
            }else {
                Toast.makeText(getApplicationContext(),"已经是第一个了",Toast.LENGTH_SHORT).show();
            }
            return position;
        }

        //下一个
        public int playnext(){
            if (position!=audioItems.size()-1){
                position++;
                playitem();
            }else {
                Toast.makeText(getApplicationContext(),"已经是最后一个了",Toast.LENGTH_SHORT).show();
            }
            return position;
        }
    }
}
当中的stringUtils是自己写的歌曲时长工具类,返回值为根据歌曲时间更改拼接的字符串,具体代码为
package com.example.leaven.demo;

import android.text.format.DateFormat;

import java.util.Calendar;

/**
 * Created by Ding on 2016/12/3.
 */
public class StringUtils {
    private static final String TAG = "itcast_StringUtils";

    /**
    * 将视频时长转换为 字符串,--》 00:01 或者 01:02:03
     */
    public static String formatDuration(int duration){
        Calendar calendar = Calendar.getInstance();
        calendar.clear();
        calendar.add(Calendar.MILLISECOND,duration);

        int hour = calendar.get(Calendar.HOUR);
//        int min = calendar.get(Calendar.MINUTE);
//        int sec = calendar.get(Calendar.SECOND);
//        LogUtils.e(TAG,"StringUtils.formatDuration,hour="+hour+":min="+":sec="+sec);

        if (hour==0){
            return (String) DateFormat.format("mm:ss",calendar);
        }else{
            return (String) DateFormat.format("hh:mm:ss",calendar);
        }
    }

    /**
     * 格式化系统时间为 01:02:03
     * @return
     */
    public static String formatSystemTime(){
        return (String) DateFormat.format("hh:mm:ss",System.currentTimeMillis());
    }

    /**
     * dida.mp3 -- > dida
     * @param displayName
     * @return
     */
    public static String formatDispayName(String displayName){
        return displayName.substring(0,displayName.indexOf("."));
    }
}

整体Demo的代码就是这样,其中歌曲信息的获取为借鉴网络,其他纯手写


你可能感兴趣的:(Android开发)