这篇博客,是基于上一篇博客实现的,使用到了主要知识点有: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;
}
}
好了,今天的编写到此结束,明天我会继续完善音乐播放器,那好,大家晚安!