Trong hướng dẫn này tôi sẽ thảo luận xây dựng một máy nghe nhạc âm thanh với các điều khiển cơ bản đơn giản như chơi, tạm dừng, chuyển tiếp, quay lại, tiếp theo, trước đó, danh sách nhạc và seekbar. Ứng dụng này về cơ bản sẽ đọc tất cả các tập tin âmthanh (mp3) từ sdcard và chơi bài hát lựa chọn. Đối với hướng dẫn này, tôi đang tham khảo MediaPlayer và đi qua nó nếu bạn cần bất kỳ tài liệu về cách sử dụng.
Mặc dù tài liệu tiếng anh nhưng mình nghĩ tut thực sự rất dễ hiểu,cũng khá là dễ đọc. Timtailieu.vn hi vọng với TUT này thì các bạn mới học lập trình android cũng có thể tự xây dựng cho mình một ứng dụng media cho riêng mình.
                
              
                                            
                                
            
                       
            
                 33 trang
33 trang | 
Chia sẻ: diunt88 | Lượt xem: 3408 | Lượt tải: 1 
              
            Bạn đang xem trước 20 trang tài liệu TUT hướng dẫn xây dựng ứng dụng Media Player trên Android, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
 Sưu tầm và convert bởi TVDT 
Android Building Audio Player Tutorial 
In this tutorial i am going to discuss building a simple audio player with basic controls like play, 
pause, forward, backward, next, previous, playlist and seekbar. This app basically will read all audio 
files(.mp3) from sdcard and plays selected song. For this tutorial i am referencing MediaPlayer and 
go through it if you need any documentation about usage. 
Android MediaPlayer Class 
Android SDK is providing MediaPlayer Class to access android in built mediaplayer services like 
playing audio, video etc., In this tutorial i am using following functions of this class to control audio 
player. 
MediaPlayer mp = new MediaPlayer(); 
// Set data source - 
setDataSource("/sdcard/path_to_song"); 
// Play audio 
mp.start(); 
// Pause audio 
mp.pause(); 
// Reset mediaplayer 
mp.reset(); 
// Get song length duration - in milliseconds 
mp.getDuration(); 
// Get current duration - in milliseconds 
mp.getCurrentDuration(); 
// Move song to particular second - used for Forward or Backward 
mp.seekTo(positon); // position in milliseconds 
// Check if song is playing or not 
mp.isPlaying(); // returns true or false 
 Sưu tầm và convert bởi TVDT 
1. Designing the Audio Player Layout 
Design your audio player using some graphic designing softwares like photoshop. I used photoshop 
to design this app layout. If you are not aware of designing just download the required images from 
the internet. Following is a screenshot of the audio player which we are going to build in this tutorial. 
(You can find this layout PSD in the download code) 
 Sưu tầm và convert bởi TVDT 
2. Preparing Required Icons and Images 
Once you are done with your app layout design, prepare the required icons and background images 
for the audio player application. Prepare your icons in different states like default, focused and 
pressed and place them all in your drawable folder. 
 Sưu tầm và convert bởi TVDT 
3. Writing XML layouts for ICON states 
(default/hover/pressed) 
After saving all the icons with different states, we need to write xml drawable for each icon. Following 
is a sample for play button. Save this file under drawable folder. 
btn_play.xml 
 <item android:drawable="@drawable/img_btn_play_pressed" 
 android:state_focused="true" 
 android:state_pressed="true" /> 
 <item android:drawable="@drawable/img_btn_play_pressed" 
 android:state_focused="false" 
 android:state_pressed="true" /> 
 <item android:drawable="@drawable/img_btn_play_pressed" 
 android:state_focused="true" /> 
 <item android:drawable="@drawable/img_btn_play" 
 android:state_focused="false" 
 android:state_pressed="false" /> 
Note: You need to write xml drawable for each icon you used for the player 
(likebtn_pause.xml, btn_next.xml etc,.) 
4. Writing XML design for SeekBar 
In this tutorial i used customized SeekBar to show song progress. You can design the style of default 
SeekBar using xml styles. In your drawable folder create to xml files and type the following code. 
Changing SeekBar background: 
seekbar_progress_bg.xml 
 <bitmap xmlns:android="" 
 android:src="@drawable/img_seekbar_progress_blue" 
 android:tileMode="repeat" 
 android:antialias="true" 
 android:dither="false" 
 android:filter="false" 
 android:gravity="left" 
 /> 
 Sưu tầm và convert bởi TVDT 
Changing SeekBar Progress: 
seekbar_progress.xml 
 <item android:id="@android:id/background" 
 android:drawable="@drawable/img_seekbar_bg" 
 android:dither="true"> 
 <gradient 
 android:startColor="#80028ac8" 
 android:centerColor="#80127fb1" 
 android:centerY="0.75" 
 android:endColor="#a004638f" 
 android:angle="270" 
 /> 
 <item 
 android:id="@android:id/progress" 
 android:drawable="@drawable/seekbar_progress_bg" 
 /> 
Actual seekbar which uses above xml files: 
<SeekBar 
 android:id="@+id/songProgressBar" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:layout_marginRight="20dp" 
 android:layout_marginLeft="20dp" 
 android:layout_marginBottom="20dp" 
 android:layout_above="@id/player_footer_bg" 
 android:thumb="@drawable/seek_handler" 
 android:progressDrawable="@drawable/seekbar_progress" 
 android:paddingLeft="6dp" 
 android:paddingRight="6dp"/> 
5. Writing XML for Player Layout 
So far we created separate xml layout for all the icons, seekbar. Now we need to combine 
everything into single layout. Create a new file called player.xml under layout folder and paste the 
following code. 
 Sưu tầm và convert bởi TVDT 
player.xml 
<RelativeLayout xmlns:android="" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:background="@color/player_background"> 
 <LinearLayout 
 android:id="@+id/player_header_bg" 
 android:layout_width="fill_parent" 
 android:layout_height="60dip" 
 android:background="@layout/bg_player_header" 
 android:layout_alignParentTop="true" 
 android:paddingLeft="5dp" 
 android:paddingRight="5dp"> 
 <TextView 
 android:id="@+id/songTitle" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:layout_weight="1" 
 android:textColor="#04b3d2" 
 android:textSize="16dp" 
 android:paddingLeft="10dp" 
 android:textStyle="bold" 
 android:text="The Good, The Bad And The Ugly" 
 android:layout_marginTop="10dp"/> 
 <ImageButton 
 android:id="@+id/btnPlaylist" 
 android:layout_width="wrap_content" 
 android:layout_height="fill_parent" 
 android:src="@drawable/btn_playlist" 
 android:background="@null"/> 
 <LinearLayout 
 android:id="@+id/songThumbnail" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:paddingTop="10dp" 
 android:paddingBottom="10dp" 
 android:gravity="center" 
 android:layout_below="@id/player_header_bg"> 
 <ImageView android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:src="@drawable/adele"/> 
 <LinearLayout 
 Sưu tầm và convert bởi TVDT 
 android:id="@+id/player_footer_bg" 
 android:layout_width="fill_parent" 
 android:layout_height="100dp" 
 android:layout_alignParentBottom="true" 
 android:background="@layout/bg_player_footer" 
 android:gravity="center"> 
 <LinearLayout 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:orientation="horizontal" 
 android:gravity="center_vertical" 
 android:background="@layout/rounded_corner" 
 android:paddingLeft="10dp" 
 android:paddingRight="10dp"> 
 <ImageButton 
 android:id="@+id/btnPrevious" 
 android:src="@drawable/btn_previous" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:background="@null"/> 
 <ImageButton 
 android:id="@+id/btnBackward" 
 android:src="@drawable/btn_backward" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:background="@null"/> 
 <ImageButton 
 android:id="@+id/btnPlay" 
 android:src="@drawable/btn_play" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:background="@null"/> 
 <ImageButton 
 android:id="@+id/btnForward" 
 android:src="@drawable/btn_forward" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:background="@null"/> 
 <ImageButton 
 android:id="@+id/btnNext" 
 android:src="@drawable/btn_next" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:background="@null"/> 
 <SeekBar 
 Sưu tầm và convert bởi TVDT 
 android:id="@+id/songProgressBar" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:layout_marginRight="20dp" 
 android:layout_marginLeft="20dp" 
 android:layout_marginBottom="20dp" 
 android:layout_above="@id/player_footer_bg" 
 android:thumb="@drawable/seek_handler" 
 android:progressDrawable="@drawable/seekbar_progress" 
 android:paddingLeft="6dp" 
 android:paddingRight="6dp"/> 
 <LinearLayout 
 android:id="@+id/timerDisplay" 
 android:layout_above="@id/songProgressBar" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:layout_marginRight="20dp" 
 android:layout_marginLeft="20dp" 
 android:layout_marginBottom="10dp"> 
 <TextView 
 android:id="@+id/songCurrentDurationLabel" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:layout_weight="1" 
 android:gravity="left" 
 android:textColor="#eeeeee" 
 android:textStyle="bold"/> 
 <TextView 
 android:id="@+id/songTotalDurationLabel" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:layout_weight="1" 
 android:gravity="right" 
 android:textColor="#04cbde" 
 android:textStyle="bold"/> 
 <LinearLayout 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:layout_above="@id/timerDisplay" 
 android:gravity="center"> 
 <ImageButton 
 android:id="@+id/btnRepeat" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:src="@drawable/btn_repeat" 
 android:layout_marginRight="5dp" 
 android:background="@null"/> 
 Sưu tầm và convert bởi TVDT 
 <ImageButton 
 android:id="@+id/btnShuffle" 
 android:layout_width="wrap_content" 
 android:layout_height="wrap_content" 
 android:src="@drawable/btn_shuffle" 
 android:layout_marginLeft="5dp" 
 android:background="@null"/> 
The above xml will give following output layout. 
6. Writing XML for PlayList ListView 
Playlist is displayed using a listview. If you are not aware of listview go through this Android ListView 
Tutorial and get an idea of listview layout. 
 Sưu tầm và convert bởi TVDT 
⇒ Create an xml file under drawable folder and name it as list_selector.xml and type following 
code. This xml is used for gradient background for list item. 
list_selector.xml 
<item 
 android:state_selected="false" 
 android:state_pressed="false" 
 android:drawable="@drawable/gradient_bg" /> 
<item android:state_pressed="true" 
 android:drawable="@drawable/gradient_bg_hover" /> 
<item android:state_selected="true" 
 android:state_pressed="false" 
 android:drawable="@drawable/gradient_bg_hover" /> 
⇒ Create a new xml file under layout layout folder and name it as playlist.xml and type the 
following code. This xml file is for listview. 
playlist.xml 
<LinearLayout xmlns:android="" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:orientation="vertical"> 
 <ListView 
 android:id="@android:id/list" 
 android:layout_width="fill_parent" 
 android:layout_height="fill_parent" 
 android:divider="#242424" 
 android:dividerHeight="1dp" 
 android:listSelector="@drawable/list_selector" /> 
⇒ Also create a new xml file under layout folder for single List Item. Name file 
asplaylist_item.xml and type following code. This xml file is for single list item which holds song 
title. 
playlist_item.xml 
<LinearLayout xmlns:android="" 
 android:layout_width="match_parent" 
 android:layout_height="match_parent" 
 android:orientation="vertical" 
 android:gravity="center" 
 android:background="@drawable/list_selector" 
 android:padding="5dp"> 
 <TextView 
 Sưu tầm và convert bởi TVDT 
 android:id="@+id/songTitle" 
 android:layout_width="fill_parent" 
 android:layout_height="wrap_content" 
 android:textSize="16dp" 
 android:padding="10dp" 
 android:color="#f3f3f3"/> 
By using above layout we can achieve following list view by loading data into it. 
7. Writing Class for reading MP3 files from 
SDcard 
So far we are done with static layouts for the player. Now the actual code starts. 
Create a new class file and name it as SongsManager.java. This class will read all the files from 
device sdcard and filters the files which are having .mp3 extension. 
 Sưu tầm và convert bởi TVDT 
