Android应用开发--MP3音乐播放器代码实现(二)

2013年5月25日 简、美音乐播放器开发

小巫在这里罗列这个播放器已经实现的功能:

1.   自动显示音乐列表

2.   点击列表播放音乐

3.   长按列表弹出对话框

4.   暂停音乐

5.   上一首音乐

6.   下一首音乐

7.   自动播放下一首歌曲

8.   单曲循环

9.   全部循环

10.  随机播放

 

以上所有功能将会分为两篇博文来讲解,首先是主界面的,接着是播放界面的。在这里要说明一点,以上功能是小巫自己一点一点调试才实现的,并不能完全排除考虑不周的地方,原本这个软件实现起来并不太难,但确实要考虑到很多细节的地方,播放状态的切换和控制就是一块,也花了我不少实现,之前还很苦恼实现自己想要的效果,但后来还是经过思考和调试把功能实现。所以说,开发是一个需要很耐心的过程,各位童鞋,如果真正喜欢编程的话,想要做出一些小作品的话,那就好好掂量自己的耐心吧,好了,废话不多说,先贴一大段代码,后面在慢慢把需要注意的地方说一下。

主界面效果图:

            

以上界面的效果怎么实现的?

很简单的,就是ListView的数据填充,但要填的的东西就要考虑了,怎么把数据从SQLite中获取,小巫封装了一个工具类,用来获取与MP3相关的数据。

==>MediaUtils

  1. package com.wwj.sb.utils;  
  2.   
  3. import java.util.ArrayList;  
  4. import java.util.HashMap;  
  5. import java.util.Iterator;  
  6. import java.util.List;  
  7.   
  8. import android.content.Context;  
  9. import android.database.Cursor;  
  10. import android.provider.MediaStore;  
  11.   
  12. import com.wwj.sb.domain.Mp3Info;  
  13.   
  14. public class MediaUtil {  
  15.     /** 
  16.      * 用于从数据库中查询歌曲的信息,保存在List当中 
  17.      *  
  18.      * @return 
  19.      */  
  20.     public static List<Mp3Info> getMp3Infos(Context context) {  
  21.         Cursor cursor = context.getContentResolver().query(  
  22.                 MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, nullnullnull,  
  23.                 MediaStore.Audio.Media.DEFAULT_SORT_ORDER);  
  24.         List<Mp3Info> mp3Infos = new ArrayList<Mp3Info>();  
  25.         for (int i = 0; i < cursor.getCount(); i++) {  
  26.             cursor.moveToNext();  
  27.             Mp3Info mp3Info = new Mp3Info();  
  28.             long id = cursor.getLong(cursor  
  29.                     .getColumnIndex(MediaStore.Audio.Media._ID));               //音乐id  
  30.             String title = cursor.getString((cursor   
  31.                     .getColumnIndex(MediaStore.Audio.Media.TITLE)));            //音乐标题  
  32.             String artist = cursor.getString(cursor  
  33.                     .getColumnIndex(MediaStore.Audio.Media.ARTIST));            //艺术家  
  34.             long duration = cursor.getLong(cursor  
  35.                     .getColumnIndex(MediaStore.Audio.Media.DURATION));          //时长  
  36.             long size = cursor.getLong(cursor  
  37.                     .getColumnIndex(MediaStore.Audio.Media.SIZE));              //文件大小  
  38.             String url = cursor.getString(cursor  
  39.                     .getColumnIndex(MediaStore.Audio.Media.DATA));              //文件路径  
  40.             int isMusic = cursor.getInt(cursor  
  41.                     .getColumnIndex(MediaStore.Audio.Media.IS_MUSIC));          //是否为音乐  
  42.             if (isMusic != 0) {     //只把音乐添加到集合当中  
  43.                 mp3Info.setId(id);  
  44.                 mp3Info.setTitle(title);  
  45.                 mp3Info.setArtist(artist);  
  46.                 mp3Info.setDuration(duration);  
  47.                 mp3Info.setSize(size);  
  48.                 mp3Info.setUrl(url);  
  49.                 mp3Infos.add(mp3Info);  
  50.             }  
  51.         }  
  52.         return mp3Infos;  
  53.     }  
  54.       
  55.     /** 
  56.      * 往List集合中添加Map对象数据,每一个Map对象存放一首音乐的所有属性 
  57.      * @param mp3Infos 
  58.      * @return 
  59.      */  
  60.     public static List<HashMap<String, String>> getMusicMaps(  
  61.             List<Mp3Info> mp3Infos) {  
  62.         List<HashMap<String, String>> mp3list = new ArrayList<HashMap<String, String>>();  
  63.         for (Iterator iterator = mp3Infos.iterator(); iterator.hasNext();) {  
  64.             Mp3Info mp3Info = (Mp3Info) iterator.next();  
  65.             HashMap<String, String> map = new HashMap<String, String>();  
  66.             map.put("title", mp3Info.getTitle());  
  67.             map.put("Artist", mp3Info.getArtist());  
  68.             map.put("duration", formatTime(mp3Info.getDuration()));  
  69.             map.put("size", String.valueOf(mp3Info.getSize()));  
  70.             map.put("url", mp3Info.getUrl());  
  71.             mp3list.add(map);  
  72.         }  
  73.         return mp3list;  
  74.     }  
  75.       
  76.     /** 
  77.      * 格式化时间,将毫秒转换为分:秒格式 
  78.      * @param time 
  79.      * @return 
  80.      */  
  81.     public static String formatTime(long time) {  
  82.         String min = time / (1000 * 60) + "";  
  83.         String sec = time % (1000 * 60) + "";  
  84.         if (min.length() < 2) {  
  85.             min = "0" + time / (1000 * 60) + "";  
  86.         } else {  
  87.             min = time / (1000 * 60) + "";  
  88.         }  
  89.         if (sec.length() == 4) {  
  90.             sec = "0" + (time % (1000 * 60)) + "";  
  91.         } else if (sec.length() == 3) {  
  92.             sec = "00" + (time % (1000 * 60)) + "";  
  93.         } else if (sec.length() == 2) {  
  94.             sec = "000" + (time % (1000 * 60)) + "";  
  95.         } else if (sec.length() == 1) {  
  96.             sec = "0000" + (time % (1000 * 60)) + "";  
  97.         }  
  98.         return min + ":" + sec.trim().substring(02);  
  99.     }  
  100. }  


