En este post, desarrollaremos un reproductor para Android.
Para la vista añadiremos un TextView
para mostrar el estado del reproductor, un seekBar
para poder movernos a lo largo de la canción, botón play/pausa, botón stop, botón repetir y botón para mostrar la imagen del disco; por último otro seekBar
para actualizar el volumen.
El funcionamiento será el que se espera de un reproductor, con la particularidad que solo reproduciremos una sola canción y visualizaremos una sola portada y lo que si tenemos que tener en cuenta, es que la aplicación no debe bloquear el dispositivo, por lo que los componentes deben actualizarse mediante hilos.
Para actualizar la posición de la canción el seekBar, implementaremos el evento de cambio de valor actualizando el objeto MediaPlayer
al igual que al cambiar el seekBar del volumen. Otro aspecto, es el contrario, que mientras que la canción avanza, el seekBar debe actualizarse, esto lo conseguiremos con un método recursivo que se actualiza cada segundo mientras la canción se esté reproduciendo mediante un hilo retardado (método playCycle()
)
package com.example.wksoftware.reproductorej3_1; import android.content.Intent; import android.content.res.Resources; import android.media.MediaPlayer; import android.os.Environment; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.view.animation.Animation; import android.view.animation.AnimationUtils; import android.widget.ImageView; import android.widget.SeekBar; import android.widget.TextView; import java.io.IOException; public class Reproductor extends AppCompatActivity { ImageView imgPlay; ImageView imgStop; ImageView imgRepeat; TextView tv; int position = 0; MediaPlayer mp; boolean isLooping = true; boolean isPlaying; boolean isStopped; SeekBar sb; SeekBar volume; Animation shake; float MAX_VOLUME = 50; Handler handler; Runnable runnable; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_reproductor); imgPlay = (ImageView) findViewById(R.id.iBPlay); imgStop = (ImageView) findViewById(R.id.iBStop); imgRepeat = (ImageView) findViewById(R.id.iBLooping); tv = (TextView) findViewById(R.id.textviewAccion); sb = (SeekBar) findViewById(R.id.seekBarSong); shake = AnimationUtils.loadAnimation(this, R.anim.shake); volume = (SeekBar) findViewById(R.id.seekBarVolume); volume.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int value, boolean b) { if (mp != null && b) { // ajustar el volumen final float volume = (float) (1 - (Math.log(MAX_VOLUME - value) / Math.log(MAX_VOLUME))); mp.setVolume(volume, volume); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean input) { if (input) { mp.seekTo(progress); } } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); setIcons(); } public void playCycle() { sb.setProgress(mp.getCurrentPosition()); handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { playCycle(); } }, 1000); } public void playAction(View view) { if (isStopped) { destruir(); mp = MediaPlayer.create(this, R.raw.track); TextView tv1 = (TextView) findViewById(R.id.textViewInfo); sb.setMax(mp.getDuration()); playCycle(); } view.startAnimation(shake); if (isPlaying) mp.pause(); else mp.start(); position = mp.getCurrentPosition(); setIcons(); } public void stopAction(View view) { if (mp != null) { view.startAnimation(shake); mp.stop(); position = 0; mp.seekTo(position); sb.setProgress(position); setIcons(); } } public void repeatAction(View view) { view.startAnimation(shake); isLooping = !isLooping; Resources res = getResources(); imgRepeat.setImageResource(isLooping ? R.drawable.ic_action_repeat : R.drawable.ic_action_repeat1); mp.setLooping(isLooping); } void destruir() { if (mp != null) mp.release(); } public void setIcons() { isPlaying = mp != null ? mp.isPlaying() : false; isStopped = !isPlaying && position == 0; Resources res = getResources(); if (isPlaying) { imgPlay.setImageResource(R.drawable.ic_action_pause); tv.setText(res.getString(R.string.action_play)); } else if (isStopped) { imgPlay.setImageResource(R.drawable.ic_action_play); tv.setText(res.getString(R.string.action_stop)); } else { imgPlay.setImageResource(R.drawable.ic_action_play); tv.setText(res.getString(R.string.action_pause)); } sb.setEnabled(!isStopped); } public void viewImage(View view) { Intent i = new Intent(getApplicationContext(), ImageActivity.class); i.putExtra("singer", "Valquirias - Wagner"); startActivity(i); overridePendingTransition(R.anim.right_in, R.anim.right_out); } }
Si le he añadido algunos efectos a los botones y activities para hacerlo visualmente más agradable. El resultado el que podéis ver al inicio del post y en este enlace os dejo el código completo.
Pd: He dejado algunas transiciones para practicar