SongsManager.mp3 
package com.androidhive.musicplayer; 
import java.io.File; 
import java.io.FilenameFilter; 
import java.util.ArrayList; 
import java.util.HashMap; 
public class SongsManager { 
 // SDCard Path 
 final String MEDIA_PATH = new String("/sdcard/"); 
 private ArrayList> songsList = new ArrayList<HashMap<String, 
String>>(); 
 // Constructor 
 public SongsManager(){ 
 } 
 /** 
 * Function to read all mp3 files from sdcard 
 * and store the details in ArrayList 
 * */ 
 public ArrayList> getPlayList(){ 
 File home = new File(MEDIA_PATH); 
 if (home.listFiles(new FileExtensionFilter()).length > 0) { 
 for (File file : home.listFiles(new FileExtensionFilter())) { 
 HashMap song = new HashMap(); 
 song.put("songTitle", file.getName().substring(0, 
(file.getName().length() - 4))); 
 song.put("songPath", file.getPath()); 
 // Adding each song to SongList 
 songsList.add(song); 
 } 
 } 
 // return songs list array 
 return songsList; 
 } 
 /** 
 * Class to filter files which are having .mp3 extension 
 * */ 
 class FileExtensionFilter implements FilenameFilter { 
 public boolean accept(File dir, String name) { 
 return (name.endsWith(".mp3") || name.endsWith(".MP3")); 
 } 
 } 
} 
 Sưu tầm và convert bởi TVDT 
8. Writing Class for PlayList ListView 
Create a new Activity class for playlist listview. Name the file as PlayListActivity.java This class will 
display list of songs in list layout by using SongsManager.java class 
PlayListActivity.java 
package com.androidhive.musicplayer; 
import java.util.ArrayList; 
import java.util.HashMap; 
import android.app.ListActivity; 
import android.content.Intent; 
import android.os.Bundle; 
import android.view.View; 
import android.widget.AdapterView; 
import android.widget.AdapterView.OnItemClickListener; 
import android.widget.ListAdapter; 
import android.widget.ListView; 
import android.widget.SimpleAdapter; 
public class PlayListActivity extends ListActivity { 
 // Songs list 
 public ArrayList> songsList = new ArrayList<HashMap<String, 
String>>(); 
 @Override 
 public void onCreate(Bundle savedInstanceState) { 
 super.onCreate(savedInstanceState); 
 setContentView(R.layout.playlist); 
 ArrayList> songsListData = new ArrayList<HashMap<String, 
String>>(); 
 SongsManager plm = new SongsManager(); 
 // get all songs from sdcard 
 this.songsList = plm.getPlayList(); 
 // looping through playlist 
 for (int i = 0; i < songsList.size(); i++) { 
 // creating new HashMap 
 HashMap song = songsList.get(i); 
 // adding HashList to ArrayList 
 songsListData.add(song); 
 } 
 // Adding menuItems to ListView 
 ListAdapter adapter = new SimpleAdapter(this, songsListData, 
 R.layout.playlist_item, new String[] { "songTitle" }, new int[] { 
 R.id.songTitle }); 
 Sưu tầm và convert bởi TVDT 
 setListAdapter(adapter); 
 // selecting single ListView item 
 ListView lv = getListView(); 
 // listening to single listitem click 
 lv.setOnItemClickListener(new OnItemClickListener() { 
 @Override 
 public void onItemClick(AdapterView parent, View view, 
 int position, long id) { 
 // getting listitem index 
 int songIndex = position; 
 // Starting new intent 
 Intent in = new Intent(getApplicationContext(), 
 AndroidBuildingMusicPlayerActivity.class); 
 // Sending songIndex to PlayerActivity 
 in.putExtra("songIndex", songIndex); 
 setResult(100, in); 
 // Closing PlayListView 
 finish(); 
 } 
 }); 
 } 
} 
9. Helper Class functions 
Create a new class called Utilities.java for handling extra work like converting time to progress 
percentage and vice-versa. Also it has function to convert millisecond to a timer string which will 
displayed on the seekbar of the player. 
Utilities.java 
package com.androidhive.musicplayer; 
public class Utilities { 
 /** 
 * Function to convert milliseconds time to 
 * Timer Format 
 * Hours:Minutes:Seconds 
 * */ 
 public String milliSecondsToTimer(long milliseconds){ 
 String finalTimerString = ""; 
 String secondsString = ""; 
 // Convert total duration into time 
 int hours = (int)( milliseconds / (1000*60*60)); 
 int minutes = (int)(milliseconds % (1000*60*60)) / (1000*60); 
 int seconds = (int) ((milliseconds % (1000*60*60)) % (1000*60) 
 Sưu tầm và convert bởi TVDT 
/ 1000); 
 // Add hours if there 
 if(hours > 0){ 
 finalTimerString = hours + ":"; 
 } 
 // Prepending 0 to seconds if it is one digit 
 if(seconds < 10){ 
 secondsString = "0" + seconds; 
 }else{ 
 secondsString = "" + seconds;} 
 finalTimerString = finalTimerString + minutes + ":" + 
secondsString; 
 // return timer string 
 return finalTimerString; 
 } 
 /** 
 * Function to get Progress percentage 
 * @param currentDuration 
 * @param totalDuration 
 * */ 
 public int getProgressPercentage(long currentDuration, long 
totalDuration){ 
 Double percentage = (double) 0; 
 long currentSeconds = (int) (currentDuration / 1000); 
 long totalSeconds = (int) (totalDuration / 1000); 
 // calculating percentage 
 percentage =(((double)currentSeconds)/totalSeconds)*100; 
 // return percentage 
 return percentage.intValue(); 
 } 
 /** 
 * Function to change progress to timer 
 * @param progress - 
 * @param totalDuration 
 * returns current duration in milliseconds 
 * */ 
 public int progressToTimer(int progress, int totalDuration) { 
 int currentDuration = 0; 
 totalDuration = (int) (totalDuration / 1000); 
 currentDuration = (int) ((((double)progress) / 100) * 
totalDuration); 
 // return current duration in milliseconds 
 return currentDuration * 1000; 
 } 
} 
 Sưu tầm và convert bởi TVDT 
