云代码会员 - 云代码空间
——
1. 项目名称:MyMusic,项目结构详图,如图1.1所示:
图1.1
2. 项目实现效果图,如下8图所示:
图2.1 主界面 图2.2 音乐列表元
图2.1和图2.2是布局效果,实现文件分别是activity_main.xml、list_item.xml。
图2.3 获取本地音乐信息 图2.4 歌词滚动界面
图2.3和图2.4为项目链接真机调试时初始界面,其中音乐列表和歌词滚动界的切换由控制,控件分别控制退、播放/暂停、进功能。
图2.5 播放本地音乐 图2.6 歌词滚动界面
图2.7 播放本地音乐 图2.8 歌词滚动界面
图2.5~图2.8为本地音乐播放时界面,通过点击选择要播放音乐进行播放,音乐选中效果为,当音乐被选中时,播放按钮立即切换为暂停按钮,同时顶部会显示正在播放音乐的名称和其艺术家名,点击暂停按钮或再次点击选中的音乐,当前音乐就会暂停播放,这是按钮恢复为播放按钮。
3. AndroidManifest.xml配置文件:(注意:申请SD卡权限和注册服务)
Ø 申请SD卡读写权限:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Ø 注册MainActivity,并注为主Activity:
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Ø 注册服务器MusicService:
<service android:name=".MusicService"/>
Ø 其他配置。
4. activity_main.xml音乐界面布局设计,采用了LinearLayout线性布局,使用控件有TextView、ListView、ScrollView、SeekBar、ImageButton,界面分为三板块,分别为正在播放的音乐名称和其艺术家、音乐列表/歌词滚动加界面、播放等控件。
5. list_item.xml音乐列表元,采用了RelativeLayout相对布局和LinearLayout线性布局组合的方式布局,同时使用了两个ImageButton控件和四个TextView控件,实现分为专辑图(这里为默认白音符,点歌播放时隐藏)、暂停图标(点歌播放时显示)、歌曲名称、其艺术家、歌曲时长、歌曲大小。
6. MainActivity主类:(注意事项:该项目是在真机下调试的,调试时,注意在手机的“权限管理”处找到项目软件“MyMusic”,点击打开设置打开“存储”权限,否则无法读取本地音乐)
类名 |
MainActivity |
类功能描述 |
主体类,继承了Activity |
类属性 |
rivate MusicService musicService; //声明 MusicService 对象
//用于播放模式函数 |
类实现的方法 |
//为了接受IBinder实例,必须创建一个 ServiceConnection 实例,并传给MusicService() private ServiceConnection serviceConnection = new ServiceConnection() {
//当service被绑定的时候回调该函数
//服务器断开或关闭的时候调用该方法
}
//初始化界面信息
//定义一个内部类,声明list_item相应的控件引用
//适配器 //构造函数 public MyAdapter(Context context, List<MusicInfo> musicList) {}
public int getCount(){} public View getView(final int position, View convertView, ViewGroup parent){} }
//进度条事件响应
//list点击音乐列表元事件响应
//按钮事件响应
//解除绑定
//音乐播放指引 }
//播放模式 |
7. MusicService音乐服务:
类名 |
MusicService |
类功能描述 |
音乐服务类,继承了Service(包含了暂停、播放、停止、缓冲、重置等等) |
类属性 |
public MediaPlayer player; //声明 MediaPlayer 对象 |
类实现的方法 |
//onBind方法 public IBinder onBind(Intent arg0) {} public void onCreate() {} public int onStartCommand(Intent intent, int flags, int startId) {}
//开始播放
//缓冲完成后执行
//播放
//停止
//缓冲
//重置
//是否播放
//解绑服务
//当前音乐的总时长
//MediaController
//返回MusicService实例 } |
8. MusicInfo歌曲信息实体类:
类名 |
MusicInfo |
类功能描述 |
歌曲信息实体类 |
类属性 |
private long id; // 歌曲ID 3 |
类实现的方法 |
Getter和Setter方法 |
9. MusicUtils音乐工具类:
类名 |
MusicUtils |
类功能描述 |
音乐工具类(包含了媒体库读取歌词信息、时间处理、文件大小处理) |
类属性 |
//生成动态数组,并转载数据 |
类实现的方法 |
//读取方法:读取SD卡里的歌曲信息,保存在List当中,以供Adapter调用显示
// 时间转化处理,将时间修改为常用的格式
// 文件大小转换处理,将B转换为MB |
10. 资源文件:
11. 其他:
12. 附录:
AndroidManifest.xml配置文件:(注意:申请SD卡权限和注册服务)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.admin.musicapp">
<!-- 允许访问SD卡 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/mymusic"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<!--注册服务-->
<service android:name=".MusicService"/>
</application>
</manifest>
activity_main.xml音乐界面布局设计:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="vertical"
android:background="@drawable/deeppink"
tools:context=".MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="10.0dip">
<TextView
android:id="@+id/music_title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="18.0dip"
android:textStyle="bold"
android:gravity="center"
android:text="正在播放歌曲名称"/>
<!--android:text="@String/music"/>-->
<TextView
android:id="@+id/music_author"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="未知艺术家"
android:gravity="center"/>
</LinearLayout>
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1">
</ListView>
<LinearLayout
android:id="@+id/surf_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:layout_weight="1"
android:visibility="gone">
<ScrollView
android:id="@+id/scroll_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/music_lyric"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="好歌不容错过"
android:textColor="#fff"
android:layout_weight="1"
android:textAppearance="?android:attr/textAppearanceLarge"/>
</ScrollView>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_marginTop="10.0dip"
android:orientation="horizontal">
<TextView
android:id="@+id/play_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5.0dip"
android:text="00:00"
android:textSize="15.0dip" />
<SeekBar
android:id="@+id/seekbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="2.0dip"
android:layout_marginRight="2.0dip"
android:layout_weight="1" />
<TextView
android:id="@+id/all_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5.0dip"
android:text="00:00"
android:textSize="15.0dip"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_marginBottom="10.0dip">
<ImageButton
android:id="@+id/music_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/music" />
<ImageButton
android:id="@+id/music_previous"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50.0dip"
android:background="@mipmap/previous"/>
<ImageButton
android:id="@+id/music_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10.0dip"
android:background="@mipmap/pause"
android:visibility="gone"/>
<ImageButton
android:id="@+id/music_play"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10.0dip"
android:background="@mipmap/play"/>
<ImageButton
android:id="@+id/music_next"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10.0dip"
android:background="@mipmap/next"/>
<ImageButton
android:id="@+id/music_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="50.0dp"
android:background="@mipmap/search"/>
</LinearLayout>
</LinearLayout>
list_item.xml音乐列表元:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/RelativeLayout1"
android:layout_width="match_parent"
android:layout_height="55.0dp"
android:orientation="vertical"
android:padding="10dp">
<LinearLayout
android:id="@+id/albumLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageButton
android:id="@+id/albumImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/ic_launcher_white" />
<ImageButton
android:id="@+id/play_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@mipmap/pause_alt"
android:visibility="gone"/>
</LinearLayout>
<TextView
android:id="@+id/music_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_gravity="center"
android:layout_marginRight="5.0dp"
android:text="@string/time"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/music_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_below="@id/music_duration"
android:layout_gravity="center"
android:layout_marginRight="3.0dp"
android:text="@string/size"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/music_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_marginLeft="5dp"
android:layout_toRightOf="@+id/albumLayout"
android:text="@string/siger"
android:textColor="@android:color/white" />
<TextView
android:id="@+id/music_artist"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/music_title"
android:layout_below="@id/music_title"
android:text="@string/artist"
android:textColor="@android:color/white" />
</RelativeLayout>
MainActivity主类:(注意:该项目是在真机下调试的,调试时,注意在手机的“权限管理”处找到项目软件“MyMusic”的存储权限打开)
/**
* Created by Admin on 2018/5/10.
*/
public class MusicActivity extends Activity implements View.OnClickListener {
private MusicService musicService; //声明 MusicService 对象
private Intent intent; //发送广播
private boolean isBind; //服务绑定标识
private boolean isShowOrNot = false; //音乐列表按钮标识
private boolean isSeekBarChanging = false; //拖动进度时与Thread更新播放进度条冲突标识
//测试list
private ListView list_view; //音乐列表
private List<MusicInfo>musicList;
private boolean isPlaying; //播放标识
int currentPositon = 0; //当前进度,用于快进、快退
private int music_position = -1; //当前音乐位置
private ScrollView scroll_view; //歌词滚动
private LinearLayout surf_view; //歌词界面
private TextView play_title; //正在播放的音乐
private TextView play_artist; //作者
private ImageButton music_list; //列表
private ImageButton music_previous; //快退
private ImageButton music_play; //播放
private ImageButton music_pause; //暂停
private ImageButton music_stop; //停止
private ImageButton music_next; //快进
private TextView play_time; //播放时间
private TextView all_time; //总时间
private SeekBar seekbar; //进度条
//为了接受IBinder实例,必须创建一个 ServiceConnection 实例,并传给MusicService()
private ServiceConnection serviceConnection = new ServiceConnection() {
//当service被绑定的时候回调该函数
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
MusicService.MediaController binder = (MusicService.MediaController) iBinder;
musicService = binder.getService();
// 设置进度条的最大值
seekbar.setMax(musicService.getDuration());
//每次播放都要加载音乐时长
seekbar.setProgress(musicService.getDuration());
//更新进度条
handler.post(updateThread);
Log.i("tag","服务器已经连接......");
}
//服务器断开或关闭的时候调用该方法
@Override
public void onServiceDisconnected(ComponentName componentName) {
musicService = null; //MusicService实例不可再用
Log.i("tag","服务器已经断开......");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 创建一个用于启动服务的显示意图,指向 MusicService 类
intent = new Intent(MusicActivity.this,MusicService.class);
initView(); //初始化界面信息
// 绑定服务,同时服务开启,如果成功则返回true,否则返回false
isBind = bindService(intent, serviceConnection, BIND_AUTO_CREATE);
if (isBind) {
Log.i("tag","音乐播放器服务绑定成功!");
} else {
Log.i("tag","音乐播放器服务绑定失败!");
}
}
//初始化界面信息
public void initView(){
scroll_view= (ScrollView) findViewById(R.id.scroll_view);
surf_view = (LinearLayout) findViewById(R.id.surf_view);
list_view = (ListView) findViewById(R.id.list_view);
play_title=(TextView) this.findViewById(R.id.music_title);
play_artist=(TextView) this.findViewById(R.id.music_author);
seekbar = (SeekBar) findViewById(R.id.seekbar);
play_time= (TextView) findViewById(R.id.play_time);
all_time= (TextView) findViewById(R.id.all_time);
music_list = (ImageButton)findViewById(R.id.music_list);
music_previous = (ImageButton)findViewById(R.id.music_previous);
music_play = (ImageButton)findViewById(R.id.music_play);
music_pause = (ImageButton)findViewById(R.id.music_pause);
music_stop = (ImageButton)findViewById(R.id.music_stop);
music_next = (ImageButton)findViewById(R.id.music_next);
//注册监听事件
seekbar.setOnSeekBarChangeListener(new SeekBarListener());
music_list.setOnClickListener(this);
music_previous.setOnClickListener(this);
music_play.setOnClickListener(this);
music_pause.setOnClickListener(this);
music_stop.setOnClickListener(this);
music_next.setOnClickListener(this);
//测试list
musicList = MusicUtils.getMusicData(MusicActivity.this);
Log.i("tag", "MyAdapter");
MyAdapter adapter = new MyAdapter(MusicActivity.this,musicList);
list_view.setAdapter(adapter);
}
//定义一个内部类,声明list_item相应的控件引用
public final class ViewHolder {
public RelativeLayout listitem; //用于监听
public ImageButton albumImage; //专辑
public ImageButton play_pause; //暂停
public TextView music_title; //歌名
public TextView music_artist; //艺术家
public TextView music_duration; //歌曲时长
public TextView music_size; //歌曲大小
}
//适配器
private class MyAdapter extends BaseAdapter {
private LayoutInflater mInflater;
private Context context;
private List<MusicInfo> musicList; //存放MusicInfo引用的集合
private MusicInfo musicInfo; //MusicInfo对象引用
public MyAdapter(Context context, List<MusicInfo> musicList) {
this.context = context;
this.musicList = musicList;
this.mInflater = LayoutInflater.from(context);
}
@Override
public int getCount(){
return musicList.size();
}
@Override
public Object getItem(int position){
return musicList.get(position);
}
@Override
public long getItemId(int position){
return position;
}
@Override
public View getView(final int position, View convertView, ViewGroup parent){
final ViewHolder holder;
if(convertView == null){
holder = new ViewHolder();
//引入布局
/**
* int resource:需要加载布局文件的id,将该布局文件加载到Activity中来操作
* ViewGroup root:需要附加到resource资源文件的根控件
* boolean attachToRoot:是否将root附加到布局文件的根视图上
*/
convertView = mInflater.inflate(R.layout.list_item, null);
//实例化对象
holder.listitem = (RelativeLayout) convertView.findViewById(R.id.RelativeLayout1);
holder.albumImage = (ImageButton) convertView.findViewById(R.id.albumImage);
holder.play_pause = (ImageButton) convertView.findViewById(R.id.play_pause);
holder.music_title = (TextView) convertView.findViewById(R.id.music_title);
holder.music_artist = (TextView) convertView.findViewById(R.id.music_artist);
holder.music_duration = (TextView)convertView.findViewById(R.id.music_duration);
holder.music_size = (TextView) convertView.findViewById(R.id.music_size);
convertView.setTag(holder); //给View添加一个格外的数据
}else{
holder = (ViewHolder)convertView.getTag(); //通过getTag()将数据取出来
}
musicInfo = musicList.get(position);
//给控件赋值,musicList
// holder.albumImage.setImageResource(musicInfo.getAlbumId()); //显示专辑
holder.music_title.setText(musicInfo.getTitle()+".mp3"); //显示歌名
holder.music_artist.setText(musicInfo.getArtist()); //显示艺术家
holder.music_duration.setText(MusicUtils.formatTime(musicInfo.getDuration())); //显示歌曲时长
holder.music_size.setText(MusicUtils.toMB(musicInfo.getSize())); //显示歌曲大小
//List的点击事件
holder.albumImage.setTag(position);
holder.albumImage.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Toast.makeText(MainActivity.this,"你点击了listitem"+((Integer)v.getTag()+1),Toast.LENGTH_SHORT).show();
itemClick(holder,(Integer)v.getTag());
notifyDataSetChanged();
}
});
return convertView;
}
}
//进度条事件响应
private class SeekBarListener implements SeekBar.OnSeekBarChangeListener{
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
}
/*滚动时,应当暂停后台定时器*/
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
isSeekBarChanging = true;
// musicService.seekTo(seekBar.getProgress());
}
/*滑动结束后,重新设置值*/
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
isSeekBarChanging = false;
}
}
//list点击事件响应
@SuppressLint("ResourceAsColor")
private void itemClick(ViewHolder holder, int position) {
music_pause.setVisibility(View.VISIBLE);
music_play.setVisibility(View.GONE);
Log.i("tag", "position:" + position);
MusicInfo musicFile = musicList.get(position);
if (position == music_position) { //选中当前歌曲
if (isPlaying) { //播放
holder.listitem.setBackgroundColor(R.color.colorAccent);
holder.albumImage.setVisibility(View.GONE);
holder.play_pause.setVisibility(View.VISIBLE);
musicService.pause();
isPlaying = false;
} else { //暂停
holder.listitem.setBackgroundColor(R.color.colorAccent);
holder.albumImage.setVisibility(View.VISIBLE);
holder.play_pause.setVisibility(View.GONE);
musicService.start();
isPlaying = true;
}
}else { //选中其他歌曲
holder.listitem.setBackgroundColor(R.color.colorAccent);
holder.albumImage.setVisibility(View.GONE);
holder.play_pause.setVisibility(View.VISIBLE);
musicService.musicPlay(musicFile.getUrl()); //musicService.musicPlay
play_title.setText(musicFile.getTitle());
play_artist.setText(musicFile.getArtist());
}
music_position = position;
}
//按钮事件响应
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.music_list:
if (isShowOrNot == false) {
list_view.setVisibility(View.GONE);
surf_view.setVisibility(View.VISIBLE);
isShowOrNot = true;
Log.i("tag","音乐列表显示");
} else {
list_view.setVisibility(View.VISIBLE);
surf_view.setVisibility(View.GONE);
isShowOrNot = false;
Log.i("tag","音乐列表隐藏");
}
Log.i("tag","打开音乐列表");
break;
case R.id.music_previous:
Log.i("tag","快退");
currentPositon = musicService.getCurrentPosition();
if (currentPositon-10000>0){
musicService.seekTo(currentPositon-10000);
}
break;
case R.id.music_play:
music_pause.setVisibility(View.VISIBLE);
music_play.setVisibility(View.GONE);
musicService.start();
Log.i("tag","开始播放音乐");
break;
case R.id.music_pause:
music_pause.setVisibility(View.GONE);
music_play.setVisibility(View.VISIBLE);
musicService.pause();
Log.i("tag","音乐暂停");
break;
case R.id.music_next:
Log.i("tag","快进");
currentPositon = musicService.getCurrentPosition();
if (currentPositon+10000<musicService.getDuration()){
musicService.seekTo(currentPositon+10000);
}
break;
case R.id.music_stop:
music_pause.setVisibility(View.GONE);
music_play.setVisibility(View.VISIBLE);
//停止的时候将播放时间设置为初始值,进度条设置为初始位置
seekbar.setProgress(0);
musicService.stop();
Log.i("tag","音乐停止");
break;
}
}
//解除绑定
@Override
protected void onDestroy() {
super.onDestroy();
musicService.stop();
unbindService(serviceConnection);
isPlaying = false;
}
//音乐播放指引
Handler handler = new Handler();
Runnable updateThread = new Runnable() { //使用线程循环更新当前播放进度,即更新进度条
@Override
public void run() {
Time progress = new Time(musicService.getCurrentPosition());
Time allTime = new Time(musicService.getDuration());
String play_timeStr = progress.toString();
Log.v("progress", play_timeStr);
String all_timeStr = allTime.toString();
play_time.setText(play_timeStr.substring(play_timeStr.indexOf(":") + 1));
all_time.setText(all_timeStr.substring(all_timeStr.indexOf(":") + 1));
// seekbar.setProgress(musicService.getCurrentPosition());
int progressValues=0;
if (musicService.getDuration()>0){
progressValues=seekbar.getMax()*musicService.getCurrentPosition()/musicService.getDuration();
}
seekbar.setProgress(progressValues);
handler.postDelayed(updateThread,400);
if(isPlaying){
MusicInterface(3,2,musicList);
}
}
};
//播放模式
private final int PREVIOUS_MUSIC = 1; //上一首
private final int NEXT_MUSIC = 2; //下一首
private final int LOOP_MODE = 3; //循环播放
private final int RANDOM_MODE = 4; //随机播放
private void MusicInterface(int mode,int msg,List<MusicInfo> musicList){
switch (mode){ //对当前的播放模式作出判断,进行不同的处理
case LOOP_MODE: //循环模式
switch (msg) {
case NEXT_MUSIC: //下一首,注意判断是否是最后一首了
if(music_position < musicList.size() - 1) {
music_position++;
}else {
Toast.makeText(this,"已经是最后一首了",Toast.LENGTH_SHORT).show();
music_position = 0;
handler.removeCallbacks(updateThread);
musicService.musicPlay(musicList.get(music_position).getUrl());
play_title.setText(musicList.get(music_position).getTitle());
}
break;
case PREVIOUS_MUSIC: //上一首,注意判断是否是第一首了
if(music_position >= 1) {
music_position--;
}else {
Toast.makeText(this, "已经是第一首了", Toast.LENGTH_SHORT).show();
music_position = musicList.size() - 1;
handler.removeCallbacks(updateThread);
musicService.musicPlay(musicList.get(music_position).getUrl());
play_title.setText(musicList.get(music_position).getTitle());
}
break;
}
break;
case RANDOM_MODE: //随机模式,注意不要出界
music_position = (int)(Math.random() * (musicList.size() - 1));
break;
}
try{ //重新初始化一个service,将切换到的歌曲信息传给service
MusicInfo musicInfo = musicList.get(music_position);
String url = musicInfo.getUrl();
play_title.setText(musicInfo.getTitle());
seekbar.setMax(musicInfo.getDuration());
musicService.musicPlay(url);
}
catch(Exception e){
e.printStackTrace();
}
}
}
MusicService音乐服务:
/**
* Created by Admin on 2018/5/4.
*/
public class MusicService extends Service{
public MediaPlayer player; //声明 MediaPlayer 对象
private MediaController controller; //声明 MediaController 对象
@Override
public IBinder onBind(Intent arg0) {
Log.i("tag","onBind");
controller = new MediaController();
return controller;
}
@Override
public void onCreate() {
Toast.makeText(this,"MusicSeivice onCreate",Toast.LENGTH_SHORT).show();
player = MediaPlayer.create(getApplicationContext(),R.raw.music); //默认读取音频
if (player == null){
Log.i("MusicSeivice","------null");
}
player.setLooping(true); //设置可以重复播放
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("MusicSeivice","onStartCommand");
new Thread(new Runnable() {
@Override
public void run() {
player.start();
while (true) {
if (player == null || player.isPlaying() == false) {
stopSelf();
Log.i("MusicSeivice", "stopSelf()");
return;
}
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
//播放
public void start(){
Log.i("tag","start");
player.start();
}
//暂停
public void pause(){
Log.i("tag","pause");
if (player != null && player.isPlaying()) {
player.pause();
}
}
//停止
public void stop(){
Log.i("tag","stop");
player.stop();
try {
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
player.seekTo(0);
}
//缓冲
public void prepare(){
Log.i("tag","prepare");
try {
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
//重置
public void reset(){
Log.i("tag","reset");
player.reset();
}
//进度
public void seekTo(int position){
Log.i("tag","seekTo");
player.seekTo(position);
}
//是否播放
public boolean isPlaying(){
Log.i("tag","isPlaying");
return player.isPlaying();
}
//解绑服务
@Override
public void onDestroy() {
Log.i("","onDestroy");
player.stop();
player.release();
super.onDestroy();
}
//当前音乐的总时长
public int getDuration() {
return player.getDuration();
}
//当前播放的位置
public int getCurrentPosition() {
return player.getCurrentPosition();
}
//读取资源
public void setDataSource(String path){
try {
player.setDataSource(path);
} catch (IOException e) {
e.printStackTrace();
}
}
//MediaController
class MediaController extends Binder {
//返回MusicService实例
public MusicService getService(){
return MusicService.this;
}
}
//开始播放
public void musicPlay(String path) {
try {
player.reset(); //重置
player.setDataSource(path);
player.prepare(); //进行缓冲
Log.i("tag", "缓冲完成");
player.setOnPreparedListener(new PreparedListener()); //缓冲完成后执行
} catch (Exception e) {
e.printStackTrace();
}
}
private final class PreparedListener implements MediaPlayer.OnPreparedListener {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.start();
Log.i("tag", "//start()执行");
}
}
}
MusicInfo音乐信息实体类:
/**
* 歌曲信息实体类
* Created by Admin on 2018/5/6.
*/
public class MusicInfo {
private long id; // 歌曲ID 3
private String title; // 歌曲名称 0
private String album; // 专辑 7
private int albumId;// 专辑ID 6
private String displayName; // 显示名称 4
private String artist; // 歌手名称 2
private int duration; // 歌曲时长 1
private int size; // 歌曲大小 8
private String url; // 歌曲路径 5
private String lrcTitle; // 歌词名称
private String lrcSize; // 歌词大小
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public int getAlbumId() {
return albumId;
}
public void setAlbumId(int albumId) {
this.albumId = albumId;
}
public String getDisplayName() {
return displayName;
}
public void setDisplayName(String displayName) {
this.displayName = displayName;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public int getDuration() {
return duration;
}
public void setDuration(int duration) {
this.duration = duration;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getLrcTitle() {
return lrcTitle;
}
public void setLrcTitle(String lrcTitle) {
this.lrcTitle = lrcTitle;
}
public String getLrcSize() {
return lrcSize;
}
public void setLrcSize(String lrcSize) {
this.lrcSize = lrcSize;
}
}
13. MusicUtils音乐工具类:(包含了媒体库读取歌词信息、时间处理、文件大小处理)
/**
* 音乐工具类
* Created by Admin on 2018/5/6.
*/
public class MusicUtils {
//读取方法:读取SD卡里的歌曲信息,保存在List当中,以供Adapter调用显示
public static List<MusicInfo> getMusicData(Context context){
//生成动态数组,并转载数据
List<MusicInfo> musicList = new ArrayList<MusicInfo>();
/**
* 媒体库查询语句,查询所有的歌曲
* 参数:
* Uri:提供内容的Provider标识,查询路径
* projection:告诉Provider要返回的内容(列Column),如果填null,则返回所有列
* selection:设置条件(相当于SQL语句中的where,null表示不进行筛选)
* selectionArgs:查询条件属性值,(配合第三个参数使用,如果在第三个参数里面有?,那么在selectionArgs写的数据就会替换掉?)
* sortOrder:按照什么进行排序,null则不进行排序
*/
ContentResolver mResolver = context.getContentResolver();
//MediaStore.Audio.Media.EXTERNAL_CONTENT_URI=="//media/external/audio/media"
Cursor cursor = mResolver.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null, null, null, null);
Log.i("tag", "cursor:"+ cursor.getCount());
Log.i("tag", "url:"+ MediaStore.Audio.Media.EXTERNAL_CONTENT_URI);
//返回查询结果
if(cursor != null) {
cursor.moveToFirst();
for (int i = 0; i < cursor.getCount(); i++) {
Log.i("tag", "TITLE:"+ cursor.getString((cursor.
getColumnIndex(MediaStore.Audio.Media.TITLE))));
Log.i("tag", "ARTIST:"+ cursor.getString((cursor.
getColumnIndex(MediaStore.Audio.Media.ARTIST))));
long id = cursor.getLong(cursor
.getColumnIndex(MediaStore.Audio.Media._ID)); //歌曲ID
String title = cursor.getString((cursor
.getColumnIndex(MediaStore.Audio.Media.TITLE))); //歌名
String artist = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.ARTIST)); //艺术家
String album = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.ALBUM)); //专辑
String displayName = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME)); //显示歌名
int albumId = cursor.getInt(
cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM_ID)); //专辑ID
int duration = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media.DURATION)); // 时长
int size = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media.SIZE)); // 文件大小
String url = cursor.getString(cursor
.getColumnIndex(MediaStore.Audio.Media.DATA)); // 文件路径
int isMusic = cursor.getInt(cursor
.getColumnIndex(MediaStore.Audio.Media.IS_MUSIC)); // 是否为音乐
if(artist.equals("") || artist.equals("<unknown>")){
artist = "未知艺术家";
}
if (isMusic != 0) { // 只把音乐添加到集合当中
MusicInfo musicInfo = new MusicInfo();
musicInfo.setId(id);
musicInfo.setTitle(title);
musicInfo.setArtist(artist);
musicInfo.setAlbum(album);
musicInfo.setAlbumId(albumId);
musicInfo.setDisplayName(displayName);
musicInfo.setDuration(duration);
musicInfo.setSize(size);
musicInfo.setUrl(url);
cursor.moveToNext(); //游标移动
musicList.add(musicInfo); //把音乐加到List集合上
}
}
cursor.close(); // 释放资源
}
return musicList;
}
// 时间转化处理,将时间修改为常用的格式
public static String formatTime(int time){
String minute = time / (1000 * 60) + "";
String second = time % (1000 * 60) + "";
if(minute.length() < 2){
minute = "0" + (time / (1000 * 60)) + "";
}else {
minute = time / (1000 * 60) + "";
}
if(second.length() == 4){
second = "0" + (time % (1000 * 60)) + "";
}else if(second.length() == 3){
second = "00" + (time % (1000 * 60)) + "";
}else if(second.length() == 2){
second = "000" + (time % (1000 * 60)) + "";
}else if(second.length() == 1){
second = "0000" + (time % (1000 * 60)) + "";
}
return minute + ":" + second.trim().substring(0, 2);
}
// 文件大小转换处理,将B转换为MB
public static String toMB(int size) {
float a = (float) size / (float) (1024 * 1024);
String b = Float.toString(a);
int c = b.indexOf(".");
String fileSize = "";
fileSize += b.substring(0, c + 2);
return fileSize + "MB";
}
}