บทความนี้จะต่อเนื่องจากบทความ BGM & Effect นะครับ [Android Code] การเพิ่มเสียงประกอบลงใน Application [BGM & Effect] เมื่อเล่นไฟล์เสียงไปหลายครั้งแล้วอยู่ๆเสียงมันก็ดันไม่เล่นซะงั้นนี้
ปัญหานี้เกิดมาจากการที่คลาส Media Player ที่ใช้เล่นเสียงถูกเรียกใช้ซ้ำเรื่อยๆ โดยไม่ได้มีการเคลียร์ของเก่าทิ้งจึงทำให้เกิดการล้นของบัฟเฟอร์ขึ้น เสียงจึงไม่เล่นและขึ้นข้อความเออเรอร์ที่ LogCat แบบนี้แทน
ดังนั้นจึงต้องเคลียร์บัฟเฟอร์ทิ้งทุกครั้งเมื่อเล่นไฟล์เสียงเสร็จ
MediaPlayer mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
ซึ่งแน่นอนว่า คำสั่งเพียงเท่านี้ก็จะทำให้เกิดปัญหาบัฟเฟอร์ล้นได้ เพราะว่าไม่มีการเคลียร์บัฟเฟอร์เมื่อเล่นไฟล์เสียงจบแต่อย่างใด จะใช้คำสั่งเคลียร์บัฟเฟอร์ แต่จะรู้ได้ไงล่ะว่าไฟล์เสียงนั้นๆเล่นจบเมื่อไร? สำหรับ Media Player จะมี Listener สำหรับจับ Event เมื่อเล่นเพลงจบให้แล้ว
MediaPlayer mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
}
});
จะเห็นว่ามีฟังก์ชัน onCompletion ที่จะทำงานเมื่อเสียงเล่นจบแล้ว ดังนั้นในฟังก์ชันดังกล่าวนี้ก็สามารถใส่คำสั่งเคลียร์บัฟเฟอร์ได้เลย
MediaPlayer mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
จะสังเกตุเห็นว่าคลาส Media Player ที่เจ้าของบล็อกเรียกใช้จะเป็น mp แทนที่จะเรียก mpEffect ทั้งนี้ก็เพราะว่า มันคือตัวเดียวกัน! จึงไม่จำเป็นต้องไปเรียกใช้งานผ่าน mpEffect เลย ผลลัพธ์ก็คือ mpEffect จะทำการ Release นั่นแหละ เพราะมันคือตัวเดียวกัน
ดังนั้นโค๊ดโดยรวมก็จะประมาณนี้
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
MediaPlayer mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
}
โค๊ดอันนี้ก็เข้าใจได้ไม่ยากเลย ก็คือกดปุ่มแล้วมีเสียงสุดคลาสสิค แต่ทีนี้ก็ยังมีปัญหาหนึ่งคือ ถ้าไฟล์เสียงเป็นเสียงสั้นๆก็ไม่เป็นไรหรอก ถ้าเป็นเสียงที่มีความยาวในระดับนึงล่ะ? ลองเอาไปทดสอบดูได้ ระหว่างนั้นถ้ากดย่อแอพหรือปิดแอพเสียงก็จะยังไม่หยุดเล่น ดังนั้นจึงควรแก้ไขโค๊ดให้เหมาะสมกว่านี้กันหน่อยละกันเนอะ
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
MediaPlayer mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
// หยุดเล่นไฟล์เสียงตรงนี้
}
}
ก็จะทำให้ไฟล์เสียงหยุดเล่นเมื่อปิดหรือย่อแอพลง
แต่ปัญหาคือจะเรียกใช้ mpEffect ได้ยังไงล่ะ ?
เพราะมันถูกประกาศและเรียกใช้ใน onClick
ซึ่งไม่สามารถเข้าถึงจาก onStop ได้เลยนะ
คำตอบง่ายๆเลยก็คือ ก็ประกาศมันเป็น Global สิ
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
// หยุดเล่นไฟล์เสียงตรงนี้
}
}
วิธีแก้ปัญหาสุดแสนจะธรรมดา ประกาศไว้ข้างนอกสุดเลย เพื่อให้ทุกฟังก์ชันสามารถเรียกใช้งาน mpEffect ได้ ทีนี้ใน onStop ก็สามารถเรียกใช้คำสั่งหยุดเล่นเสียงได้
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
mpEffect.stop();
mpEffect.release();
}
}
แค่นี้ก็สามารถใช้คำสั่งหยุดเล่นเพลงและเคลียร์บัฟเฟอร์ทิ้งได้แล้ว จากโค๊ดนี้อยากให้เอาไปลองกันดู เพราะมันจะเกิดเออเรอร์ได้อีกกรณี นั่นก็คือยังไม่ได้กดเล่นเสียงแล้วกดออกทันที ทำให้เกิด NullPointerException ซึ่งเกิดมาจากการที่ใช้คำสั่งหยุดเล่นเสียงและเคลียร์บัฟเฟอร์ ทั้งๆที่ยังไม่ได้กำหนดค่าให้กับ mpEffect เลย (กำหนดค่าก็ต่อเมื่อกดปุ่ม) ดังนั้นถ้ายังไม่ได้กดปุ่มเล่นเสียงแล้วกดออกทันที ก็จะทำให้เออเรอร์
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
mpEffect.stop();
mpEffect.release();
}
}
เท่านี้ก็เรียบร้อย เวลากดปุ่มเสียงก็ทำงานแค่คำสั่ง Start ไปเลย ไม่ต้องมานั่งกำหนดค่า mpEffect ซ้ำซ้อนให้เสียเวลา เพราะยังไงก็ใช้เสียงเดิม และนอกจากนี้วิธีนี้ยังแก้ปัญหาเสียงเพลงเล่นซ้อนกันเมื่อกดเล่นรัวๆได้ด้วยนะ โดยกดซ้ำก็จะไม่เล่นซ้อนกับเสียงเดิม จนกว่าเสียงเดิมจะเล่นจนจบ
แต่ถึงกระนั้น ปัญหาก็ยังไม่หมด นั่นก็คือ คำสั่งใน onStop นั่นเอง จะเห็นว่าใช้คำสั่งให้หยุดเล่นเสียงและเคลียร์บัฟเฟอร์ แต่ลองคิดตามดู คำสั่งดังกล่าวนี้จะใช้เพื่ออะไร? ใช้เพื่อหยุดเล่นเสียงเพลง เพื่อไม่ให้เสียงเพลงเล่นค้างไว้ ดังนั้นคำสั่งนี้ ควรจะทำงานเมื่อเสียงเพลงเล่นอยู่เท่านั้น เพราะคำสั่งจะทำงานตลอดเวลา ถึงแม้ว่าเสียงจะเล่นอยู่หรือไม่ก็ตาม ดังนั้นในการใช้คำสั่งนี้ใน onStop ควรมีการเช็คด้วยว่าเสียงเล่นอยู่หรือไม่
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
if(mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
}
}
วิธีแก้ปัญหาง่ายๆเลยก็คือ ก็ใช้ If เช็คไปสิว่าเสียงเล่นอยู่หรือไม่ ถ้าเล่นอยู่ก็ค่อยให้ใช้คำสั่งดังกล่าวแทน แต่ก็ยังคงมีเออเรอร์อยู่อีกนะ คือคำสั่ง isPlaying() ไม่สามารถทำงานได้เมื่อ Media Player ถูก Release แล้ว ดังนั้นเพื่อแก้ปัญหาดังกล่าวเจ้าของบล็อกจึงใช้ Try-Catch ซะเลย
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mpEffect = MediaPlayer.create(Main.this, R.raw.sound_effect);
Button buttonSound = (Button)findViewById(R.id.buttonSound);
buttonSound.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
try {
if(mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
เพื่อป้องกันกรณีดังกล่าว ซึ่งจะเป็นเออเรอร์แบบ IllegalStateException เพียงเท่านั้นก็เป็นอันเสร็จเรียบร้อยสำหรับการจัดการปัญหาต่างๆ
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound1 = (Button)findViewById(R.id.buttonSound1);
buttonSound1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_01);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
Button buttonSound2 = (Button)findViewById(R.id.buttonSound2);
buttonSound2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_02);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
Button buttonSound3 = (Button)findViewById(R.id.buttonSound3);
buttonSound3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_03);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
Button buttonSound4 = (Button)findViewById(R.id.buttonSound4);
buttonSound4.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_04);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
try {
if(mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
ดังนั้น mpEffect ก็จะใช้ร่วมกัน โดยสามารถกดให้เล่นเสียงซ้อนกันได้ แต่ทีนี้ให้มาโฟกัสกันที่ onStop กันต่อ สำหรับกรณีเสียงเพลงที่มากกว่าหนึ่ง
สรุปคำสั่งทั้งหมดสำหรับการเล่นไฟล์เสียงหลายไฟล์ จะได้ดังนี้
แต่โค๊ดมันยาวไปหน่อย แถมคำสั่งใน onClick ก็คล้ายๆกัน ถ้างั้นทำเป็นฟังก์ชันไปเลยดีกว่าจะได้สั้นลง ดูง่ายขึ้น
เท่านี้ก็สั้นลงแล้ว แต่ทว่าโค๊ดตัวนี้เวลากดเล่นหลายๆครั้งรัวๆ เสียงมันจะเล่นซ้อนกัน ถ้าไม่ต้องการให้เสียงเล่นซ้อนกันก็ต้องทำการเช็คก่อน เมื่อผู้ใช้ onClick ที่ปุ่มใดๆ เช็คก่อนว่า MediaPlayer เล่นอยู่หรือไม่ ถ้ากำลังเล่นอยู่ก็ให้หยุดเสียงที่เล่นอยู่ก่อนแล้วจึงเล่นเสียงที่ผู้ใช้กด
แต่โค๊ดยาวขึ้นอีกแล้ว ต้องทำให้สั้นลงแล้วล่ะ
แต่ยังไม่พอ อยากได้สั้นกว่านี้อีกนิดนึง จะเห็นว่า การเช็คว่าไฟล์เสียงอื่นๆเล่นอยู่หรือป่าว เหมือนกับใน onStop เพราะงั้นจึงรวบเฉพาะโค๊ดเช็คเงื่อนไขดังกล่าวเป็นอีกฟังก์ชันได้
ก็เรียบร้อยแล้ว สำหรับเล่นเสียงแบบไม่ให้ซ้ำซ้อนกัน
ก็จะเห็นว่า การใช้งานไฟล์เสียง ใช่ว่าเรียกใช้งานแล้วเสียงเล่นได้ แล้วจะปล่อยทิ้งไว้แบบนั้นเฉยๆเลย ควรจะมีการจัดการที่เหมาะสมด้วย ซึ่งวิธีก็จะแตกต่างกันไปตามกรณีการใช้งาน เพื่อป้องกันเออเรอร์ใดๆ
สำหรับผู้ที่หลงเข้ามาอ่านคนไหนที่ต้องการไฟล์ตัวอย่าง สามารถดาวน์โหลดได้จาก Sound Management [Google Drive]
public void onStop() {
super.onStop();
try {
if(mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
เนื่องจากกรณีไฟล์เสียงมากกว่าหนึ่ง จะกำหนดค่าตัวแปร mpEffect ก็ต่อเมื่อกดปุ่ม Button ใดๆแล้วเท่านั้น ดังนั้นถ้ายังไม่กดล่ะ? mpEffect ก็จะมีค่าเป็น Null อยู่ คือยังไม่มีการกำหนดค่า แล้วถ้าผู้ใช้ยังไม่ได้กดเล่นเสียงใดๆแล้วกดออกทันทีล่ะ? ให้สังเกตุตรงคำสั่ง mpEffect.isPlaying() ซึ่งตรงนี้ล่ะจะเออเรอร์ เพราะว่า mpEffect เป็น Null อยู่ จึงไม่สามารถเรียกใช้คำสั่งได้ ดังนั้นจึงต้องมีการเช็คก่อนว่า mpEffect เป็น Null หรือไม่ ถ้าเป็น Null คำสั่ง isPlaying ก็จะไม่ทำงาน ทำให้ไม่เกิดเออเรอร์
public void onStop() {
super.onStop();
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
สรุปคำสั่งทั้งหมดสำหรับการเล่นไฟล์เสียงหลายไฟล์ จะได้ดังนี้
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound1 = (Button)findViewById(R.id.buttonSound1);
buttonSound1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_01);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
Button buttonSound2 = (Button)findViewById(R.id.buttonSound2);
buttonSound2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_02);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
Button buttonSound3 = (Button)findViewById(R.id.buttonSound3);
buttonSound3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_03);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
Button buttonSound4 = (Button)findViewById(R.id.buttonSound4);
buttonSound4.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mpEffect =
MediaPlayer.create(Main.this, R.raw.sound_effect_04);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
});
}
public void onStop() {
super.onStop();
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
แต่โค๊ดมันยาวไปหน่อย แถมคำสั่งใน onClick ก็คล้ายๆกัน ถ้างั้นทำเป็นฟังก์ชันไปเลยดีกว่าจะได้สั้นลง ดูง่ายขึ้น
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound1 = (Button)findViewById(R.id.buttonSound1);
buttonSound1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_01);
}
});
Button buttonSound2 = (Button)findViewById(R.id.buttonSound2);
buttonSound2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_02);
}
});
Button buttonSound3 = (Button)findViewById(R.id.buttonSound3);
buttonSound3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_03);
}
});
Button buttonSound4 = (Button)findViewById(R.id.buttonSound4);
buttonSound4.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_04);
}
});
}
public void onStop() {
super.onStop();
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public void playSound(Context context, int resId) {
mpEffect = MediaPlayer.create(context, resId);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
}
เท่านี้ก็สั้นลงแล้ว แต่ทว่าโค๊ดตัวนี้เวลากดเล่นหลายๆครั้งรัวๆ เสียงมันจะเล่นซ้อนกัน ถ้าไม่ต้องการให้เสียงเล่นซ้อนกันก็ต้องทำการเช็คก่อน เมื่อผู้ใช้ onClick ที่ปุ่มใดๆ เช็คก่อนว่า MediaPlayer เล่นอยู่หรือไม่ ถ้ากำลังเล่นอยู่ก็ให้หยุดเสียงที่เล่นอยู่ก่อนแล้วจึงเล่นเสียงที่ผู้ใช้กด
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound1 = (Button)findViewById(R.id.buttonSound1);
buttonSound1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
playSound(Main.this, R.raw.sound_effect_01);
}
});
Button buttonSound2 = (Button)findViewById(R.id.buttonSound2);
buttonSound2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
playSound(Main.this, R.raw.sound_effect_02);
}
});
Button buttonSound3 = (Button)findViewById(R.id.buttonSound3);
buttonSound3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
playSound(Main.this, R.raw.sound_effect_03);
}
});
Button buttonSound4 = (Button)findViewById(R.id.buttonSound4);
buttonSound4.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
playSound(Main.this, R.raw.sound_effect_04);
}
});
}
public void onStop() {
super.onStop();
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public void playSound(Context context, int resId) {
mpEffect = MediaPlayer.create(context, resId);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
}
จะเห็นว่าโค๊ดเช็คว่าไฟล์เพลงเล่นอยู่หรือไม่ ถ้าเล่นอยู่ก็หยุดก่อน นี่มันคือโค๊ดเช็คเหมือนกันใน onStop เป๊ะๆเลย (ก็แหงดิ เช็คเหมือนกัน)แต่โค๊ดยาวขึ้นอีกแล้ว ต้องทำให้สั้นลงแล้วล่ะ
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound1 = (Button)findViewById(R.id.buttonSound1);
buttonSound1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_01);
}
});
Button buttonSound2 = (Button)findViewById(R.id.buttonSound2);
buttonSound2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_02);
}
});
Button buttonSound3 = (Button)findViewById(R.id.buttonSound3);
buttonSound3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_03);
}
});
Button buttonSound4 = (Button)findViewById(R.id.buttonSound4);
buttonSound4.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_04);
}
});
}
public void onStop() {
super.onStop();
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
public void playSound(Context context, int resId) {
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
mpEffect = MediaPlayer.create(context, resId);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
}
กรณีแรกคือ ก็เอาคำสั่งที่ว่ามาใส่ในฟังก์ชัน playSound เลยสิ เพราะเล่นเพลงทุกครั้งต้องมีการเช็คอยู่แล้วว่ามีไฟล์อื่นเล่นอยู่หรือป่าวแต่ยังไม่พอ อยากได้สั้นกว่านี้อีกนิดนึง จะเห็นว่า การเช็คว่าไฟล์เสียงอื่นๆเล่นอยู่หรือป่าว เหมือนกับใน onStop เพราะงั้นจึงรวบเฉพาะโค๊ดเช็คเงื่อนไขดังกล่าวเป็นอีกฟังก์ชันได้
package app.akexorcist.soundmanagement;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.app.Activity;
import android.content.Context;
public class Main extends Activity {
MediaPlayer mpEffect;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button buttonSound1 = (Button)findViewById(R.id.buttonSound1);
buttonSound1.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_01);
}
});
Button buttonSound2 = (Button)findViewById(R.id.buttonSound2);
buttonSound2.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_02);
}
});
Button buttonSound3 = (Button)findViewById(R.id.buttonSound3);
buttonSound3.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_03);
}
});
Button buttonSound4 = (Button)findViewById(R.id.buttonSound4);
buttonSound4.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
playSound(Main.this, R.raw.sound_effect_04);
}
});
}
public void onStop() {
super.onStop();
stopIfPlating();
}
public void playSound(Context context, int resId) {
stopIfPlating();
mpEffect = MediaPlayer.create(context, resId);
mpEffect.start();
mpEffect.setOnCompletionListener(new OnCompletionListener() {
public void onCompletion(MediaPlayer mp) {
mp.release();
}
});
}
public void stopIfPlating() {
try {
if(mpEffect != null && mpEffect.isPlaying()) {
mpEffect.stop();
mpEffect.release();
}
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
}
ก็เรียบร้อยแล้ว สำหรับเล่นเสียงแบบไม่ให้ซ้ำซ้อนกัน
ก็จะเห็นว่า การใช้งานไฟล์เสียง ใช่ว่าเรียกใช้งานแล้วเสียงเล่นได้ แล้วจะปล่อยทิ้งไว้แบบนั้นเฉยๆเลย ควรจะมีการจัดการที่เหมาะสมด้วย ซึ่งวิธีก็จะแตกต่างกันไปตามกรณีการใช้งาน เพื่อป้องกันเออเรอร์ใดๆ
สำหรับผู้ที่หลงเข้ามาอ่านคนไหนที่ต้องการไฟล์ตัวอย่าง สามารถดาวน์โหลดได้จาก Sound Management [Google Drive]