昨天写了如何实现音乐播放器的第一篇,今天需要实现的是如何从手机内存里读取音乐文件并且显示在列表中。
首先,我们需要从主界面通过点击本地音乐按钮跳转到音乐列表界面;另外需要让程序主界面连续按下两次返回键后退出程序。由于逻辑十分简单就不讲解了,直接贴出代码:
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.KeyEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class HomeActicity extends Activity{
private TextView myMusic;
// 定义一个变量,来标识是否退出
private static boolean isExit = false;
Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
isExit = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.home);
myMusic = (TextView) findViewById(R.id.myMusic);
myMusic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(HomeActicity.this,MainActivity.class);
startActivity(intent);
}
});
}
/*
判断是否按下返回键
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
exit();
return false;
}
return super.onKeyDown(keyCode, event);
}
private void exit() {
if (!isExit) {
isExit = true;
Toast.makeText(getApplicationContext(), "再按一次退出程序",
Toast.LENGTH_SHORT).show();
// 利用handler延迟发送更改状态信息
mHandler.sendEmptyMessageDelayed(0, 2000);
} else {
finish();
System.exit(0);
}
}
}
我们先进行分析一下,把这个过程划分为几个步凑:
1、完成音乐列表的xml布局
2、从手机内存中读取音乐文件并保存到List集合中,List存放的事Mp3Info对象
3、迭代List集合,把每一个Mp3Info对象的所有属性,保存到Map对象中
4、定义一个List集合,并把Map对象添加到List集合中
5、定义一个SimpleAdapter,并调用setAdapter方法将数据显示到列表中
下面就是具体的代码:
第一步:音乐列表布局
item布局文件如下:
import android.content.Context;
import android.util.AttributeSet;
import android.widget.TextView;
/**
* 实现跑马灯效果的TextView
*/
public class MarqueeTextView extends TextView{
public MarqueeTextView(Context context) {
super(context);
}
public MarqueeTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MarqueeTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
//返回textview是否处在选中的状态
//而只有选中的textview才能够实现跑马灯效果
@Override
public boolean isFocused() {
return true;
}
}
先定义一个Mp3类,定义好相应的id、title等,并实现其set、get方法
public class Mp3Info {
long id;
String title;
String artist;
long duration;
long size;
String url;
public void setId(long id) {
this.id = id;
}
public long getId() {
return id;
}
public void setTitle(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getArtist() {
return artist;
}
public void setDuration(long duration) {
this.duration = duration;
}
public long getDuration() {
return duration;
}
public void setSize(long size) {
this.size = size;
}
public long getSize() {
return size;
}
public void setUrl(String url) {
this.url = url;
}
public String getUrl() {
return url;
}
}
为了读取手机文件需要用到语句
Cursor cursor = context.getContentResolver().query( MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
接下来展示详细的代码:
import android.content.Context;
import android.database.Cursor;
import android.provider.MediaStore;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
public class MediaUtil {
/**
* 用于从数据库中查询歌曲的信息,保存在List当中
*
* @return
*/
public static List getMp3Infos(Context context) {
Cursor cursor = context.getContentResolver().query(
MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, null, null, null,
MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
List mp3Infos = new ArrayList();
for (int i = 0; i < cursor.getCount(); i++) {
cursor.moveToNext();
Mp3Info mp3Info = new Mp3Info();
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)); //艺术家
long duration = cursor.getLong(cursor
.getColumnIndex(MediaStore.Audio.Media.DURATION)); //时长
long size = cursor.getLong(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 (isMusic != 0) { //只把音乐添加到集合当中
mp3Info.setId(id);
mp3Info.setTitle(title);
mp3Info.setArtist(artist);
mp3Info.setDuration(duration);
mp3Info.setSize(size);
mp3Info.setUrl(url);
mp3Infos.add(mp3Info);
}
}
return mp3Infos;
}
/**
* 往List集合中添加Map对象数据,每一个Map对象存放一首音乐的所有属性
* @param mp3Infos
* @return
*/
public static List> getMusicMaps(
List mp3Infos) {
List> mp3list = new ArrayList>();
String music_menu = String.valueOf(R.drawable.music_menu);
String check_music = String.valueOf(R.drawable.check);
int i = 0; //定义歌曲的序号
for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext();) {
i++;
Mp3Info mp3Info = (Mp3Info) iterator.next();
HashMap map = new HashMap();
map.put("number",String.valueOf(i));
map.put("id",String.valueOf(mp3Info.getId()));
map.put("title", mp3Info.getTitle());
map.put("Artist", mp3Info.getArtist());
map.put("duration", formatTime(mp3Info.getDuration()));
map.put("size", String.valueOf(mp3Info.getSize()));
map.put("url", mp3Info.getUrl());
map.put("music_menu",music_menu);
map.put("check_music",check_music);
mp3list.add(map);
}
return mp3list;
}
/**
* 格式化时间,将毫秒转换为分:秒格式
* @param time
* @return
*/
public static String formatTime(long time) {
String min = time / (1000 * 60) + "";
String sec = time % (1000 * 60) + "";
if (min.length() < 2) {
min = "0" + time / (1000 * 60) + "";
} else {
min = time / (1000 * 60) + "";
}
if (sec.length() == 4) {
sec = "0" + (time % (1000 * 60)) + "";
} else if (sec.length() == 3) {
sec = "00" + (time % (1000 * 60)) + "";
} else if (sec.length() == 2) {
sec = "000" + (time % (1000 * 60)) + "";
} else if (sec.length() == 1) {
sec = "0000" + (time % (1000 * 60)) + "";
}
return min + ":" + sec.trim().substring(0, 2);
}
}
其中需要注意的几点:
1、判定并选择音乐文件,保证只有音乐文件添加到List集合中
2、歌曲的id并不是歌曲的序号,需要自己定义;并且需要主要i一定要定义在foreach语句之外
最后便是在MainActivity中定义SimpleAdapter并将数据添加到列表中
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import java.util.HashMap;
import java.util.List;
public class MainActivity extends Activity {
private ListView mMusiclist; //音乐列表
private SimpleAdapter mAdapter;
List mp3Infos = null;
private List> mp3list;
private HashMap map;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mMusiclist = (ListView) findViewById(R.id.musiclist);
//为ListView添加数据源
mp3Infos = MediaUtil.getMp3Infos(getApplicationContext()); //获取歌曲对象集合
setListAdpter(MediaUtil.getMusicMaps(mp3Infos)); //显示歌曲列表
}
/**
* 填充列表
* @param
*/
public void setListAdpter(List> mp3list) {
mAdapter = new SimpleAdapter(this, mp3list,
R.layout.musicitem, new String[]{"number","title","check_music",
"Artist", "music_menu"}, new int[]{R.id.number,R.id.music_title,R.id.check,
R.id.music_Artist, R.id.music_menu});
mMusiclist.setAdapter(mAdapter);
}
}