这篇博客,是基于上一篇博客实现的,使用到了主要知识点有:Service,MediaPlayer。等。。。 好了,先说布局:
activity_main.xml
<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" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:gravity="center" android:text="@string/hello" /> <ListView android:id="@+id/Music_list" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > </ListView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal" > <Button android:id="@+id/button_start" style="@android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_start" /> <Button android:id="@+id/button_stop" style="@android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_stop" /> <Button android:id="@+id/button_loop" style="@android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_loop" /> <Button android:id="@+id/button_uplist" style="@android:attr/buttonBarButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/button_uplist" /> </LinearLayout> </LinearLayout>
这次因为用到了listView 所以要有一个Item布局
music_list_item.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/music_list_item" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <TextView android:id="@+id/music_name" android:layout_width="match_parent" android:layout_height="wrap_content" /> </LinearLayout>
配置文件添加两个权限,另外,因为用到了service,所以要添加service
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<service android:name=".MusicService" android:exported="true" > </service>
好,现在上主要代码,注释写的不是特别详细,我有些问题也是搞不懂,请轻喷
我这次采用了接口编程,那么,新建一个Path.java接口,代码如下
package com.android.MyMediaPlayer; import java.util.ArrayList; public interface Path { /** * 返回一个音乐名称数组 * @return */ public ArrayList<String> getMusicList(); /** * 返回一个音乐路径数组 * @return */ public ArrayList<String> getMusicPath(); }
实现这个接口
SongList.java
package com.android.MyMediaPlayer; import android.annotation.SuppressLint; import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; @SuppressLint("SdCardPath") public class SongList implements Path { // 用于保存歌曲名称 ArrayList<String> musicList = null; // 用于保存歌曲路径 ArrayList<String> musicPath = null; public static final String SD_PATH = "/sdcard/"; @Override public ArrayList<String> getMusicList() { musicList = new ArrayList<String>(); File home = new File(SD_PATH); if (home.listFiles(new mp3Filter()).length > 0) { for (File file : home.listFiles(new mp3Filter())) { musicList.add(file.getName()); } } return musicList; } @Override public ArrayList<String> getMusicPath() { musicPath = new ArrayList<String>(); if (musicList != null && musicList.size() > 0) { for (int i = 0; i < musicList.size(); i++) { musicPath.add(SD_PATH + musicList.get(i)); } } return musicPath; } private class mp3Filter implements FilenameFilter { @Override public boolean accept(File dir, String filename) { // TODO Auto-generated method stub return (filename.endsWith(".mp3")); } } }
好了,获取路径都写好了,接下来就可以写服务类了
MusicService.java
package com.android.MyMediaPlayer; import java.io.IOException; import android.app.Service; import android.content.Intent; import android.media.MediaPlayer; import android.net.Uri; import android.os.IBinder; import android.util.Log; public class MusicService extends Service { // 标识 public static final String TAG = "MusicService"; // 各种动作的标识 public static final String PLAY_ACTION = "com.android.MyMediaPlayer.PLAY_ACTION"; public static final String PAUSE_ACTION = "com.android.MyMediaPlayer.PAUSE_ACTION"; public static final String STOP_ACTION = "com.android.MyMediaPlayer.STOP_ACTION"; public static final String LOOP_ACTION = "com.android.MyMediaPlayer.LOOP_ACTION"; public static final String NOTLOOP_ACTION = "com.android.MyMediaPlayer.NOTLOOP_ACTION"; public static final String SONG_LIST = "com.android.MyMediaPlayer.SONG_LIST"; private MediaPlayer player; // 音乐地址 private Uri uri = null; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); init(); // 用log输出来了解service的生命周期 Log.d(TAG, "onCreate__"); } @SuppressWarnings({ "deprecation" }) @Override public void onStart(Intent intent, int startId) { super.onStart(intent, startId); // 将从Activity传来的值进行判断,在对这些动作进行操作 if (intent != null) { String action = intent.getAction(); if (action.equals(SONG_LIST)) { uri=intent.getData(); initByPath(uri); if (player.isPlaying()==true) { player.pause();; }else { play(); } } else if (action.equals(PLAY_ACTION)) { play(); } else if (action.equals(STOP_ACTION)) { stop(); } else if (action.equals(PAUSE_ACTION)) { pause(); } else if (action.equals(LOOP_ACTION)) { looping(true); } else if (action.equals(NOTLOOP_ACTION)) { looping(false); } } Log.d(TAG, "onStart__"); } private void looping(boolean b) { player.setLooping(b); } private void pause() { player.pause(); } private void stop() { player.stop(); player.reset(); try { // 必须调用prepare方法,不如停止之后不能再播放 player.prepare(); } catch (IllegalStateException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } private void play() { player.start(); } private void init() { player = new MediaPlayer();// 对象初始化 避免空指针异常 } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); player.stop(); player.pause(); } // 对象初始化 private void initByPath(Uri uri) { if (uri != null) { player = MediaPlayer.create(MusicService.this, uri); } } }
然后就是最关键的Activity了,在这个文件里,我加载了ListView,还写了一些其他东西。另外有一个BUG,我还没解决,这个BUG就是你重复点击一个listView的Item,会有多首歌同时播放。。。我知道问题出在item的点击事件里,但是我还没能解决,希望读者有解决方案可以告诉我,万分感谢。
MusicPlayer.java
package com.android.MyMediaPlayer; import java.util.ArrayList; import java.util.HashMap; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.content.Intent; import android.net.Uri; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.ListView; import android.widget.SimpleAdapter; import android.widget.Toast; public class MusicPlayer extends Activity { private Button button_start;// 开始 暂停按钮 private Button button_stop;// 停止按钮 private Button button_loop;// 重复按钮 private Button button_uplist;// 刷新列表 private ListView musicList;// 音乐列表 // 接口编程 private Path musicPath; // listView的适配器 private SimpleAdapter adapter; // 保存歌曲名的列表 private ArrayList<String> musicName = null; // 用于保存歌曲的路径 private ArrayList<String> music_Path = null; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 获取 ‘获取列表类’的实例 musicPath = new SongList(); findView(); setListener(); if (musicName == null) { // 如果为空加载listView upList(); } } private void setListener() { button_start.setOnClickListener(buttonListener); button_stop.setOnClickListener(buttonListener); button_loop.setOnClickListener(buttonListener); button_uplist.setOnClickListener(buttonListener); musicList.setOnItemClickListener(listItemListener); } private void upList() { // 获取播放歌曲的列表 musicName = musicPath.getMusicList(); // 获取歌曲路径 music_Path = musicPath.getMusicPath(); ArrayList<HashMap<String, Object>> ListItem = new ArrayList<HashMap<String, Object>>(); for (int i = 0; i < musicName.size(); i++) { HashMap<String, Object> map = new HashMap<String, Object>(); map.put("musicname", musicName.get(i)); // 暂时只用到歌曲名 ListItem.add(map); } // new适配器,为了扩展性 ,我采用了simpleAdapter adapter = new SimpleAdapter(MusicPlayer.this, ListItem, R.layout.music_list_item, new String[] { "musicname" }, new int[] { R.id.music_name }); musicList.setAdapter(adapter); } private OnItemClickListener listItemListener = new OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { if (music_Path != null) { String Path = music_Path.get(position); // 把按下Item之后得到的歌曲路径传给服务 Intent intent = new Intent(); intent.setClass(MusicPlayer.this, MusicService.class); intent.setAction(MusicService.SONG_LIST); Uri uri = Uri.parse(Path); intent.setData(uri); startService(intent); buttonListener.onClick(button_start); } } }; private OnClickListener buttonListener = new View.OnClickListener() { @Override public void onClick(View v) { switch (v.getId()) { // 根据刚刚setid进行按钮操作 case 0: // 根据点击按钮切换暂停继续 Intent intent_play = new Intent(MusicService.PLAY_ACTION); intent_play.setClass(MusicPlayer.this, MusicService.class); startService(intent_play); if (button_start.getText() == "暂停") { button_start.setText("播放"); Intent intent_pause = new Intent(MusicService.PAUSE_ACTION); intent_pause.setClass(MusicPlayer.this, MusicService.class); startService(intent_pause); } else { button_start.setText("暂停"); } break; case 1: if (button_start.getText() == "暂停") { button_start.setText("播放"); Intent intent_pause = new Intent(MusicService.PAUSE_ACTION); intent_pause.setClass(MusicPlayer.this, MusicService.class); startService(intent_pause); } Intent intent_stop = new Intent(MusicService.STOP_ACTION); intent_stop.setClass(MusicPlayer.this, MusicService.class); startService(intent_stop); break; case 2: Intent intent_loop = new Intent(MusicService.LOOP_ACTION); intent_loop.setClass(MusicPlayer.this, MusicService.class); startService(intent_loop); // 按下按钮 文字切换 if (button_loop.getText() == "取消重复") { button_loop.setText("重复"); Intent intent_notLoop = new Intent( MusicService.NOTLOOP_ACTION); intent_notLoop.setClass(MusicPlayer.this, MusicService.class); startService(intent_notLoop); Toast.makeText(MusicPlayer.this, "重复已关闭", Toast.LENGTH_SHORT).show(); } else { button_loop.setText("取消重复"); Toast.makeText(MusicPlayer.this, "重复已开启", Toast.LENGTH_SHORT).show(); } break; case 3: if (musicName == null) { // 如果为空加载listView upList(); } else { // 刷新listView adapter.notifyDataSetChanged(); } break; } } }; private void findView() { // 给每个按钮setid是为了监听按钮时分辨按钮 button_start = (Button) findViewById(R.id.button_start); button_start.setId(0); button_stop = (Button) findViewById(R.id.button_stop); button_stop.setId(1); button_loop = (Button) findViewById(R.id.button_loop); button_loop.setId(2); button_uplist = (Button) findViewById(R.id.button_uplist); button_uplist.setId(3); musicList = (ListView) findViewById(R.id.Music_list); } // 按下menu键会执行这个方法 @Override public boolean onCreateOptionsMenu(Menu menu) { // 增加两个选项 menu.add(0, 0, 0, R.string.menu_about); menu.add(0, 1, 0, R.string.menu_exit); return super.onCreateOptionsMenu(menu); } // 点击menu中的选项会执行这个方法 @Override public boolean onOptionsItemSelected(MenuItem item) { super.onOptionsItemSelected(item); switch (item.getItemId()) { case 0: // 创建新的dialog new AlertDialog.Builder(MusicPlayer.this) .setTitle(R.string.menu_about) .setMessage(R.string.about_message) .setPositiveButton(R.string.dialog_yes, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 不做任何处理 } }).show();// 要show 要不然显示不出 break; case 1: //系统关闭进程 android.os.Process.killProcess(android.os.Process.myPid()); finish(); Intent intent = new Intent(); stopService(intent); break; } return true; } }
好了,今天的编写到此结束,明天我会继续完善音乐播放器,那好,大家晚安!