本地音乐播放器(三)
2016-05-09 18:50
507 查看
mainActivity (ui)代码!
package cn.tedu.music_player_3.ui;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import cn.tedu.music_player_3.R;
import cn.tedu.music_player_3.adapter.MusicAdapter;
import cn.tedu.music_player_3.app.MusicPlayerApplication;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.service.PlayMusicService;
import cn.tedu.music_player_3.util.CommonUtils;
import cn.tedu.music_player_3.util.Consts;
public class MainActivity extends Activity
implements Consts, OnClickListener, OnItemClickListener, OnSeekBarChangeListener {
/**
* ImageButton:播放/暂停
*/
private ImageButton ibPlayOrPause;
/**
* ImageButton:下一首
*/
private ImageButton ibNext;
/**
* ImageButton:上一首
*/
private ImageButton ibPrevious;
/**
* TextView:当前播放的歌曲的标题
*/
private TextView tvMusicTitle;
/**
* TextView:当前播放的歌曲的时长
*/
private TextView tvMusicDuration;
/**
* SeekBar:当前播放进度
*/
private SeekBar sbMusicProgress;
/**
* TextView:当前播放到的时间
*/
private TextView tvMusicCurrentPosition;
/**
* ListView:歌曲列表控件
*/
private ListView lvMusics;
/**
* Application
*/
private MusicPlayerApplication app;
/**
* 数据
*/
private List musics;
/**
* MusicAdapter
*/
private MusicAdapter musicAdapter;
/**
* 广播接收者
*/
private BroadcastReceiver receiver;
/**
* 当前播放的歌曲的索引
*/
private int currentMusicIndex;
/**
* 是否正在拖进度条
*/
private boolean isTrackingTouch;
}
自定义Baseadater代码;
package cn.tedu.music_player_3.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
public abstract class BaseAdapter
extends android.widget.BaseAdapter {
private Context context;
private List data;
private LayoutInflater inflater;
}
Musciadapter 代码!
package cn.tedu.music_player_3.adapter;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import cn.tedu.music_player_3.R;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.util.CommonUtils;
public class MusicAdapter extends BaseAdapter {
}
MusicAplayerAppliction 代码:
package cn.tedu.music_player_3.adapter;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import cn.tedu.music_player_3.R;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.util.CommonUtils;
public class MusicAdapter extends BaseAdapter {
}
IDao 代码;
package cn.tedu.music_player_3.dal;
import java.util.List;
public interface IDao {
/**
* 获取数据
*
* @return 数据的List集合
*/
List getData();
}
MediaStoreMusicDao 类代码
package cn.tedu.music_player_3.dal;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import cn.tedu.music_player_3.entity.Music;
class MediaStoreMusicDao implements IDao {
private Context context;
}
MusicDaoFactory 类
package cn.tedu.music_player_3.dal;
import android.content.Context;
import cn.tedu.music_player_3.entity.Music;
public class MusicDaoFactory {
private MusicDaoFactory() {
super();
}
}
SDCardMusicDao类代码:
package cn.tedu.music_player_3.dal;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.os.Environment;
import android.util.Log;
import cn.tedu.music_player_3.entity.Music;
/**
* 歌曲数据的访问类
* @author chengheng
* @version 2.0
*/
public class SDCardMusicDao implements IDao {
/**
* 扫描sdcard中Music下所有.mp3文件
* @return 扫描到的Music对象的List集合,该返回值永不为null
*/
@Override
public List getData() {
// 准备返回值
List musics = new ArrayList();
}
实体类 Music 代码:
package cn.tedu.music_player_3.entity;
public class Music {
}
PlayMusicService 类代码:
package cn.tedu.music_player_3.service;
import java.io.IOException;
import java.util.List;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.IBinder;
import cn.tedu.music_player_3.app.MusicPlayerApplication;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.util.Consts;
public class PlayMusicService extends Service implements Consts {
/**
* 广播接收者
*/
private BroadcastReceiver receiver;
/**
* MediaPlayer
*/
private MediaPlayer player;
/**
* 歌曲数据的List集合
*/
private List musics;
/**
* Application
*/
private MusicPlayerApplication app;
/**
* 当前播放的歌曲的索引
*/
private int currentMusicIndex;
/**
* 暂停时的播放位置
*/
private int pausePosition;
/**
* Intent:用于表示广播中发送的信息
*/
private Intent broadcastIntent = new Intent();
/**
* 更新进度的线程
*/
private UpdateProgressThread updateProgressThread;
}
工具类 CommonUtils代码
package cn.tedu.music_player_3.util;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Locale;
/**
* 通用工具类
*/
public class CommonUtils {
/**
* 格式化时间的工具
*/
private static SimpleDateFormat sdf = new SimpleDateFormat(“mm:ss”, Locale.CHINA);
/**
* 被格式化的时间对象
*/
private static Date date = new Date();
}
工具类Consts代码:
package cn.tedu.music_player_3.util;
public interface Consts {
}
Activit_main.xml 代码
package cn.tedu.music_player_3.ui;
import java.util.List;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
import android.widget.TextView;
import cn.tedu.music_player_3.R;
import cn.tedu.music_player_3.adapter.MusicAdapter;
import cn.tedu.music_player_3.app.MusicPlayerApplication;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.service.PlayMusicService;
import cn.tedu.music_player_3.util.CommonUtils;
import cn.tedu.music_player_3.util.Consts;
public class MainActivity extends Activity
implements Consts, OnClickListener, OnItemClickListener, OnSeekBarChangeListener {
/**
* ImageButton:播放/暂停
*/
private ImageButton ibPlayOrPause;
/**
* ImageButton:下一首
*/
private ImageButton ibNext;
/**
* ImageButton:上一首
*/
private ImageButton ibPrevious;
/**
* TextView:当前播放的歌曲的标题
*/
private TextView tvMusicTitle;
/**
* TextView:当前播放的歌曲的时长
*/
private TextView tvMusicDuration;
/**
* SeekBar:当前播放进度
*/
private SeekBar sbMusicProgress;
/**
* TextView:当前播放到的时间
*/
private TextView tvMusicCurrentPosition;
/**
* ListView:歌曲列表控件
*/
private ListView lvMusics;
/**
* Application
*/
private MusicPlayerApplication app;
/**
* 数据
*/
private List musics;
/**
* MusicAdapter
*/
private MusicAdapter musicAdapter;
/**
* 广播接收者
*/
private BroadcastReceiver receiver;
/**
* 当前播放的歌曲的索引
*/
private int currentMusicIndex;
/**
* 是否正在拖进度条
*/
private boolean isTrackingTouch;
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 激活Service Intent intent = new Intent(this, PlayMusicService.class); startService(intent); // 初始化控件 setViews(); // 显示ListView showMusicList(); // 为控件配置监听器 setListeners(); // 注册广播接收者 regBroadcastReceiver(); } /** * 初始化控件 */ private void setViews() { lvMusics = (ListView) findViewById(R.id.lv_musics); ibPlayOrPause = (ImageButton) findViewById(R.id.ib_play_or_pause); ibPrevious = (ImageButton) findViewById(R.id.ib_previous); ibNext = (ImageButton) findViewById(R.id.ib_next); tvMusicTitle = (TextView) findViewById(R.id.tv_music_title); tvMusicDuration = (TextView) findViewById(R.id.tv_music_duration); sbMusicProgress = (SeekBar) findViewById(R.id.sb_music_progress); tvMusicCurrentPosition = (TextView) findViewById(R.id.tv_music_current_position); } /** * 显示ListView */ private void showMusicList() { app = (MusicPlayerApplication) getApplication(); musics = app.getMusics(); musicAdapter = new MusicAdapter(this, musics); lvMusics.setAdapter(musicAdapter); } /** * 配置监听器 */ private void setListeners() { ibPlayOrPause.setOnClickListener(this); ibPrevious.setOnClickListener(this); ibNext.setOnClickListener(this); lvMusics.setOnItemClickListener(this); sbMusicProgress.setOnSeekBarChangeListener(this); } /** * 注册广播接收者 */ private void regBroadcastReceiver() { receiver = new InnerReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_SET_AS_PAUSE_STATE); filter.addAction(ACTION_SET_AS_PLAY_STATE); filter.addAction(ACTION_UPDATE_PROGRESS); registerReceiver(receiver, filter); } /** * Intent:用于表示广播中发送的信息 */ private Intent broadcastIntent = new Intent(); @Override public void onClick(View v) { switch (v.getId()) { case R.id.ib_play_or_pause: // 发送广播到Service:播放或暂停 broadcastIntent.setAction(ACTION_PLAY_OR_PAUSE); sendBroadcast(broadcastIntent); break; case R.id.ib_previous: // 发送广播到Service:播放上一首 broadcastIntent.setAction(ACTION_PREVIOUS); sendBroadcast(broadcastIntent); break; case R.id.ib_next: // 发送广播到Service:播放下一首 broadcastIntent.setAction(ACTION_NEXT); sendBroadcast(broadcastIntent); break; } } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // 发送广播到Service:播放指定的歌曲 broadcastIntent.setAction(ACTION_PLAY_POSITION); broadcastIntent.putExtra(EXTRA_MUSIC_INDEX, position); sendBroadcast(broadcastIntent); } private class InnerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 获取广播中的Action String action = intent.getAction(); // 判断Action if (ACTION_SET_AS_PAUSE_STATE.equals(action)) { // -- 操作:设置为暂停状态 -- // 将按钮设置为“播放” ibPlayOrPause.setImageResource(android.R.drawable.ic_media_play); } else if (ACTION_SET_AS_PLAY_STATE.equals(action)) { // -- 操作:设置为播放状态 -- // 将按钮设置为“暂停” ibPlayOrPause.setImageResource(android.R.drawable.ic_media_pause); // 获取当前正在播放的歌曲的索引 currentMusicIndex = intent.getIntExtra(EXTRA_MUSIC_INDEX, 0); // 设置显示歌曲的标题 tvMusicTitle.setText("正在播放:" + musics.get(currentMusicIndex).getName()); // 设置显示歌曲的时长 tvMusicDuration.setText(CommonUtils.getFormattedTime(musics.get(currentMusicIndex).getDuration())); } else if (ACTION_UPDATE_PROGRESS.equals(action)) { // -- 更新进度 -- // 获取当前播放到的位置 int currentPosition = intent.getIntExtra(EXTRA_CURRENT_POSITION, 0); // 需要更新到的进度值 int progress = currentPosition * 100 / musics.get(currentMusicIndex).getDuration(); // 判断用户是否正在拖进度条,如果在拖,则不更新SeekBar if (!isTrackingTouch) { // 更新SeekBar:当前播放到的进度 sbMusicProgress.setProgress(progress); } // 更新TextView:当前播放到的时间 tvMusicCurrentPosition.setText(CommonUtils.getFormattedTime(currentPosition)); } } } @Override protected void onDestroy() { // 取消注册广播接收者 if (receiver != null) { unregisterReceiver(receiver); receiver = null; } super.onDestroy(); } @Override public void onStartTrackingTouch(SeekBar seekBar) { // 标识:开始拖进度 isTrackingTouch = true; } @Override public void onStopTrackingTouch(SeekBar seekBar) { // 标识:已停止拖进度 isTrackingTouch = false; // 发送广播到Service:从指定的进度开始播放 broadcastIntent.setAction(ACTION_PLAY_FROM_PROGRESS); broadcastIntent.putExtra(EXTRA_PROGRESS, sbMusicProgress.getProgress()); sendBroadcast(broadcastIntent); } @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { } /** * 当按下回退键时,不finish此activity,将其隐藏到后台,只有点击notification中的关闭按钮时才会关闭此activity */ @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if(keyC 4000 ode==KeyEvent.KEYCODE_BACK){ moveTaskToBack(false); return true; } return super.onKeyDown(keyCode, event); }
}
自定义Baseadater代码;
package cn.tedu.music_player_3.adapter;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
public abstract class BaseAdapter
extends android.widget.BaseAdapter {
private Context context;
private List data;
private LayoutInflater inflater;
public BaseAdapter(Context context, List<T> data) { super(); setContext(context); setData(data); setLayoutInflater(); } public void setContext(Context context) { if(context == null) { throw new IllegalArgumentException("参数Context不允许为null!!!"); } this.context = context; } public Context getContext() { return this.context; } public void setData(List<T> data) { if(data == null) { data = new ArrayList<T>(); } this.data = data; } public List<T> getData() { return this.data; } public void setLayoutInflater() { inflater = LayoutInflater.from(this.context); } public LayoutInflater getLayoutInflater() { return this.inflater; } @Override public int getCount() { return data.size(); } @Override public Object getItem(int position) { return null; } @Override public long getItemId(int position) { return 0; }
}
Musciadapter 代码!
package cn.tedu.music_player_3.adapter;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import cn.tedu.music_player_3.R;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.util.CommonUtils;
public class MusicAdapter extends BaseAdapter {
public MusicAdapter(Context context, List<Music> data) { super(context, data); } @Override public View getView(int position, View convertView, ViewGroup parent) { Music music = getData().get(position); ViewHolder holder; if(convertView == null) { convertView = getLayoutInflater().inflate(R.layout.music_item, null); holder = new ViewHolder(); holder.tvName = (TextView) convertView.findViewById(R.id.tv_music_item_name); holder.tvDuration = (TextView) convertView.findViewById(R.id.tv_music_item_duration); holder.tvArtist = (TextView) convertView.findViewById(R.id.tv_music_item_artist); holder.tvAlbum = (TextView) convertView.findViewById(R.id.tv_music_item_album); holder.ivImage = (ImageView) convertView.findViewById(R.id.iv_music_item_image); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tvName.setText(music.getName()); holder.tvArtist.setText(music.getArtist()); holder.tvAlbum.setText(music.getAlbum()); holder.tvDuration.setText(CommonUtils.getFormattedTime(music.getDuration())); if(music.getAlbumArt() == null) { holder.ivImage.setImageResource(R.drawable.ic_launcher); } else { Bitmap bm = BitmapFactory.decodeFile(music.getAlbumArt()); holder.ivImage.setImageBitmap(bm); } return convertView; } class ViewHolder { TextView tvName; TextView tvDuration; TextView tvArtist; TextView tvAlbum; ImageView ivImage; }
}
MusicAplayerAppliction 代码:
package cn.tedu.music_player_3.adapter;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import cn.tedu.music_player_3.R;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.util.CommonUtils;
public class MusicAdapter extends BaseAdapter {
public MusicAdapter(Context context, List<Music> data) { super(context, data); } @Override public View getView(int position, View convertView, ViewGroup parent) { Music music = getData().get(position); ViewHolder holder; if(convertView == null) { convertView = getLayoutInflater().inflate(R.layout.music_item, null); holder = new ViewHolder(); holder.tvName = (TextView) convertView.findViewById(R.id.tv_music_item_name); holder.tvDuration = (TextView) convertView.findViewById(R.id.tv_music_item_duration); holder.tvArtist = (TextView) convertView.findViewById(R.id.tv_music_item_artist); holder.tvAlbum = (TextView) convertView.findViewById(R.id.tv_music_item_album); holder.ivImage = (ImageView) convertView.findViewById(R.id.iv_music_item_image); convertView.setTag(holder); } else { holder = (ViewHolder) convertView.getTag(); } holder.tvName.setText(music.getName()); holder.tvArtist.setText(music.getArtist()); holder.tvAlbum.setText(music.getAlbum()); holder.tvDuration.setText(CommonUtils.getFormattedTime(music.getDuration())); if(music.getAlbumArt() == null) { holder.ivImage.setImageResource(R.drawable.ic_launcher); } else { Bitmap bm = BitmapFactory.decodeFile(music.getAlbumArt()); holder.ivImage.setImageBitmap(bm); } return convertView; } class ViewHolder { TextView tvName; TextView tvDuration; TextView tvArtist; TextView tvAlbum; ImageView ivImage; }
}
IDao 代码;
package cn.tedu.music_player_3.dal;
import java.util.List;
public interface IDao {
/**
* 获取数据
*
* @return 数据的List集合
*/
List getData();
}
MediaStoreMusicDao 类代码
package cn.tedu.music_player_3.dal;
import java.util.ArrayList;
import java.util.List;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.MediaStore;
import android.util.Log;
import cn.tedu.music_player_3.entity.Music;
class MediaStoreMusicDao implements IDao {
private Context context;
public MediaStoreMusicDao(Context context) { super(); this.context = context; } @Override public List<Music> getData() { // 1. 准备初始条件 // 1.1. 声明返回值 List<Music> musics = new ArrayList<Music>(); // 1.2. 准备ContentResolver ContentResolver cr = context.getContentResolver(); // 1.3. 准备Uri Uri uri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; // 2. 执行业务 // 2.1. 执行查询,获取Cursor String[] projection = { "_id", // 0 "title", // 1 "_data", // 2 "_size", // 3 "duration", // 4 "album", // 5 "artist", // 6 "album_artist", // 7 "album_key" // 8 }; Cursor c = cr.query(uri, projection, null, null, null); // 2.2. 遍历Cursor,读取每一首歌曲信息,创建为Music对象,并添加到List集合中 if(c != null) { if(c.moveToFirst()) { Log.i("tedu", "读取歌曲信息... ..."); for(; !c.isAfterLast(); c.moveToNext()) { Music music = new Music(); music.setId(c.getLong(0)); music.setName(c.getString(1)); music.setPath(c.getString(2)); music.setSize(c.getInt(3)); music.setDuration(c.getInt(4)); music.setAlbum(c.getString(5)); music.setArtist(c.getString(6)); music.setAlbumArtist(c.getString(7)); music.setAlbumKey(c.getString(8)); music.setAlbumArt(getAlbumArtByKey(music.getAlbumKey())); Log.d("tedu", "" + music); musics.add(music); } Log.i("tedu", "读取歌曲信息完成!"); } // 2.3. 释放相关资源 c.close(); c = null; } // 3. 返回结果 return musics; } /** * 根据album_key获取album_art * @param albumKey * @return album_art字段的值,即歌曲内置图片的路径,该返回值可能为null */ private String getAlbumArtByKey(String albumKey) { // 判断参数是否有效 if(albumKey == null) { return null; } // 声明返回值 String albumArt = null; // 准备ContentResolver ContentResolver cr = context.getContentResolver(); // 准备Uri Uri uri = MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI; // 执行查询 String[] projection = { "album_art" }; String selection = "album_key=?"; String[] selectionArgs = { albumKey }; Cursor c = cr.query(uri, projection, selection, selectionArgs, null); // 处理数据 if(c != null) { if(c.moveToFirst()) { albumArt = c.getString(0); } // 释放资源 c.close(); c = null; } // 返回 return albumArt; }
}
MusicDaoFactory 类
package cn.tedu.music_player_3.dal;
import android.content.Context;
import cn.tedu.music_player_3.entity.Music;
public class MusicDaoFactory {
private MusicDaoFactory() {
super();
}
public static IDao<Music> newInstance(Context context) { return new MediaStoreMusicDao(context); }
}
SDCardMusicDao类代码:
package cn.tedu.music_player_3.dal;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import android.os.Environment;
import android.util.Log;
import cn.tedu.music_player_3.entity.Music;
/**
* 歌曲数据的访问类
* @author chengheng
* @version 2.0
*/
public class SDCardMusicDao implements IDao {
/**
* 扫描sdcard中Music下所有.mp3文件
* @return 扫描到的Music对象的List集合,该返回值永不为null
*/
@Override
public List getData() {
// 准备返回值
List musics = new ArrayList();
// 扫描sdcard中Music下所有.mp3文件 if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) { File dir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC); if (dir.exists()) { File[] files = dir.listFiles(); if (files != null && files.length > 0) { for (int i = 0; i < files.length; i++) { if (files[i].isFile()) { if (files[i].getName().toLowerCase(Locale.CHINA).endsWith(".mp3")) { Music music = new Music(); music.setPath(files[i].getAbsolutePath()); music.setName(files[i].getName().substring(0, files[i].getName().length() - 4)); Log.v("tedu", "" + music); musics.add(music); } } } } else { Log.w("tedu", "Music文件夹下没有有效的文件!"); } } else { Log.w("tedu", "sdcard下Music文件夹不存在!无法扫描到歌曲!"); } } else { Log.w("tedu", "sdcard没有正确挂载!无法访问!"); } // 返回 return musics; }
}
实体类 Music 代码:
package cn.tedu.music_player_3.entity;
public class Music {
private long id; private String name; private String path; private int size; private int duration; private String album; private String artist; private String albumArtist; private String albumKey; private String albumArt; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public int getSize() { return size; } public void setSize(int size) { this.size = size; } public int getDuration() { return duration; } public void setDuration(int duration) { this.duration = duration; } public String getAlbum() { return album; } public void setAlbum(String album) { this.album = album; } public String getArtist() { return artist; } public void setArtist(String artist) { this.artist = artist; } public String getAlbumArtist() { return albumArtist; } public void setAlbumArtist(String albumArtist) { this.albumArtist = albumArtist; } public String getAlbumKey() { return albumKey; } public void setAlbumKey(String albumKey) { this.albumKey = albumKey; } public String getAlbumArt() { return albumArt; } public void setAlbumArt(String albumArt) { this.albumArt = albumArt; } @Override public String toString() { return "Music [id=" + id + ", name=" + name + ", path=" + path + ", size=" + size + ", duration=" + duration + ", album=" + album + ", artist=" + artist + ", albumArtist=" + albumArtist + ", albumKey=" + albumKey + ", albumArt=" + albumArt + "]"; }
}
PlayMusicService 类代码:
package cn.tedu.music_player_3.service;
import java.io.IOException;
import java.util.List;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.IBinder;
import cn.tedu.music_player_3.app.MusicPlayerApplication;
import cn.tedu.music_player_3.entity.Music;
import cn.tedu.music_player_3.util.Consts;
public class PlayMusicService extends Service implements Consts {
/**
* 广播接收者
*/
private BroadcastReceiver receiver;
/**
* MediaPlayer
*/
private MediaPlayer player;
/**
* 歌曲数据的List集合
*/
private List musics;
/**
* Application
*/
private MusicPlayerApplication app;
/**
* 当前播放的歌曲的索引
*/
private int currentMusicIndex;
/**
* 暂停时的播放位置
*/
private int pausePosition;
/**
* Intent:用于表示广播中发送的信息
*/
private Intent broadcastIntent = new Intent();
/**
* 更新进度的线程
*/
private UpdateProgressThread updateProgressThread;
@Override public void onCreate() { // 获取歌曲数据 app = (MusicPlayerApplication) getApplication(); musics = app.getMusics(); // 初始化播放器 player = new MediaPlayer(); // 为MediaPlayer配置监听器 player.setOnCompletionListener(new OnCompletionListener() { @Override public void onCompletion(MediaPlayer mp) { next(); } }); // 注册广播接收者 receiver = new InnerReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_PLAY_OR_PAUSE); filter.addAction(ACTION_PREVIOUS); filter.addAction(ACTION_NEXT); filter.addAction(ACTION_PLAY_POSITION); filter.addAction(ACTION_PLAY_FROM_PROGRESS); registerReceiver(receiver, filter); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // 设置当前Service为非粘性的 return START_NOT_STICKY; } d5e7 @Override public void onDestroy() { // 解除注册广播接收者 if (receiver != null) { unregisterReceiver(receiver); receiver = null; } // 停止线程 stopUpdateProgressThread(); // 释放播放器资源 if (player != null) { player.release(); player = null; } } /** * 开启更新进度(发送广播让Activity更新)的线程 */ private void startUpdateProgressThread() { if (updateProgressThread == null) { updateProgressThread = new UpdateProgressThread(); updateProgressThread.setRunning(true); updateProgressThread.start(); } } /** * 停止更新进度(发送广播让Activity更新)的线程 */ private void stopUpdateProgressThread() { if (updateProgressThread != null) { updateProgressThread.setRunning(false); updateProgressThread = null; } } private class UpdateProgressThread extends Thread { private boolean isRunning; public void setRunning(boolean isRunning) { this.isRunning = isRunning; } @Override public void run() { while (isRunning) { if (player.isPlaying()) { // 发出广播:使Activity更新播放进度 broadcastIntent.setAction(ACTION_UPDATE_PROGRESS); broadcastIntent.putExtra(EXTRA_CURRENT_POSITION, player.getCurrentPosition()); sendBroadcast(broadcastIntent); } try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } private class InnerReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // 获取广播的Action String action = intent.getAction(); // 判断Action if (ACTION_PLAY_OR_PAUSE.equals(action)) { // -- 播放或暂停 -- // 判断播放状态 if (player.isPlaying()) { // 正在播放,则暂停 pause(); } else { // 没有播放,则播放 play(); } } else if (ACTION_PREVIOUS.equals(action)) { // 播放上一首 previous(); } else if (ACTION_NEXT.equals(action)) { // 播放下一首 next(); } else if (ACTION_PLAY_POSITION.equals(action)) { // 获取歌曲的position int position = intent.getIntExtra(EXTRA_MUSIC_INDEX, 0); // 播放指定的歌曲 play(position); } else if(ACTION_PLAY_FROM_PROGRESS.equals(action)) { // 获取进度 int progress = intent.getIntExtra(EXTRA_PROGRESS, 0); // 从指定的进度开始播放 playFromProgress(progress); } } } /** * 播放歌曲 */ private void play() { try { player.reset(); player.setDataSource(musics.get(currentMusicIndex).getPath()); player.prepare(); player.seekTo(pausePosition); player.start(); // 发出广播:使Activity将界面设置为播放状态 broadcastIntent.setAction(ACTION_SET_AS_PLAY_STATE); broadcastIntent.putExtra(EXTRA_MUSIC_INDEX, currentMusicIndex); sendBroadcast(broadcastIntent); // 开启线程 startUpdateProgressThread(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } /** * 播放指定的歌曲 * * @param position * 歌曲的索引位置 */ private void play(int position) { currentMusicIndex = position; pausePosition = 0; play(); } /** * 从指定的进度开始播放歌曲 * @param progress 进度值 */ private void playFromProgress(int progress) { // 设置播放的起点位置 pausePosition = musics.get(currentMusicIndex).getDuration() * progress / 100; // 播放 play(); } /** * 暂停 */ private void pause() { player.pause(); pausePosition = player.getCurrentPosition(); // 发出广播:使Activity将界面设置为暂停状态 broadcastIntent.setAction(ACTION_SET_AS_PAUSE_STATE); sendBroadcast(broadcastIntent); // 停止线程 stopUpdateProgressThread(); } /** * 播放上一首 */ private void previous() { currentMusicIndex--; if (currentMusicIndex < 0) { currentMusicIndex = musics.size() - 1; } pausePosition = 0; play(); } /** * 播放下一首 */ private void next() { currentMusicIndex++; if (currentMusicIndex >= musics.size()) { currentMusicIndex = 0; } pausePosition = 0; play(); } @Override public IBinder onBind(Intent intent) { return null; }
}
工具类 CommonUtils代码
package cn.tedu.music_player_3.util;
import java.util.Date;
import java.text.SimpleDateFormat;
import java.util.Locale;
/**
* 通用工具类
*/
public class CommonUtils {
/**
* 格式化时间的工具
*/
private static SimpleDateFormat sdf = new SimpleDateFormat(“mm:ss”, Locale.CHINA);
/**
* 被格式化的时间对象
*/
private static Date date = new Date();
/** * 获取格式化后的时间 * * @param timeMillis * 时间值,取值为从1970-1-1 0:00:00至今的毫秒数 * @return 格式化为mm:ss格式的字符串 */ public static String getFormattedTime(long timeMillis) { // 设置时间 date.setTime(timeMillis); // 返回格式化后的结果 return sdf.format(date); }
}
工具类Consts代码:
package cn.tedu.music_player_3.util;
public interface Consts {
String ACTION_PLAY_OR_PAUSE = "cn.tedu.intent.action.PLAY_OR_PAUSE"; String ACTION_PREVIOUS = "cn.tedu.intent.action.PREVIOUS"; String ACTION_NEXT = "cn.tedu.intent.action.NEXT"; String ACTION_PLAY_POSITION = "cn.tedu.intent.action.PLAY_POSITION"; String ACTION_PLAY_FROM_PROGRESS = "cn.tedu.intent.action.PLAY_FROM_PROGRESS"; String ACTION_SET_AS_PLAY_STATE = "cn.tedu.intent.action.SET_AS_PLAY_STATE"; String ACTION_SET_AS_PAUSE_STATE = "cn.tedu.intent.action.SET_AS_PAUSE_STATE"; String ACTION_UPDATE_PROGRESS = "cn.tedu.intent.action.UPDATE_PROGRESS"; /** * 歌曲的索引 */ String EXTRA_MUSIC_INDEX = "position"; /** * 当前播放到的位置 */ String EXTRA_CURRENT_POSITION = "current_position"; /** * 从多少进度开始播放 */ String EXTRA_PROGRESS = "progress";
}
Activit_main.xml 代码
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories