天天看點

Android開發音樂播放器

音樂播放器中綜合了以下内容:

SeekBar、ListView、廣播接收者(以代碼的形式注冊Receiver)、系統服務、MediaPlayer

實作的功能:

1.暫停/播放、下一首/上一首,點選某一首時播放

2.支援拖動進度條快進

3.清單排序

4.來電話時,停止播放,挂斷後繼續播放

5.可在背景播放

效果圖:

Android開發音樂播放器

界面:

main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
	<TextView  
		android:id="@+id/name"
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    />
	<SeekBar
		android:id="@+id/seekBar"
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:layout_marginBottom="5dp"
		/>
	<LinearLayout
	    android:layout_width="fill_parent" 
	    android:layout_height="wrap_content" 
	    android:layout_marginBottom="20dp"
		>
		<Button
		    android:layout_width="40dp" 
		    android:layout_height="40dp" 
		    android:text="|◀"
		    android:onClick="previous"
			/>
		<Button
			android:id="@+id/pp"
		    android:layout_width="40dp" 
		    android:layout_height="40dp" 
		    android:text="▶"
		    android:onClick="pp"
			/>
		<Button
		    android:layout_width="40dp" 
		    android:layout_height="40dp" 
		    android:text="▶|"
		    android:onClick="next"
			/>
	</LinearLayout>
	<ListView
		android:id="@+id/list"
		android:layout_width="fill_parent" 
		android:layout_height="fill_parent" 
		/>
</LinearLayout>
           

item.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:padding="10dp"
	>
	<TextView
		android:id="@+id/mName"
		android:layout_width="fill_parent"
		android:layout_height="wrap_content"
		android:textSize="15sp"
		/>
</LinearLayout>
           

MainActivity:

package cn.test.audio;

import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
import android.view.View;
import android.widget.AdapterView;
import android.widget.Button;
import android.widget.ListView;
import android.widget.SeekBar;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.SeekBar.OnSeekBarChangeListener;

public class MainActivity extends Activity {
	private TextView nameTextView;
	private SeekBar seekBar;
	private ListView listView;
	private List<Map<String, String>> data;
	private int current;
	private MediaPlayer player;
	private Handler handler = new Handler();
	private Button ppButton;
	private boolean isPause;
	private boolean isStartTrackingTouch;

	public void onCreate(Bundle savedInstanceState) { 
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		nameTextView = (TextView) findViewById(R.id.name);
		seekBar = (SeekBar) findViewById(R.id.seekBar);
		listView = (ListView) findViewById(R.id.list);
		ppButton = (Button) findViewById(R.id.pp);
		
		//建立一個音樂播放器
		player = new MediaPlayer();

		//顯示音樂播放清單
		generateListView();

		//進度條監聽器
		seekBar.setOnSeekBarChangeListener(new MySeekBarListener());
		
		//播放器監聽器
		player.setOnCompletionListener(new MyPlayerListener());

		//意圖過濾器
		IntentFilter filter = new IntentFilter();
		
		//播出電話暫停音樂播放
		filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
		registerReceiver(new PhoneListener(), filter);

		//建立一個電話服務
		TelephonyManager manager = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		
		//監聽電話狀态,接電話時停止播放
		manager.listen(new MyPhoneStateListener(), PhoneStateListener.LISTEN_CALL_STATE);
	}

	/*
	 * 監聽電話狀态
	 */
	private final class MyPhoneStateListener extends PhoneStateListener {
		public void onCallStateChanged(int state, String incomingNumber) {
			pause();
		}
	}

	/*
	 * 播放器監聽器
	 */
	private final class MyPlayerListener implements OnCompletionListener {
		//歌曲播放完後自動播放下一首歌曲
		public void onCompletion(MediaPlayer mp) {
			next();
		}
	}

	/*
	 * 下一首按鈕
	 */
	public void next(View view) {
		next();
	}

	/*
	 * 前一首按鈕
	 */
	public void previous(View view) {
		previous();
	}

	/*
	 * 播放前一首歌
	 */
	private void previous() {
		current = current - 1 < 0 ? data.size() - 1 : current - 1;
		play();
	}