好吧,来重头戏了,一大段代码来袭。

HomeActivity.Java

  1. package com.wwj.sb.activity;  
  2.   
  3. import java.util.HashMap;  
  4. import java.util.List;  
  5.   
  6. import android.app.Activity;  
  7. import android.app.AlertDialog;  
  8. import android.app.Service;  
  9. import android.content.BroadcastReceiver;  
  10. import android.content.Context;  
  11. import android.content.DialogInterface;  
  12. import android.content.Intent;  
  13. import android.content.IntentFilter;  
  14. import android.graphics.Color;  
  15. import android.os.Bundle;  
  16. import android.os.Vibrator;  
  17. import android.view.ContextMenu;  
  18. import android.view.ContextMenu.ContextMenuInfo;  
  19. import android.view.KeyEvent;  
  20. import android.view.View;  
  21. import android.view.View.OnClickListener;  
  22. import android.view.View.OnCreateContextMenuListener;  
  23. import android.view.ViewGroup.LayoutParams;  
  24. import android.widget.AdapterView;  
  25. import android.widget.AdapterView.OnItemClickListener;  
  26. import android.widget.ArrayAdapter;  
  27. import android.widget.Button;  
  28. import android.widget.ImageView;  
  29. import android.widget.ListView;  
  30. import android.widget.SimpleAdapter;  
  31. import android.widget.TextView;  
  32. import android.widget.Toast;  
  33.   
  34. import com.wwj.sb.domain.AppConstant;  
  35. import com.wwj.sb.domain.Mp3Info;  
  36. import com.wwj.sb.service.PlayerService;  
  37. import com.wwj.sb.utils.ConstantUtil;  
  38. import com.wwj.sb.utils.CustomDialog;  
  39. import com.wwj.sb.utils.MediaUtil;  
  40.   
  41. /** 
  42.  * 2013/5/7 
  43.  * 简、美音乐播放器 
  44.  * @author wwj 
  45.  *  
  46.  */  
  47. public class HomeActivity extends Activity {  
  48.     private ListView mMusiclist; // 音乐列表  
  49.     private List<Mp3Info> mp3Infos = null;  
  50.     private SimpleAdapter mAdapter; // 简单适配器  
  51.     private Button previousBtn; // 上一首  
  52.     private Button repeatBtn; // 重复(单曲循环、全部循环)  
  53.     private Button playBtn; // 播放(播放、暂停)  
  54.     private Button shuffleBtn; // 随机播放  
  55.     private Button nextBtn; // 下一首  
  56.     private TextView musicTitle;//歌曲标题  
  57.     private TextView musicDuration; //歌曲时间  
  58.     private Button musicPlaying;    //歌曲专辑  
  59.   
  60.     private int repeatState;        //循环标识  
  61.     private final int isCurrentRepeat = 1// 单曲循环  
  62.     private final int isAllRepeat = 2// 全部循环  
  63.     private final int isNoneRepeat = 3// 无重复播放  
  64.     private boolean isFirstTime = true;   
  65.     private boolean isPlaying; // 正在播放  
  66.     private boolean isPause; // 暂停  
  67.     private boolean isNoneShuffle = true// 顺序播放  
  68.     private boolean isShuffle = false// 随机播放  
  69.       
  70.       
  71.     private int listPosition = 0;   //标识列表位置  
  72.     private HomeReceiver homeReceiver;  //自定义的广播接收器  
  73.     //一系列动作  
  74.     public static final String UPDATE_ACTION = "com.wwj.action.UPDATE_ACTION";  
  75.     public static final String CTL_ACTION = "com.wwj.action.CTL_ACTION";  
  76.     public static final String MUSIC_CURRENT = "com.wwj.action.MUSIC_CURRENT";  
  77.     public static final String MUSIC_DURATION = "com.wwj.action.MUSIC_DURATION";  
  78.     public static final String REPEAT_ACTION = "com.wwj.action.REPEAT_ACTION";  
  79.     public static final String SHUFFLE_ACTION = "com.wwj.action.SHUFFLE_ACTION";  
  80.       
  81.       
  82.     private int currentTime;  
  83.     private int duration;  
  84.     @Override  
  85.     public void onCreate(Bundle savedInstanceState) {  
  86.         super.onCreate(savedInstanceState);  
  87.         setContentView(R.layout.home_activity_layout);  
  88.   
  89.         mMusiclist = (ListView) findViewById(R.id.music_list);  
  90.         mMusiclist.setOnItemClickListener(new MusicListItemClickListener());  
  91.         mMusiclist.setOnCreateContextMenuListener(new MusicListItemContextMenuListener());  
  92.         mp3Infos = MediaUtil.getMp3Infos(getApplicationContext());  //获取歌曲对象集合  
  93.         setListAdpter(MediaUtil.getMusicMaps(mp3Infos));    //显示歌曲列表  
  94.         findViewById();             //找到界面上的每一个控件  
  95.         setViewOnclickListener();   //为一些控件设置监听器  
  96.         repeatState = isNoneRepeat; // 初始状态为无重复播放状态  
  97.           
  98.           
  99.         homeReceiver = new HomeReceiver();  
  100.         // 创建IntentFilter  
  101.         IntentFilter filter = new IntentFilter();  
  102.         // 指定BroadcastReceiver监听的Action  
  103.         filter.addAction(UPDATE_ACTION);  
  104.         filter.addAction(MUSIC_CURRENT);  
  105.         filter.addAction(MUSIC_DURATION);  
  106.         filter.addAction(REPEAT_ACTION);  
  107.         filter.addAction(SHUFFLE_ACTION);  
  108.         // 注册BroadcastReceiver  
  109.         registerReceiver(homeReceiver, filter);  
  110.           
  111.   
  112.     }  
  113.   
  114.     /** 
  115.      * 从界面上根据id获取按钮 
  116.      */  
  117.     private void findViewById() {  
  118.         previousBtn = (Button) findViewById(R.id.previous_music);  
  119.         repeatBtn = (Button) findViewById(R.id.repeat_music);  
  120.         playBtn = (Button) findViewById(R.id.play_music);  
  121.         shuffleBtn = (Button) findViewById(R.id.shuffle_music);  
  122.         nextBtn = (Button) findViewById(R.id.next_music);  
  123.         musicTitle = (TextView) findViewById(R.id.music_title);  
  124.         musicDuration = (TextView) findViewById(R.id.music_duration);  
  125.         musicPlaying = (Button) findViewById(R.id.playing);  
  126.     }  
  127.   
  128.     /** 
  129.      * 给每一个按钮设置监听器 
  130.      */  
  131.     private void setViewOnclickListener() {  
  132.         ViewOnClickListener viewOnClickListener = new ViewOnClickListener();  
  133.         previousBtn.setOnClickListener(viewOnClickListener);  
  134.         repeatBtn.setOnClickListener(viewOnClickListener);  
  135.         playBtn.setOnClickListener(viewOnClickListener);  
  136.         shuffleBtn.setOnClickListener(viewOnClickListener);  
  137.         nextBtn.setOnClickListener(viewOnClickListener);  
  138.         musicPlaying.setOnClickListener(viewOnClickListener);  
  139.     }  
  140.   
  141.     private class ViewOnClickListener implements OnClickListener {  
  142.         Intent intent = new Intent();  
  143.         @Override  
  144.         public void onClick(View v) {  
  145.             switch (v.getId()) {  
  146.             case R.id.previous_music: // 上一首  
  147.                 playBtn.setBackgroundResource(R.drawable.play_selector);  
  148.                 isFirstTime = false;  
  149.                 isPlaying = true;  
  150.                 isPause = false;  
  151.                 previous();  
  152.                 break;  
  153.             case R.id.repeat_music: // 重复播放  
  154.                 if (repeatState == isNoneRepeat) {  
  155.                     repeat_one();  
  156.                     shuffleBtn.setClickable(false);  
  157.                     repeatState = isCurrentRepeat;  
  158.                 } else if (repeatState == isCurrentRepeat) {  
  159.                     repeat_all();  
  160.                     shuffleBtn.setClickable(false);  
  161.                     repeatState = isAllRepeat;  
  162.                 } else if (repeatState == isAllRepeat) {  
  163.                     repeat_none();  
  164.                     shuffleBtn.setClickable(true);  
  165.                     repeatState = isNoneRepeat;  
  166.                 }  
  167.                 switch (repeatState) {  
  168.                 case isCurrentRepeat: // 单曲循环  
  169.                     repeatBtn  
  170.                             .setBackgroundResource(R.drawable.repeat_current_selector);  
  171.                     Toast.makeText(HomeActivity.this, R.string.repeat_current,  
  172.                             Toast.LENGTH_SHORT).show();  
  173.                     break;  
  174.                 case isAllRepeat: // 全部循环  
  175.                     repeatBtn  
  176.                             .setBackgroundResource(R.drawable.repeat_all_selector);  
  177.                     Toast.makeText(HomeActivity.this, R.string.repeat_all,  
  178.                             Toast.LENGTH_SHORT).show();  
  179.                     break;  
  180.                 case isNoneRepeat: // 无重复  
  181.                     repeatBtn  
  182.                             .setBackgroundResource(R.drawable.repeat_none_selector);  
  183.                     Toast.makeText(HomeActivity.this, R.string.repeat_none,  
  184.                             Toast.LENGTH_SHORT).show();  
  185.                     break;  
  186.                 }  
  187.   
  188.                 break;  
  189.             case R.id.play_music: // 播放音乐  
  190.                 if(isFirstTime) {  
  191.                     play();  
  192.                     isFirstTime = false;  
  193.                     isPlaying = true;  
  194.                     isPause = false;  
  195.                 } else {  
  196.                     if (isPlaying) {  
  197.                         playBtn.setBackgroundResource(R.drawable.pause_selector);  
  198.                         intent.setAction("com.wwj.media.MUSIC_SERVICE");  
  199.                         intent.putExtra("MSG", AppConstant.PlayerMsg.PAUSE_MSG);  
  200.                         startService(intent);  
  201.                         isPlaying = false;  
  202.                         isPause = true;  
  203.                           
  204.                     } else if (isPause) {  
  205.                         playBtn.setBackgroundResource(R.drawable.play_selector);  
  206.                         intent.setAction("com.wwj.media.MUSIC_SERVICE");  
  207.                         intent.putExtra("MSG", AppConstant.PlayerMsg.CONTINUE_MSG);  
  208.                         startService(intent);  
  209.                         isPause = false;  
  210.                         isPlaying = true;  
  211.                     }  
  212.                 }  
  213.                 break;  
  214.             case R.id.shuffle_music: // 随机播放  
  215.                 if (isNoneShuffle) {  
  216.                     shuffleBtn  
  217.                             .setBackgroundResource(R.drawable.shuffle_selector);  
  218.                     Toast.makeText(HomeActivity.this, R.string.shuffle,  
  219.                             Toast.LENGTH_SHORT).show();  
  220.                     isNoneShuffle = false;  
  221.                     isShuffle = true;  
  222.                     shuffleMusic();  
  223.                     repeatBtn.setClickable(false);  
  224.                 } else if (isShuffle) {  
  225.                     shuffleBtn  
  226.                             .setBackgroundResource(R.drawable.shuffle_none_selector);  
  227.                     Toast.makeText(HomeActivity.this, R.string.shuffle_none,  
  228.                             Toast.LENGTH_SHORT).show();  
  229.                     isShuffle = false;  
  230.                     isNoneShuffle = true;  
  231.                     repeatBtn.setClickable(true);  
  232.                 }  
  233.                 break;  
  234.             case R.id.next_music: // 下一首  
  235.                 playBtn.setBackgroundResource(R.drawable.play_selector);  
  236.                 isFirstTime = false;  
  237.                 isPlaying = true;  
  238.                 isPause = false;  
  239.                 next();  
  240.                 break;  
  241.             case R.id.playing:  //正在播放  
  242.                 Mp3Info mp3Info = mp3Infos.get(listPosition);  
  243.                 Intent intent = new Intent(HomeActivity.this, PlayerActivity.class);  
  244.                 intent.putExtra("title", mp3Info.getTitle());     
  245.                 intent.putExtra("url", mp3Info.getUrl());  
  246.                 intent.putExtra("artist", mp3Info.getArtist());  
  247.                 intent.putExtra("listPosition", listPosition);  
  248.                 intent.putExtra("currentTime", currentTime);  
  249.                 intent.putExtra("duration", duration);  
  250.                 intent.putExtra("MSG", AppConstant.PlayerMsg.PLAYING_MSG);  
  251.                 startActivity(intent);  
  252.                 break;  
  253.             }  
  254.         }  
  255.     }  
  256.   
  257.     private class MusicListItemClickListener implements OnItemClickListener {  
  258.         /** 
  259.          * 点击列表播放音乐 
  260.          */  
  261.         @Override  
  262.         public void onItemClick(AdapterView<?> parent, View view, int position,  
  263.                 long id) {  
  264.             listPosition = position;  
  265.             playMusic(listPosition);          
  266.         }  
  267.   
  268.     }  
  269.       
  270.     public class MusicListItemContextMenuListener implements OnCreateContextMenuListener {  
  271.   
  272.         @Override  
  273.         public void onCreateContextMenu(ContextMenu menu, View v,  
  274.                 ContextMenuInfo menuInfo) {  
  275.             Vibrator vibrator = (Vibrator) getSystemService(Service.VIBRATOR_SERVICE);  
  276.             vibrator.vibrate(50);       //长按振动  
  277.             musicListItemDialog();      //长按后弹出的对话框  
  278.         }  
  279.   
  280.     }  
  281.   
  282.     /** 
  283.      * 填充列表 
  284.      *  
  285.      * @param mp3Infos 
  286.      */  
  287.     public void setListAdpter(List<HashMap<String, String>> mp3list) {  
  288.         mAdapter = new SimpleAdapter(this, mp3list,  
  289.                 R.layout.music_list_item_layout, new String[] { "title",  
  290.                         "Artist""duration" }, new int[] { R.id.music_title,  
  291.                         R.id.music_Artist, R.id.music_duration });  
  292.         mMusiclist.setAdapter(mAdapter);  
  293.     }  
  294.       
  295.       
  296.     /** 
  297.      * 下一首歌曲 
  298.      */  
  299.     public void next() {  
  300.         listPosition = listPosition + 1;  
  301.         if(listPosition <= mp3Infos.size() - 1) {  
  302.             Mp3Info mp3Info = mp3Infos.get(listPosition);  
  303.             musicTitle.setText(mp3Info.getTitle());  
  304.             Intent intent = new Intent();  
  305.             intent.setAction("com.wwj.media.MUSIC_SERVICE");  
  306.             intent.putExtra("listPosition", listPosition);  
  307.             intent.putExtra("url", mp3Info.getUrl());  
  308.             intent.putExtra("MSG", AppConstant.PlayerMsg.NEXT_MSG);  
  309.             startService(intent);  
  310.         } else {  
  311.             Toast.makeText(HomeActivity.this"没有下一首了", Toast.LENGTH_SHORT).show();  
  312.         }  
  313.     }  
  314.   
  315.     /** 
  316.      * 上一首歌曲 
  317.      */  
  318.     public void previous() {  
  319.         listPosition = listPosition - 1;  
  320.         if(listPosition >= 0) {  
  321.             Mp3Info mp3Info = mp3Infos.get(listPosition);  
  322.             musicTitle.setText(mp3Info.getTitle());  
  323.             Intent intent = new Intent();  
  324.             intent.setAction("com.wwj.media.MUSIC_SERVICE");  
  325.             intent.putExtra("listPosition", listPosition);  
  326.             intent.putExtra("url", mp3Info.getUrl());  
  327.             intent.putExtra("MSG", AppConstant.PlayerMsg.PRIVIOUS_MSG);  
  328.             startService(intent);  
  329.         }else {  
  330.             Toast.makeText(HomeActivity.this"没有上一首了", Toast.LENGTH_SHORT).show();  
  331.         }  
  332.     }  
  333.   
  334.     public void play() {  
  335.         playBtn.setBackgroundResource(R.drawable.play_selector);  
  336.         Mp3Info mp3Info = mp3Infos.get(listPosition);  
  337.         musicTitle.setText(mp3Info.getTitle());  
  338.         Intent intent = new Intent();  
  339.         intent.setAction("com.wwj.media.MUSIC_SERVICE");  
  340.         intent.putExtra("listPosition"0);  
  341.         intent.putExtra("url", mp3Info.getUrl());  
  342.         intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);  
  343.         startService(intent);  
  344.     }  
  345.       
  346.     /** 
  347.      * 单曲循环 
  348.      */  
  349.     public void repeat_one() {  
  350.         Intent intent = new Intent(CTL_ACTION);  
  351.         intent.putExtra("control"1);  
  352.         sendBroadcast(intent);  
  353.     }  
  354.       
  355.     /** 
  356.      * 全部循环 
  357.      */  
  358.     public void repeat_all() {  
  359.         Intent intent = new Intent(CTL_ACTION);  
  360.         intent.putExtra("control"2);  
  361.         sendBroadcast(intent);  
  362.     }  
  363.   
  364.     /** 
  365.      * 顺序播放 
  366.      */  
  367.     public void repeat_none() {  
  368.         Intent intent = new Intent(CTL_ACTION);  
  369.         intent.putExtra("control"3);  
  370.         sendBroadcast(intent);  
  371.     }  
  372.       
  373.     /** 
  374.      * 随机播放 
  375.      */  
  376.     public void shuffleMusic() {  
  377.         Intent intent = new Intent(CTL_ACTION);  
  378.         intent.putExtra("control"4);  
  379.         sendBroadcast(intent);  
  380.     }  
  381.   
  382.     public void musicListItemDialog() {  
  383.         String[] menuItems = new String[]{"播放音乐","设为铃声","查看详情"};  
  384.         ListView menuList = new ListView(HomeActivity.this);  
  385.         menuList.setCacheColorHint(Color.TRANSPARENT);  
  386.         menuList.setDividerHeight(1);  
  387.         menuList.setAdapter(new ArrayAdapter<String>(HomeActivity.this, R.layout.context_dialog_layout, R.id.dialogText, menuItems));  
  388.         menuList.setLayoutParams(new LayoutParams(ConstantUtil.getScreen(HomeActivity.this)[0] / 2, LayoutParams.WRAP_CONTENT));  
  389.           
  390.           
  391.         final CustomDialog customDialog = new CustomDialog.Builder(HomeActivity.this).setTitle(R.string.operation).setView(menuList).create();  
  392.         customDialog.show();  
  393.           
  394.         menuList.setOnItemClickListener( new OnItemClickListener() {  
  395.   
  396.             @Override  
  397.             public void onItemClick(AdapterView<?> parent, View view,  
  398.                     int position, long id) {  
  399.                 customDialog.cancel();  
  400.                 customDialog.dismiss();  
  401.             }  
  402.               
  403.         });  
  404.     }  
  405.     public void playMusic(int listPosition) {  
  406.         if (mp3Infos != null) {  
  407.             Mp3Info mp3Info = mp3Infos.get(listPosition);  
  408.             musicTitle.setText(mp3Info.getTitle());  
  409.             Intent intent = new Intent(HomeActivity.this, PlayerActivity.class);  
  410.             intent.putExtra("title", mp3Info.getTitle());     
  411.             intent.putExtra("url", mp3Info.getUrl());  
  412.             intent.putExtra("artist", mp3Info.getArtist());  
  413.             intent.putExtra("listPosition", listPosition);  
  414.             intent.putExtra("currentTime", currentTime);  
  415.             intent.putExtra("repeatState", repeatState);  
  416.             intent.putExtra("shuffleState", isShuffle);  
  417.             intent.putExtra("MSG", AppConstant.PlayerMsg.PLAY_MSG);  
  418.             startActivity(intent);  
  419.         }  
  420.     }  
  421.       
  422.     @Override  
  423.     protected void onStop() {  
  424.         // TODO Auto-generated method stub  
  425.         super.onStop();  
  426.     }  
  427.       
  428.       
  429.     @Override  
  430.     protected void onDestroy() {  
  431.         // TODO Auto-generated method stub  
  432.         super.onDestroy();  
  433.     }  
  434.       
  435.     /** 
  436.      * 按返回键弹出对话框确定退出 
  437.      */  
  438.     @Override  
  439.     public boolean onKeyDown(int keyCode, KeyEvent event) {  
  440.         if (keyCode == KeyEvent.KEYCODE_BACK  
  441.                 && event.getAction() == KeyEvent.ACTION_DOWN) {  
  442.   
  443.             new AlertDialog.Builder(this)  
  444.                     .setIcon(R.drawable.ic_launcher)  
  445.                     .setTitle("退出")  
  446.                     .setMessage("您确定要退出?")  
  447.                     .setNegativeButton("取消"null)  
  448.                     .setPositiveButton("确定",  
  449.                             new DialogInterface.OnClickListener() {  
  450.   
  451.                                 @Override  
  452.                                 public void onClick(DialogInterface dialog,  
  453.                                         int which) {  
  454.                                     finish();  
  455.                                     Intent intent = new Intent(  
  456.                                             HomeActivity.this,  
  457.                                             PlayerService.class);  
  458.                                     unregisterReceiver(homeReceiver);  
  459.                                     stopService(intent); // 停止后台服务  
  460.                                 }  
  461.                             }).show();  
  462.   
  463.         }  
  464.         return super.onKeyDown(keyCode, event);  
  465.     }  
  466.       
  467.       
  468.     //自定义的BroadcastReceiver,负责监听从Service传回来的广播  
  469.     public class HomeReceiver extends BroadcastReceiver {  
  470.   
  471.         @Override  
  472.         public void onReceive(Context context, Intent intent) {  
  473.             String action = intent.getAction();   
  474.             if(action.equals(MUSIC_CURRENT)){  
  475.                 //currentTime代表当前播放的时间  
  476.                 currentTime = intent.getIntExtra("currentTime", -1);  
  477.                 musicDuration.setText(MediaUtil.formatTime(currentTime));  
  478.             } else if (action.equals(MUSIC_DURATION)) {  
  479.                 duration = intent.getIntExtra("duration", -1);  
  480.             }  
  481.             else if(action.equals(UPDATE_ACTION)) {  
  482.                 //获取Intent中的current消息,current代表当前正在播放的歌曲  
  483.                 listPosition = intent.getIntExtra("current", -1);  
  484.                 if(listPosition >= 0) {  
  485.                     musicTitle.setText(mp3Infos.get(listPosition).getTitle());  
  486.                 }  
  487.             }else if(action.equals(REPEAT_ACTION)) {  
  488.                 repeatState = intent.getIntExtra("repeatState", -1);  
  489.                 switch (repeatState) {  
  490.                 case isCurrentRepeat: // 单曲循环  
  491.                     repeatBtn  
  492.                             .setBackgroundResource(R.drawable.repeat_current_selector);  
  493.                     shuffleBtn.setClickable(false);  
  494.                     break;  
  495.                 case isAllRepeat: // 全部循环  
  496.                     repeatBtn  
  497.                             .setBackgroundResource(R.drawable.repeat_all_selector);  
  498.                     shuffleBtn.setClickable(false);  
  499.                     break;  
  500.                 case isNoneRepeat: // 无重复  
  501.                     repeatBtn  
  502.                             .setBackgroundResource(R.drawable.repeat_none_selector);  
  503.                     shuffleBtn.setClickable(true);  
  504.                     break;  
  505.                 }  
  506.             }  
  507.             else if(action.equals(SHUFFLE_ACTION)) {  
  508.                 isShuffle = intent.getBooleanExtra("shuffleState"false);  
  509.                 if(isShuffle) {  
  510.                     isNoneShuffle = false;  
  511.                     shuffleBtn.setBackgroundResource(R.drawable.shuffle_selector);  
  512.                     repeatBtn.setClickable(false);  
  513.                 } else {  
  514.                     isNoneShuffle = true;  
  515.                     shuffleBtn.setBackgroundResource(R.drawable.shuffle_none_selector);  
  516.                     repeatBtn.setClickable(true);  
  517.                 }  
  518.             }  
  519.         }  
  520.           
  521.     }  
  522. }  


