Demo需求:简单的音乐播放器,上一曲下一曲的切换,用户拖拽进度条调节音乐播放进度,歌曲信息的获取和歌曲进度的时间刷新等等
开发工具:Android studio
效果图:
布局:
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("."));
}
}