模仿音乐播放器项目, 这个播放器基本功能已经实现,但是最大的问题是播放代码放在了activity中处理的,当推出音乐播放界面的时候,音乐是需要继续播放,当带过来电话时 音乐需要暂停,打完电话继续播放,所以以前的版本还是有很大问题的,今天决定一步一步实现一个功能齐全的播放器,把播放控制代码放在service中。
首先来实现这样一个简单的界面:
新建一个android项目,如图所示:
把项目中用到的图片拷贝到drawable目录下,编写main.xml
<?xml version="1.0" encoding="utf-8"?>
<TabHost xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="5dp" >
<TabWidget
android:id="@android:id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="5dp" />
</LinearLayout>
</TabHost>
编写MainActivity类
public class MainActivity extends TabActivity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
Resources res = getResources();
TabHost tabHost = getTabHost();
TabHost.TabSpec spec;
Intent intent;
intent = new Intent().setClass(this, ListActivity.class);
spec = tabHost.newTabSpec("音乐").setIndicator("音乐",
res.getDrawable(R.drawable.item))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, ArtistsActivity.class);
spec = tabHost.newTabSpec("艺术家").setIndicator("艺术家",
res.getDrawable(R.drawable.artist))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, AlbumsActivity.class);
spec = tabHost.newTabSpec("专辑").setIndicator("专辑",
res.getDrawable(R.drawable.album))
.setContent(intent);
tabHost.addTab(spec);
intent = new Intent().setClass(this, SongsActivity.class);
spec = tabHost.newTabSpec("最近播放").setIndicator("最近播放",
res.getDrawable(R.drawable.album))
.setContent(intent);
tabHost.addTab(spec);
tabHost.setCurrentTab(0);
}
}
注意这里要继承的是TabActivity,关于TabHost的用法不做过多介绍,官网有。最后分别建立其他用到的activity和使用的xml布局文件,不要忘记在manifest中注册,
这样上面的主界面就完成了。
下面看一下怎么遍历音乐文件,通过listview展现到界面上,
在相应目录下建立MusicList类,这是一个普通类,为了加载音乐文件
public class MusicList {
public static List<Music> getMusicData(Context context){
List<Music> musicList=new ArrayList<Music>();
ContentResolver cr=context.getContentResolver();
if(cr!=null){
//获取所有歌曲
Cursor cursor=cr.query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
null, null,null, MediaStore.Audio.Media.DEFAULT_SORT_ORDER);
if(null==cursor){
return null;
}
if(cursor.moveToFirst()){
do{
Music m=new Music();
String title=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.TITLE));
String singer=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ARTIST));
if("<unknown>".equals(singer)){
singer="未知艺术家";
}
String album=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.ALBUM));
long size=cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.SIZE));
long time=cursor.getLong(cursor.getColumnIndex(MediaStore.Audio.Media.DURATION));
String url=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DATA));
String name=cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Media.DISPLAY_NAME));
m.setTitle(title);
m.setSinger(singer);
m.setAlbum(album);
m.setSize(size);
m.setTime(time);
m.setUrl(url);
m.setName(name);
musicList.add(m);
}while(cursor.moveToNext());
}
}
return musicList;
}
}
这里是通过ContentResolver得到的音乐信息,因为系统为了便于应用程序间音乐信息的共享,提供了ContentProvder,所以我就没有遍历SD卡下的音乐文件。
Music类:
public class Music{
private String title;
private String singer;
private String album;
private String url;
private long size;
private long time;
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSinger() {
return singer;
}
public void setSinger(String singer) {
this.singer = singer;
}
public String getAlbum() {
return album;
}
public void setAlbum(String album) {
this.album = album;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
}
因为要用到自定义适配器,所以在layout下先建立一个和适配器匹配的xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginTop="2dip"
android:background="#00000000"
android:orientation="horizontal" >
<ImageView
android:id="@+id/music_item_image"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_gravity="center"
android:background="@drawable/item"
android:paddingRight="10dip" />
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="60dip"
android:layout_weight="1"
android:layout_marginLeft="3dp"
android:gravity="center_vertical"
android:orientation="vertical" >
<TextView
android:id="@+id/music_item_name"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:textColor="#ffffff"
android:textSize="18dp"
android:text="依然爱你"
android:textStyle="bold" />
<TextView
android:id="@+id/music_item_singer"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="5dip"
android:textColor="#ffffff"
android:text="王力宏"
android:textSize="12dp" />
</LinearLayout>
<TextView
android:id="@+id/music_item_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:paddingRight="5dip"
android:text="03:42"
android:textColor="#ffffff" />
</LinearLayout>
接下来是自定义的适配器MusicAdapter
public class MusicAdapter extends BaseAdapter {
private List<Music> listMusic;
private Context context;
public MusicAdapter(Context context,List<Music> listMusic){
this.context=context;
this.listMusic=listMusic;
}
public void setListItem(List<Music> listMusic){
this.listMusic=listMusic;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return listMusic.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return listMusic.get(arg0);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// TODO Auto-generated method stub
if(convertView==null){
convertView=LayoutInflater.from(context).inflate(R.layout.music_item, null);
}
Music m=listMusic.get(position);
//音乐名
TextView textMusicName=(TextView) convertView.findViewById(R.id.music_item_name);
textMusicName.setText(m.getName());
//歌手
TextView textMusicSinger=(TextView) convertView.findViewById(R.id.music_item_singer);
textMusicSinger.setText(m.getSinger());
//持续时间
TextView textMusicTime=(TextView) convertView.findViewById(R.id.music_item_time);
textMusicTime.setText(toTime((int)m.getTime()));
return convertView;
}
/**
* 时间格式转换
* @param time
* @return
*/
public String toTime(int time) {
time /= 1000;
int minute = time / 60;
int hour = minute / 60;
int second = time % 60;
minute %= 60;
return String.format("%02d:%02d", minute, second);
}
}
时间格式的转换是我从网上找到的,直接调用toTime方法能得到格式化后的时间了。
最后是在ListActivity添加适配器:
public class ListActivity extends Activity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.listmusic);
listView= (ListView) this.findViewById(R.id.listAllMusic);
List<Music> listMusic=MusicList.getMusicData(getApplicationContext());
MusicAdapter adapter=new MusicAdapter(this, listMusic);
listView.setAdapter(adapter);
}
}
这样音乐文件就会加载上来了,看看效果吧: