update: 2016/08/10
reference:
1. Android MediaPlayer and VideoView Tutorial
2. [Android 開發] 裝置方向改變時,不重新創建 activity 的方法
A. Create a Project
1. 設定好專案相關資料後 > Next
> Next
B. Create raw folder to store audio files
1. res > New > Directory
C. Design the Interface:
1. 點選 activity_main.xml 檔案, 新增元件與 onClick 事件如下:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="cat.myhome.audioplayer.MainActivity">
<SeekBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/seekBar"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="<Max Time>"
android:id="@+id/textView_maxTime"
android:layout_below="@+id/seekBar"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_marginTop="38dp"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:gravity="center" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="<Current Position>"
android:id="@+id/textView_currentPosion"
android:layout_marginTop="65dp"
android:gravity="center"
android:layout_below="@+id/textView_maxTime"
android:layout_centerHorizontal="true" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="<<"
android:id="@+id/button_rewind"
android:layout_marginLeft="20dp"
android:layout_marginTop="93dp"
android:onClick="doRewind"
android:layout_below="@+id/textView_currentPosion"
android:layout_alignParentStart="true" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start"
android:id="@+id/button_start"
android:onClick="doStart"
android:layout_alignTop="@+id/button_rewind"
android:layout_toEndOf="@+id/button_rewind"
android:layout_marginLeft="30dp" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Pause"
android:id="@+id/button_pause"
android:onClick="doPause"
android:layout_alignTop="@+id/button_start"
android:layout_toStartOf="@+id/button_fastForward"
android:layout_marginRight="30dp" />
<Button
style="?android:attr/buttonStyleSmall"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=">>"
android:id="@+id/button_fastForward"
android:onClick="doFastForward"
android:layout_alignTop="@+id/button_pause"
android:layout_alignEnd="@+id/textView_maxTime"
android:layout_marginRight="20dp" />
</RelativeLayout>
-----------------------------------------------------------------------------------------------
D. When the device orientation changes, not re-created activity method
1. 開啟 AndroidManifest.xml 檔案, 修改如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="cat.myhome.audioplayer">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
p.s. screenSize : added in API level 13
-----------------------------------------------------------------------------------------------
E. 開啟 MainActivity.java 檔案, 修改如下:
package cat.myhome.audioplayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
//@AudioPlayer ------
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import android.media.MediaPlayer;
import android.os.Handler;
import java.util.concurrent.TimeUnit;
public class MainActivity extends AppCompatActivity {
//@AudioPlayer ------
private TextView textMaxTime;
private TextView textCurrentPosition;
private Button buttonPause;
private Button buttonStart;
private SeekBar seekBar;
private Handler threadHandler = new Handler();
private MediaPlayer mediaPlayer;
//@AudioPlayer: add variables ------
private int duration = 0;
private int currentPosition = 0;
private String maxTimeString = "";
private String currentTimeString = "";
//@AudioPlayer: data defined ------
// 5 second per step for Forward or Rewind
private int perTimeStep = 5000;
// 0.2 second for error allowed time: (duration - currentPosition)
private int errorAllowedTime = 200;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//@AudioPlayer ------
this.textMaxTime =(TextView) this.findViewById(R.id.textView_maxTime);
this.textCurrentPosition = (TextView)this.findViewById(R.id.textView_currentPosion);
this.buttonStart = (Button) this.findViewById(R.id.button_start);
this.buttonPause = (Button) this.findViewById(R.id.button_pause);
this.buttonPause.setEnabled(false);
this.seekBar = (SeekBar) this.findViewById(R.id.seekBar);
this.seekBar.setClickable(false);
// ID of 'mysong' in 'raw' folder
int songId = this.getRawResIdByName("marcus");
// Create MediaPlayer
this.mediaPlayer = MediaPlayer.create(this, songId);
//@AudioPlayer: set textMaxTime ------
this.duration = this.mediaPlayer.getDuration();//@update #######
this.maxTimeString = this.millisecondsToString(this.duration);
this.textMaxTime.setText(this.maxTimeString);
//@AudioPlayer: set CurrentPosition ------
this.currentPosition = this.mediaPlayer.getCurrentPosition();
this.currentTimeString = this.millisecondsToString(this.currentPosition);
this.textCurrentPosition.setText(this.currentTimeString);
//@AudioPlayer: set seekBar Max ------
this.seekBar.setMax(this.duration);
//@AudioPlayer: When the audio file ready for playback ------
this.mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mediaPlayer) {
mediaPlayer.seekTo(currentPosition);
mediaPlayer.start();
// Create a thread to update position of SeekBar
UpdateSeekBarThread updateSeekBarThread = new UpdateSeekBarThread();
threadHandler.postDelayed(updateSeekBarThread,50);
buttonPause.setEnabled(true);
buttonStart.setEnabled(false);
}
});
}
//@AudioPlayer: Find ID of resource in 'raw' folder ------
public int getRawResIdByName(String resName) {
String pkgName = this.getPackageName();
// Return 0 if not found.
int resID = this.getResources().getIdentifier(resName, "raw", pkgName);
return resID;
}
//@AudioPlayer: Convert millisecond to string ------
private String millisecondsToString(int milliseconds) {
long minutes = TimeUnit.MILLISECONDS.toMinutes((long) milliseconds);
long seconds = TimeUnit.MILLISECONDS.toSeconds((long) milliseconds) ;
//@AudioPlayer: update convert handle ------
seconds = seconds - (minutes * 60);
String minutesStr = "" + minutes;
String secondsStr = "" + seconds;
if(seconds < 10) {
secondsStr = "0" + seconds;
}
if(minutes < 10) {
minutesStr = "0" + minutes;
}
return minutesStr+":"+ secondsStr;
//return minutes+":"+ seconds;
}
//@AudioPlayer ------
public void doStart(View view) {
//@AudioPlayer: update ------
this.currentPosition = this.mediaPlayer.getCurrentPosition(); //@update ########
if(this.currentPosition == 0) {
//DO Nothing
} else if(this.currentPosition == this.duration) {
// Resets the MediaPlayer to its uninitialized state.
this.mediaPlayer.reset();
}
this.mediaPlayer.start();
// Create a thread to update position of SeekBar.
UpdateSeekBarThread updateSeekBarThread = new UpdateSeekBarThread();
threadHandler.postDelayed(updateSeekBarThread,50);
this.buttonPause.setEnabled(true);
this.buttonStart.setEnabled(false);
}
//@AudioPlayer: Thread to Update position for SeekBar ------
class UpdateSeekBarThread implements Runnable {
public void run() {
currentPosition = mediaPlayer.getCurrentPosition();
//duration = mediaPlayer.getDuration();
String currentPositionStr = millisecondsToString(currentPosition);
textCurrentPosition.setText(currentPositionStr);
seekBar.setProgress(currentPosition);
//if(currentPosition == duration) {
// errorAllowedTime = 0.2 second
if((currentPosition + errorAllowedTime) >= duration) {
buttonPause.setEnabled(false);
buttonStart.setEnabled(true);
}
// Delay thread 50 milisecond.
threadHandler.postDelayed(this, 50);
}
}
//@AudioPlayer: When user click to "Pause" ------
public void doPause(View view) {
this.mediaPlayer.pause();
this.buttonPause.setEnabled(false);
this.buttonStart.setEnabled(true);
}
//@AudioPlayer: When user click to "Rewind" ------
public void doRewind(View view) {
this.currentPosition = this.mediaPlayer.getCurrentPosition();
//int SUBTRACT_TIME = 5000; // 5 seconds.
int SUBTRACT_TIME = this.perTimeStep; // 5 seconds.
if(this.currentPosition - SUBTRACT_TIME > 0 ) {
this.mediaPlayer.seekTo(this.currentPosition - SUBTRACT_TIME);
}
else {
this.mediaPlayer.seekTo(0);
}
}
//@AudioPlayer: When user click to "Fast-Forward" ------
public void doFastForward(View view) {
this.currentPosition = this.mediaPlayer.getCurrentPosition();
//int ADD_TIME = 5000; // 5 seconds.
int ADD_TIME = this.perTimeStep; // 5 seconds.
if(this.currentPosition + ADD_TIME < this.duration) {
this.mediaPlayer.seekTo(this.currentPosition + ADD_TIME);
}
else {
//Do Nothing
}
}
//@AudioPlayer: onPause ------ @Override
protected void onPause() {
super.onPause();
this.mediaPlayer.pause();
}
//@AudioPlayer: onStop ------
@Override
protected void onStop() {
super.onStop();
this.mediaPlayer.stop();
}
//@AudioPlayer: (not used now) ------
// When you change direction of phone, this method will be called.
// It store the state of video (Current position)
/*
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
// Store current position.
savedInstanceState.putInt("currentPosition", this.mediaPlayer.getCurrentPosition());
}
*/
//@AudioPlayer: (not used now) ------
// After rotating the phone. This method is called.
/*
@Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Get saved position.
int currentPosition = savedInstanceState.getInt("currentPosition");
Log.d("currentPosition: ", "" + currentPosition);
}
*/
}
-----------------------------------------------------------------------------------------------
F. 結果:
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。