花了2个多小时,完成了一个小小的Android MP3播放器,在各位大牛看来是小菜一碟
对于新手的我来说,还是有一定成就感的,好吧,斗胆拿出来分享一下,希望大神们多提意见。
1.简单说下我的构思,我想做两个页面,登录程序后,首先展示的是SD卡下的所有MP3文件,
点击某一首歌曲后,跳转到第二个页面进行控制播放,暂停等功能,只有完全退出程序才关闭停止歌曲....
2.第一步,对项目进行分下包,虽然项目很小,但是我觉得无论多小的项目,分包应该都是要
认真对待的。我这里主要分为4个包.....
第一个包下面有两个文件:MainActivity是主界面,PlayActivity是播放界面
control包下面是一个列表适配器的定义文件
model包下面是歌曲的Bean文件
utils包下面是一些封装好的方法
3.我的布局文件有3个
看下主界面的布局先,就是activity_main.xml文件
<RelativeLayout 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" > <ListView android:id="@+id/showSongList" android:layout_width="match_parent" android:layout_height="match_parent" > </ListView></RelativeLayout>
很简单,就是一个ListView....
再看下播放界面的布局文件,就是playsong.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <TextView android:id="@+id/tView" android:layout_marginTop="30dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="\n\n\n正在播放\n1.XXXXX" /> <ImageView android:id="@+id/igView" android:layout_gravity="center" android:layout_marginTop="30dp" android:layout_width="200dp" android:layout_height="400dp" /> <SeekBar android:id="@+id/skBar" android:layout_gravity="center_vertical|center" android:layout_height="wrap_content" android:layout_width="200dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical|center" android:layout_marginTop="30dp" android:orientation="horizontal"> <Button android:id="@+id/preBtn" android:layout_width="80dp" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@string/preSong" /> <Button android:id="@+id/playBtn" android:layout_width="80dp" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@string/startPlay" /> <Button android:id="@+id/pauseBtn" android:layout_width="80dp" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@string/pausePlay" /> <Button android:id="@+id/nextBtn" android:layout_width="80dp" android:layout_height="wrap_content" android:gravity="center_horizontal" android:text="@string/nextSong" /> </LinearLayout></LinearLayout>
也很简单...贴上一副图片,你就能明白了....
第三个布局文件是list_song_item.xml,它用来定义ListView中每一项的内容...
就是适配器用的布局文件...这里我只写了一个TextView...
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/songInfo" android:layout_width="match_parent" android:layout_height="60dp" android:gravity="left|center_vertical" android:textSize="30sp" /></LinearLayout>
4.看下MainActivity的代码吧..
public class MainActivity extends Activity { private ListView lv ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //找到ListView lv = (ListView)findViewById(R.id.showSongList); //设置适配器 lv.setAdapter(new SongAdapter(this)); //点击某一项后跳转到播放页面 lv.setOnItemClickListener(new OnItemClickListener() { public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) { // TODO Auto-generated method stub Intent intent = new Intent(MainActivity.this, PlayActivity.class); //携带要播放歌曲的序号 intent.putExtra("pos",position); //开始跳转 startActivity(intent); } }); } /* (non-Javadoc) * @see android.app.Activity#onKeyUp(int, android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if(keyCode == KeyEvent.KEYCODE_BACK) { //按返回键的时候,设置哨兵isExit,终止播放歌曲.. PlayActivity.isExit = true; } return super.onKeyUp(keyCode, event); }
比如我点击第一首,就会跳转到播放页面
5.看下播放页面的代码PlayActivity.Java...有一点很关键,就是
那个MediaPlayer,因为用户每点一次歌曲都会跳转到这个页面,
不可能同时有几个MediaPlayer工作,所以整个程序只维护一个
MediaPlayer...
public class PlayActivity extends Activity implements OnClickListener{ //当isExit = ture的时候,终止线程 public static boolean isExit; //有且只有一个MediaPlayer private static MediaPlayer mp = new MediaPlayer(); //所用到的控件 private TextView tView; private ImageView igView; private Button nextBtn; private Button preBtn; private Button playBtn; private Button pauseBtn; private SeekBar skBar; private int curPlayIndex; private SongControl sc; //获取所有歌曲列表 private ArrayList<SongBean> songList; //当点击上一首,或下一首的时候设置该变量 private boolean indexChange; //线程 private Thread songThread; /* (non-Javadoc) * @see android.app.Activity#onCreate(android.os.Bundle) */ @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.playsong); sc = SongControl.newInstance(); songList = sc.getSongList(); indexChange = true; isExit = false; tView = (TextView)findViewById(R.id.tView); igView = (ImageView)findViewById(R.id.igView); nextBtn = (Button) findViewById(R.id.nextBtn); preBtn = (Button)findViewById(R.id.preBtn); playBtn = (Button)findViewById(R.id.playBtn); pauseBtn = (Button)findViewById(R.id.pauseBtn); skBar = (SeekBar)findViewById(R.id.skBar); //设置SeekBar侦听 skBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() { public void onStopTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub //拖到最后的时候,直接播放下一首歌曲 if(seekBar.getProgress() == mp.getDuration()) { nextSong(); } mp.seekTo(seekBar.getProgress()); } public void onStartTrackingTouch(SeekBar seekBar) { // TODO Auto-generated method stub } public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { // TODO Auto-generated method stub } }); songThread = new Thread(new Runnable() { public void run() { // TODO Auto-generated method stub while(true) { //如果是true,终止线程 if(isExit) { stopSong(); break; } if(mp.isPlaying()) { try { Thread.sleep(500); skBar.setProgress(mp.getCurrentPosition()); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } }); songThread.start(); nextBtn.setOnClickListener(this); preBtn.setOnClickListener(this); playBtn.setOnClickListener(this); pauseBtn.setOnClickListener(this); // curPlayIndex = getIntent().getIntExtra("pos", 0); playSong(); } public void onClick(View v) { // TODO Auto-generated method stub switch (v.getId()) { case R.id.preBtn: preSong(); break; case R.id.nextBtn: nextSong(); break; case R.id.playBtn: playSong(); break; case R.id.pauseBtn: pauseSong(); break; default: break; } } //播放歌曲触发的动作 public void playSong() { try { if (indexChange) { mp.reset(); mp.setDataSource(songList.get(curPlayIndex).getSongPath()); mp.prepare(); skBar.setMax(mp.getDuration()); //设置title setTitle(); //设置图片背景 igView.setBackgroundResource(songList.get(curPlayIndex).getSongPhoto()); } mp.start(); indexChange = false; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public void pauseSong() { if(mp.isPlaying()) { mp.pause(); } } public void nextSong() { if(curPlayIndex!=songList.size()-1) { curPlayIndex++; indexChange=true; playSong(); } } public void preSong() { if(curPlayIndex!=0) { curPlayIndex--; indexChange=true; playSong(); } } public void stopSong() { mp.stop(); mp.release(); } /* (non-Javadoc) * @see android.app.Activity#onKeyUp(int, android.view.KeyEvent) */ @Override public boolean onKeyUp(int keyCode, KeyEvent event) { // TODO Auto-generated method stub if(keyCode == KeyEvent.KEYCODE_BACK) { this.finish(); return true; } return super.onKeyUp(keyCode, event); } public void setTitle() { String nextSongName = curPlayIndex == songList.size()-1?"无":songList.get(curPlayIndex+1).getSongName(); tView.setText("正在播放:"+songList.get(curPlayIndex).getSongName()+"\n接着要播放:"+nextSongName); }}
6.SongBean文件,截个图吧
7.SongControl文件...封装一些方法
public class SongControl { private ArrayList<SongBean> songList; private MediaPlayer mp; private final int[] Images = new int[] {R.drawable.b1,R.drawable.b2}; public static SongControl newInstance() { SongControl sc = new SongControl(); sc.songList = new ArrayList<SongBean>(); sc.mp = new MediaPlayer(); return sc; } //获取SD卡的路径 public String getRootPath() { if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { return Environment.getExternalStorageDirectory().getPath(); } else { return "/"; } } //获取所有歌曲列表 public ArrayList<SongBean> getSongList() { return loadData(getRootPath(),new FileFilter() { public boolean accept(File pathname) { // TODO Auto-generated method stub return pathname.getPath().endsWith("mp3"); } }); } //加载数据 public ArrayList<SongBean> loadData(String path,FileFilter myFilter) { int index = 0; File fileSet = new File(path); if(fileSet.exists()&&fileSet.isDirectory()) { for(File file : fileSet.listFiles(myFilter)) { SongBean sb = new SongBean(); sb.setSongName(file.getName()); sb.setSinger("hjq"); sb.setSongDuration(getSongTime(file.getPath())); sb.setSongPath(file.getPath()); sb.setSongPhoto(Images[index]); songList.add(sb); index++; } return songList; } else { return null; } } //获取歌曲的时间 public String getSongTime(String path) { mp.reset(); try { mp.setDataSource(path); mp.prepare(); int times = mp.getDuration()/1000; int hour = 0; int min = 0; int sec = 0 ; if(times>3600) { hour = times/3600; times%=3600; } if(times>60) { min = times/60; times%=60; sec = times; } return 0==hour?hour+":"+min+":"+sec:min+":"+sec; } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalStateException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; }
那个适配器的话,很简单,就不贴上了....
哎,不容易啊,看来还有很长的路要走....