到这里,要开讲啦。

以下是需要注意的几点:

1. 音乐是通过Service来播放的,Activity通过启动服务来实现在后台播放音乐。

2. Activity中自定义了一个广播接收器,需要进行intent过滤器的定义,动作的添加,注册广播接收器:

  1. <span style="white-space:pre">      </span>homeReceiver = new HomeReceiver();  
  2.         // 创建IntentFilter  
  3.         IntentFilter filter = new IntentFilter();  
  4.         // 指定BroadcastReceiver监听的Action  
  5.         filter.addAction(UPDATE_ACTION);  
  6.         filter.addAction(MUSIC_CURRENT);  
  7.         filter.addAction(MUSIC_DURATION);  
  8.         filter.addAction(REPEAT_ACTION);  
  9.         filter.addAction(SHUFFLE_ACTION);  
  10.         // 注册BroadcastReceiver  
  11.         registerReceiver(homeReceiver, filter);  
  12.           


3. 在广播接收器类当中对动作进行处理,比如实现时间的更新和标题的更新等。

4. 这里还要注意按钮触发,播放状态的改变,比如音乐循环,有三种状态:单曲、全部循环、顺序,每切换一个状态都要向服务发送一条广播,通知它要改变状态。

5. 点击列表的时候,会跳入到播放界面的Activity中,要注意用intent来传递参数,注意每个参数的用途,比如title、url、MSG,就分别代表标题、路径、播放状态。