	/*
	 * 播放下一首歌
	 */
	private void next() {
		current = (current + 1) % data.size();
		play();
	}

	/*
	 * 進度條監聽器
	 */
	private final class MySeekBarListener implements OnSeekBarChangeListener {
		//移動觸發
		public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
		}

		//起始觸發
		public void onStartTrackingTouch(SeekBar seekBar) {
			isStartTrackingTouch = true;
		}

		//結束觸發
		public void onStopTrackingTouch(SeekBar seekBar) {
			player.seekTo(seekBar.getProgress());
			isStartTrackingTouch = false;
		}
	}

	/*
	 * 顯示音樂播放清單
	 */
	private void generateListView() {
		List<File> list = new ArrayList<File>();
		
		//擷取sdcard中的所有歌曲
		findAll(Environment.getExternalStorageDirectory(), list);
		
		//播放清單進行排序,字元順序
		Collections.sort(list);

		data = new ArrayList<Map<String, String>>();
		for (File file : list) {
			Map<String, String> map = new HashMap<String, String>();
			map.put("name", file.getName());
			map.put("path", file.getAbsolutePath());
			data.add(map);
		}

		SimpleAdapter adapter = new SimpleAdapter(this, data, R.layout.item, new String[] { "name" }, new int[] { R.id.mName });
		listView.setAdapter(adapter);

		listView.setOnItemClickListener(new MyItemListener());
	}

	private final class MyItemListener implements OnItemClickListener {
		public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
			current = position;
			play();
		}
	}

	
	private void play() {
		try {
			//重播
			player.reset();
			
			//擷取歌曲路徑
			player.setDataSource(data.get(current).get("path"));
			
			//緩沖
			player.prepare();
			
			//開始播放
			player.start();
			
			//顯示歌名
			nameTextView.setText(data.get(current).get("name"));
			
			//設定進度條長度
			seekBar.setMax(player.getDuration());

			//播放按鈕樣式
			ppButton.setText("||");

			//發送一個Runnable, handler收到之後就會執行run()方法
			handler.post(new Runnable() {
				public void run() {
					// 更新進度條狀态
					if (!isStartTrackingTouch)
						seekBar.setProgress(player.getCurrentPosition());
					// 1秒之後再次發送
					handler.postDelayed(this, 1000);
				}
			});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * 查找檔案路徑中所有mp3檔案
	 * @param file 要找的目錄
	 * @param list 用來裝檔案的List
	 */
	private void findAll(File file, List<File> list) {
		File[] subFiles = file.listFiles();
		if (subFiles != null)
			for (File subFile : subFiles) {
				if (subFile.isFile() && subFile.getName().endsWith(".mp3"))
					list.add(subFile);
				else if (subFile.isDirectory())//如果是目錄
					findAll(subFile, list); //遞歸
			}
	}

	/*
	 * 暫停/播放按鈕
	 */
	public void pp(View view) {
		
		//預設從第一首歌曲開始播放
		if (!player.isPlaying() && !isPause) {
			play();
			return;
		}

		Button button = (Button) view;
		//暫停/播放按鈕
		if ("||".equals(button.getText())) {
			pause();
			button.setText("▶");
		} else {
			resume();
			button.setText("||");
		}
	}

	/*
	 * 開始操作
	 */
	private void resume() {
		if (isPause) {
			player.start();
			isPause = false;
		}
	}

	/*
	 * 暫停操作
	 */
	private void pause() {
		if (player != null && player.isPlaying()) {
			player.pause();
			isPause = true;
		}
	}

	/*
	 * 收到廣播時暫停
	 */
	private final class PhoneListener extends BroadcastReceiver {
		public void onReceive(Context context, Intent intent) {
			pause();
		}
	}

	/*
	 * 恢複播放
	 * @see android.app.Activity#onResume()
	 */
	protected void onResume() {
		super.onResume();
		resume();
	}
}
           

注冊權限:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="cn.itcast.audio"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>
    <uses-sdk android:minSdkVersion="8" />
    
    <!-- 監聽電話呼出 -->
	<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS"/>
	<!-- 監聽電話狀态改變 -->
	<uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

</manifest>