7. Writing Classes needed for Audio Player 
Open your main activity class which deals with main player interface and make the 
classimplements from OnCompletionListener, SeekBar.OnSeekBarChangeListener. 
In this case my main activity name is AndroidBuildingMusicPlayerActivity. 
AndroidBuildingMusicPlayerActivity.java 
public class AndroidBuildingMusicPlayerActivity extends Activity 
 implements OnCompletionListener, SeekBar.OnSeekBarChangeListener { 
Now declare all variable needed for this audio player class. 
AndroidBuildingMusicPlayerActivity.java 
public class AndroidBuildingMusicPlayerActivity extends Activity 
 implements OnCompletionListener, SeekBar.OnSeekBarChangeListener { 
 private ImageButton btnPlay; 
 private ImageButton btnForward; 
 private ImageButton btnBackward; 
 private ImageButton btnNext; 
 private ImageButton btnPrevious; 
 private ImageButton btnPlaylist; 
 private ImageButton btnRepeat; 
 private ImageButton btnShuffle; 
 private SeekBar songProgressBar; 
 private TextView songTitleLabel; 
 private TextView songCurrentDurationLabel; 
 private TextView songTotalDurationLabel; 
 // Media Player 
 private MediaPlayer mp; 
 // Handler to update UI timer, progress bar etc,. 
 private Handler mHandler = new Handler();; 
 private SongsManager songManager; 
 private Utilities utils; 
 private int seekForwardTime = 5000; // 5000 milliseconds 
 private int seekBackwardTime = 5000; // 5000 milliseconds 
 private int currentSongIndex = 0; 
 private boolean isShuffle = false; 
 private boolean isRepeat = false; 
 private ArrayList> songsList = new ArrayList<HashMap<String, 
String>>(); 
Now reference all buttons, images from xml layout to class. 
AndroidBuildingMusicPlayerActivity.java 
// All player buttons 
 btnPlay = (ImageButton) findViewById(R.id.btnPlay); 
 btnForward = (ImageButton) findViewById(R.id.btnForward); 
 btnBackward = (ImageButton) findViewById(R.id.btnBackward); 
 Sưu tầm và convert bởi TVDT 
 btnNext = (ImageButton) findViewById(R.id.btnNext); 
 btnPrevious = (ImageButton) findV