6. 长按列表会弹出自定义对话框,也会有短暂的震动效果,自定义对话框需要自行实现。这里我也贴一下实现代码吧。

  1. package com.wwj.sb.utils;  
  2.   
  3.   
  4. import android.app.Activity;  
  5. import android.app.Dialog;  
  6. import android.content.Context;  
  7. import android.content.DialogInterface;  
  8. import android.text.TextUtils;  
  9. import android.view.LayoutInflater;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.view.ViewGroup.LayoutParams;  
  13. import android.widget.Button;  
  14. import android.widget.FrameLayout;  
  15. import android.widget.ImageView;  
  16. import android.widget.LinearLayout;  
  17. import android.widget.TextView;  
  18.   
  19. import com.wwj.sb.activity.R;  
  20.   
  21. /** 
  22.  * 自定义对话框类 
  23.  *  
  24.  * @author wwj 
  25.  *  
  26.  */  
  27. public class CustomDialog extends Dialog {  
  28.   
  29.     public CustomDialog(Context context) {  
  30.         super(context);  
  31.     }  
  32.   
  33.     public CustomDialog(Context context, int theme) {  
  34.         super(context, theme);  
  35.     }  
  36.   
  37.     public static class Builder {  
  38.   
  39.         private Context context;  
  40.         private int mIcon = -1// 提示图标  
  41.         private CharSequence mTitle; // 提示标题  
  42.         private CharSequence mMessage; // 提示内容  
  43.         private CharSequence mPositiveButtonText; // 确定按钮文本  
  44.         private CharSequence mNegativeButtonText; // 取消按钮文本  
  45.         private CharSequence mNeutralButtonText; // 中间按钮文本  
  46.         private boolean mCancelable = true// 是否启用取消键  
  47.   
  48.         private int mViewSpacingLeft;  
  49.         private int mViewSpacingTop;  
  50.         private int mViewSpacingRight;  
  51.         private int mViewSpacingBottom;  
  52.         private boolean mViewSpacingSpecified = false;  
  53.   
  54.         // 提示内容View  
  55.         private View mView;  
  56.   
  57.         // 各种触发事件  
  58.         private OnClickListener mPositiveButtonClickListener,  
  59.                 mNegativeButtonClickListener, mNeutralButtonClickListener;  
  60.         private OnCancelListener mCancelListener; // 取消键事件  
  61.         private OnKeyListener mKeyListener; // 按键处理  
  62.   
  63.         public Builder(Context context) {  
  64.             this.context = context;  
  65.         }  
  66.   
  67.         public Builder setMessage(CharSequence message) {  
  68.             this.mMessage = message;  
  69.             return this;  
  70.         }  
  71.   
  72.         public Builder setMessage(int message) {  
  73.             this.mMessage = context.getText(message);  
  74.             return this;  
  75.         }  
  76.   
  77.         public Builder setTitle(int title) {  
  78.             this.mTitle = context.getText(title);  
  79.             return this;  
  80.         }  
  81.   
  82.         public Builder setTitle(CharSequence title) {  
  83.             this.mTitle = title;  
  84.             return this;  
  85.         }  
  86.   
  87.         public Builder setIcon(int icon) {  
  88.             this.mIcon = icon;  
  89.             return this;  
  90.         }  
  91.   
  92.         public Builder setView(View view) {  
  93.             this.mView = view;  
  94.             mViewSpacingSpecified = false;  
  95.             return this;  
  96.         }  
  97.   
  98.         public Builder setView(View view, int left, int top, int right,  
  99.                 int bottom) {  
  100.             this.mView = view;  
  101.             this.mViewSpacingLeft = left;  
  102.             this.mViewSpacingTop = top;  
  103.             this.mViewSpacingRight = right;  
  104.             this.mViewSpacingBottom = bottom;  
  105.             mViewSpacingSpecified = true;  
  106.             return this;  
  107.         }  
  108.   
  109.         public Builder setPositonButton(int textId,  
  110.                 final OnClickListener listener) {  
  111.             this.mPositiveButtonText = context.getText(textId);  
  112.             this.mPositiveButtonClickListener = listener;  
  113.             return this;  
  114.         }  
  115.   
  116.         public Builder setPostionButton(String text,  
  117.                 final OnClickListener listener) {  
  118.             this.mPositiveButtonText = text;  
  119.             this.mPositiveButtonClickListener = listener;  
  120.             return this;  
  121.         }  
  122.   
  123.         public Builder setNeutralButton(int textId,  
  124.                 final OnClickListener listener) {  
  125.             this.mNeutralButtonText = context.getText(textId);  
  126.             this.mNeutralButtonClickListener = listener;  
  127.             return this;  
  128.         }  
  129.           
  130.         public Builder setNeutralButton(String text, final OnClickListener listener) {  
  131.             this.mNeutralButtonText = text;  
  132.             this.mNeutralButtonClickListener = listener;  
  133.             return this;  
  134.         }  
  135.         public Builder setNegativeButton(int textId,  
  136.                 final OnClickListener listener) {  
  137.             this.mNegativeButtonText = context.getText(textId);  
  138.             this.mNegativeButtonClickListener = listener;  
  139.             return this;  
  140.         }  
  141.   
  142.         public Builder setNegativeButton(String text,  
  143.                 final OnClickListener listener) {  
  144.             this.mNegativeButtonText = text;  
  145.             this.mNegativeButtonClickListener = listener;  
  146.             return this;  
  147.         }  
  148.           
  149.           
  150.         public Builder setCancelable(boolean cancelable) {  
  151.             this.mCancelable = cancelable;  
  152.             return this;  
  153.         }  
  154.           
  155.         public Builder setOnCancelListener(OnCancelListener listener) {  
  156.             this.mCancelListener = listener;  
  157.             return this;  
  158.         }  
  159.           
  160.         public Builder setOnKeyListener(OnKeyListener listener) {  
  161.             this.mKeyListener = listener;  
  162.             return this;  
  163.         }  
  164.           
  165.         public CustomDialog create() {  
  166.             LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);  
  167.             final CustomDialog dialog = new CustomDialog(context, R.style.CustomDialog);  
  168.             dialog.setCancelable(mCancelable);  
  169.             //设置取消键事件  
  170.             if(mCancelListener != null) {  
  171.                 dialog.setOnCancelListener(mCancelListener);  
  172.             }  
  173.             //设置键盘监听事件  
  174.             if(mKeyListener != null) {  
  175.                 dialog.setOnKeyListener(mKeyListener);  
  176.             }  
  177.             //获取对话框布局  
  178.             View layout = inflater.inflate(R.layout.alert_dialog, (ViewGroup)(((Activity)context).findViewById(R.id.parentPanel)));  
  179.             layout.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));  
  180.               
  181.             //设置标题  
  182.             ((TextView) layout.findViewById(R.id.alertTitle)).setText(mTitle);  
  183.             //设置图标  
  184.             if(mIcon != -1) {  
  185.                 ((ImageView) layout.findViewById(R.id.icon))  
  186.                 .setBackgroundResource(mIcon);  
  187.             }  
  188.               
  189.             int count = 0;  
  190.             //设置确定按钮  
  191.             if(setButton(layout, mPositiveButtonText, R.id.button1, dialog, mPositiveButtonClickListener)) count++;  
  192.             // 设置拒绝按钮  
  193.             if(setButton(layout, mNegativeButtonText, R.id.button2, dialog, mNegativeButtonClickListener)) count++;  
  194.             // 设置中间按钮  
  195.             if(setButton(layout, mNeutralButtonText, R.id.button3, dialog, mNeutralButtonClickListener)) count++;  
  196.               
  197.             if(count == 0) {  
  198.                 layout.findViewById(R.id.buttonPanel).setVisibility(View.GONE);  
  199.             }  
  200.             //一个按钮时,显示两边空间  
  201.             if(count == 1) {  
  202.                 layout.findViewById(R.id.leftSpacer)  
  203.                     .setVisibility(View.INVISIBLE);  
  204.                 layout.findViewById(R.id.rightSpacer).setVisibility(View.INVISIBLE);  
  205.             }  
  206.             //设置提示消息  
  207.             if(!TextUtils.isEmpty(mMessage)) {  
  208.                 ((TextView)layout.findViewById(R.id.message))  
  209.                     .setText(mMessage);  
  210.             } else {  
  211.                 ((LinearLayout) layout.findViewById(R.id.contentPanel))  
  212.                     .setVisibility(View.GONE);  
  213.             }  
  214.             //设置提示内容布局  
  215.             if(mView != null) {  
  216.                 final FrameLayout customPanel = (FrameLayout) layout  
  217.                         .findViewById(R.id.customPanel);  
  218.                 if(mViewSpacingSpecified) {  
  219.                     customPanel.setPadding(mViewSpacingLeft, mViewSpacingTop, mViewSpacingRight, mViewSpacingBottom);  
  220.                 }  
  221.                 customPanel.addView(mView);  
  222.             } else {  
  223.                 ((FrameLayout) layout.findViewById(R.id.customPanel))  
  224.                             .setVisibility(View.GONE);  
  225.             }  
  226.             dialog.setContentView(layout);  
  227.             return dialog;  
  228.                   
  229.         }  
  230.           
  231.         public CustomDialog show() {  
  232.             CustomDialog dialog = create();  
  233.             dialog.show();  
  234.             return dialog;  
  235.         }  
  236.           
  237.         private boolean setButton(View layout, CharSequence mPositiveButtonText, int id, final Dialog dialog, final OnClickListener listener) {  
  238.             if(!TextUtils.isEmpty(mPositiveButtonText)) {  
  239.                 final Button button = (Button) layout.findViewById(id);  
  240.                 button.setText(mPositiveButtonText);  
  241.                 if(listener != null) {  
  242.                     button.setOnClickListener(new View.OnClickListener() {  
  243.                           
  244.                         @Override  
  245.                         public void onClick(View v) {  
  246.                             listener.onClick(dialog, DialogInterface.BUTTON_POSITIVE);  
  247.                         }  
  248.                     });  
  249.                 } else {  
  250.                     //默认事件为关闭对话框  
  251.                     button.setOnClickListener(new View.OnClickListener() {  
  252.                           
  253.                         @Override  
  254.                         public void onClick(View v) {  
  255.                             dialog.cancel();  
  256.                             dialog.dismiss();  
  257.                         }  
  258.                     });  
  259.                 }  
  260.                 return true;  
  261.             } else {  
  262.                 layout.findViewById(id).setVisibility(View.GONE);  
  263.                 return false;  
  264.             }  
  265.         }  
  266.     }  
  267. }  

关于主界面的业务逻辑具体实现和需要注意的地方,小巫已经说完了。其实最重要的是要写好服务类,下一篇播放将会给童鞋们介绍服务类的实现。最后感谢大家的关注。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值