Crear una aplicación de reproductor de música con Anko

Lo que vas a crear

Un buen enfoque para convertirse en un experto en un nuevo lenguaje de programación o biblioteca es intentar crear algo útil con él. En mi tutorial sobre la simplificación del desarrollo de Android con Anko, le presenté el lenguaje específico de Anko y las funciones de ayuda. Aunque estoy seguro de que los encontraste impresionantes, es posible que todavía tengas miedo de usarlos en aplicaciones grandes y complejas, ya que son muy diferentes de las clases y métodos tradicionales de Android..

Así que hoy, vamos a utilizar Kotlin y Anko para crear una aplicación de reproductor de música para Android, una que puede seleccionar y reproducir automáticamente canciones aleatorias desde el dispositivo del usuario. Su interfaz de usuario razonablemente compleja, que tendrá diferentes widgets interactuando entre sí, debería ayudarlo a comprender mejor cómo funcionan las aplicaciones Anko..

Prerrequisitos

Para poder seguir este tutorial paso a paso, necesitarás:

  • La última versión de Android Studio
  • un teléfono o tableta con Android 5.0 o superior
  • y unos cuantos álbumes de MP3

Si aún no lo ha hecho, lea el siguiente tutorial antes de continuar:

1. Creando un nuevo proyecto

Inicia Android Studio y presiona la tecla Iniciar un nuevo proyecto de Android Studio botón para iniciar el asistente de creación de proyectos. En la siguiente pantalla, asigne un nombre a su aplicación y asegúrese de que Incluye soporte de Kotlin. el campo está marcado.

A continuación, apunte el nivel de API 21 o superior y elija el Actividad vacía modelo. Debido a que no necesitaremos ningún archivo XML de diseño, asegúrese de deseleccionar Generar archivo de diseño campo.

Por último, pulse Terminar para crear el proyecto.

2. Agregando Dependencias

Para agregar Anko al proyecto, agregue lo siguiente implementación dependencia en el construir.gradle archivo de la aplicación módulo:

implementación 'org.jetbrains.anko: anko: 0.10.1'

Usaremos las rutinas de Kotlin para realizar algunas operaciones de forma asíncrona, así que agregue una dependencia para ello a continuación.

implementación 'org.jetbrains.kotlinx: kotlinx-coroutines-android: 0.19.3'

Nuestro reproductor de música, porque reproduce canciones al azar, necesita una lista de todas las canciones disponibles en el dispositivo. Para evitar implementar la lógica para crear dicha lista, agregue DroidMelody, una biblioteca que creé específicamente para este tutorial, como la última dependencia. Debido a que es aprobado y publicado por jcenter, el repositorio predeterminado de Android Studio, agregarlo no es diferente de agregar cualquier otra dependencia.

implementación 'com.progur.droidmelody: droidmelody: 1.0.2'

Además, necesitaremos algunos iconos relacionados con los medios, así que abra el Vector Asset Studio a continuación. Dentro de ella, navega a la AV categoría y elija los íconos con los símbolos de reproducción, pausa y reproducción aleatoria.

En este punto, los siguientes archivos deben estar presentes en el res / drawable carpeta de tu proyecto:

  • ic_play_arrow_black_24dp.xml
  • ic_pause_black_24dp.xml
  • ic_shuffle_black_24dp.xml

3. Solicitando permisos

La mayoría de los usuarios almacenan sus canciones en medios de almacenamiento externos. Por lo tanto, en dispositivos con Android Marshmallow o superior, deberemos solicitar explícitamente el READ_EXTERNAL_STORAGE permiso en tiempo de ejecución.

Sin embargo, antes de solicitar el permiso, debe verificar si el usuario ya lo ha otorgado. Puedes hacerlo llamando al ContextCompat.checkSelfPermission () metodo dentro del onCreate () Método de su actividad. Si no se ha otorgado el permiso, puede solicitarlo llamando al ActivityCompat.requestPermissions () método.

En consecuencia, agregue el siguiente código:

if (ContextCompat.checkSelfPermission (this, Manifest.permission.READ_EXTERNAL_STORAGE)! = PackageManager.PERMISSION_GRANTED) // Solicite el permiso ActivityCompat.requestPermissions (this, arrayOf (Manifest.permission.READ_EXTERNAL_STORAGE_STORAGE)) /) creando la interfaz de usuario createPlayer ()

Tenga en cuenta que el código anterior llama a un método llamado createPlayer () Si el permiso ya ha sido otorgado. Estaremos creando ese método en el siguiente paso..

Después de solicitar el permiso, debe anular la onRequestPermissionsResult () Método de la actividad para determinar si el usuario ha aceptado su solicitud. Si lo hicieron, debes llamar de nuevo al createPlayer () método. Si no lo hicieron, mostrar un mensaje de error utilizando Anko longToast () ayudante y cierra la aplicación.

anular fun onRequestPermissionsResult (requestCode: Int, permissions: Array, grantResults: IntArray) super.onRequestPermissionsResult (requestCode, permissions, grantResults) if (grantResults [0] == PackageManager.PERMISSION_GRANTED) createPlayer () else longToast ("No se ha otorgado el permiso.") finish ()) 

4. Fetching All Songs

Ahora es el momento de definir la createPlayer () Método, que será responsable tanto del aspecto como de la funcionalidad de nuestra aplicación..

diversión privada createPlayer () // más código aquí

Dentro del método, lo primero que debe hacer es generar una lista de todas las canciones disponibles en el dispositivo. Debido a que esto es, como es de esperar, una operación potencialmente de larga ejecución, puede iniciarla en una nueva rutina utilizando el asíncrono () función.

Dentro de la coroutine, crea una nueva instancia de DroidMelody SongFinder clase y llamar a su preparar() Método, que utiliza la resolución de contenido de su actividad para encontrar realmente todas las canciones y colocarlas en una lista llamada todas las canciones. Una vez que el método se completa, simplemente puede regresar todas las canciones de la coroutina. El siguiente código le muestra cómo:

val songsJob = async val songFinder = SongFinder (contentResolver) songFinder.prepare () songFinder.allSongs

La corrutina anterior se ejecuta de forma asíncrona. Para esperar su resultado, debes llamar al esperar() Método dentro de otra coroutine creado usando el lanzamiento() función. Debido a que usaremos el resultado para crear la interfaz de usuario de nuestra aplicación, la nueva rutina debería ejecutarse en el hilo de la interfaz de usuario. Esto se especifica al pasar kotlinx.coroutines.experimental.android.UI como un argumento para lanzamiento().

launch (kotlinx.coroutines.experimental.android.UI) val songs = songsJob.await () // Más código aquí

Ahora tienes una lista de Canción objetos. Cada Canción El objeto tendrá varios detalles importantes sobre la canción a la que hace referencia, como su título, artista, carátula del álbum y URI..

5. Creando un componente Anko

Por defecto, el DSL de Anko está disponible directamente solo dentro de onCreate () Método de una actividad. Para poder usarlo dentro de la createPlayer () método, usted puede depender de la IU () Funciona o crea un nuevo componente Anko. En este tutorial, usaremos este último enfoque porque es más reutilizable..

Para crear un nuevo componente Anko, debe extender el resumen AnkoComponent clase y anular su createView () Método, dentro del cual tendrás acceso al DSL..

val playerUI = objeto: AnkoComponent anular la diversión createView (ui: AnkoContext) = con (ui) // código DSL aquí

6. Definiendo la interfaz de usuario

Debido a que nuestra aplicación es un reproductor de música aleatorio, y no uno que pueda funcionar con listas de reproducción, tendrá una interfaz de usuario poco convencional. Aquí están los widgets visibles que contendrá:

  • un ImageView Widget para mostrar la carátula del álbum de la canción que se está reproduciendo actualmente.
  • un Botón de imagen Widget que permite al usuario pausar o reanudar la canción.
  • un Botón de imagen Widget que le permite al usuario elegir otra canción al azar.
  • una Vista de texto Widget para mostrar el título de la canción.
  • una Vista de texto Widget para mostrar el nombre del artista de la canción.

En consecuencia, agregue los siguientes campos al componente Anko:

var albumArt: ImageView? = nulo var playButton: ImageButton? = null var shuffleButton: ImageButton? = nulo var songTitle: TextView? = null var songArtist: TextView? = nulo

Además, necesitaremos un Disposición relativa y un par de LinearLayout contenedores para colocar los widgets anteriores y establecer relaciones entre ellos. El siguiente diagrama muestra la jerarquía de vistas que crearemos a continuación:

Porque el Disposición relativa El widget se encuentra en la raíz de la jerarquía de vistas, primero debe crearlo agregando el siguiente código dentro de createView () Método del componente Anko:

relativeLayout backgroundColor = Color.BLACK // Más código aquí

Tenga en cuenta que hemos utilizado el color de fondo Propiedad del widget para darle un color negro. Usaremos varias de estas propiedades en este tutorial para que nuestra aplicación se vea mejor. Eres libre de cambiar sus valores para que coincida con tus preferencias.

Dentro de Disposición relativa widget, añadir el ImageView Widget para la carátula del álbum. Debería ocupar todo el espacio disponible en la pantalla, así que use el lparams () Método después de agregarlo y pasar el matchParent constante a ella dos veces, una para el ancho y una para la altura. Así es cómo:

albumArt = imageView scaleType = ImageView.ScaleType.FIT_CENTER .lparams (matchParent, matchParent)

los lparams () El método, como su nombre lo sugiere, le permite especificar los parámetros de diseño que deben asociarse con un widget. Usándolo, puede especificar rápidamente detalles como los márgenes que debe tener un widget, sus dimensiones y su posición.

A continuación, crea un LinearLayout widget con una orientación vertical llamando a la VerticalLayout () función y añadir el Vista de texto Widgets para ello. El diseño debe colocarse en la parte inferior de la pantalla, por lo que debe llamar al alignParentBottom () Función mientras se especifican sus parámetros de diseño.

verticalLayout backgroundColor = Color.parseColor ("# 99000000") songTitle = textView textColor = Color.WHITE tipo de letra = Typeface.DEFAULT_BOLD textSize = 18f songArtist = textView textColor = Color.WHITE // Más código aquí .lparams ( matchParent, wrapContent) alignParentBottom ()

Del mismo modo, crear el LinearLayout widget con una orientación horizontal llamando a la LinearLayout () función, y añadir los dos Botón de imagen Widgets para ello. Asegúrate de usar el imageResource Propiedad de los botones para especificar los iconos que deben mostrar. El siguiente código le muestra cómo:

linearLayout playButton = imageButton imageResource = R.drawable.ic_play_arrow_black_24dp onClick playOrPause () .lparams (0, wrapContent, icono de la persona de la prospección de animales de compañía) (0, wrapContent, 0.5f) .lparams (matchParent, wrapContent) topMargin = dip (5)

Puede ver que el código anterior tiene controladores de eventos de clic para Botón de imagen widgets Dentro de los manejadores, hay llamadas a dos métodos nombrados intuitivamente: playOrPause () y playRandom (). Los crearemos en los siguientes pasos..

En este punto, hemos terminado de definir el aspecto de nuestra aplicación.. 

7. tocando canciones

Nuestra aplicación todavía es incapaz de reproducir música. Vamos a arreglar eso creando el playRandom () método.

fun playRandom () // Más código aquí

Estaremos usando una instancia de la Reproductor multimedia Clase para tocar la música. Es un recurso bastante costoso, y debe publicarse cuando el usuario cierre la aplicación. Por lo tanto, debe definirse como un campo de la actividad, y no el componente Anko, y liberarse dentro del onDestroy () método de la actividad.

privado var mediaPlayer: MediaPlayer? = null override fun onDestroy () mediaPlayer? .release () super.onDestroy ()

Dentro de playRandom () En este método, ahora podemos elegir una canción aleatoria de la lista de canciones que generamos anteriormente, simplemente barajando la lista y seleccionando el primer elemento. Este enfoque no es muy eficiente, pero es muy conciso.

Collections.shuffle (canciones) val song = songs [0]

Ahora puede inicializar el reproductor multimedia con la URI de la canción recién elegida. Además, use el setOnCompletionListener () Método para asegurarse de que una nueva canción aleatoria comience a reproducirse tan pronto como se complete la canción actual.

mediaPlayer? .reset () mediaPlayer = MediaPlayer.create (ctx, song.uri) mediaPlayer? .setOnCompletionListener playRandom ()

Los contenidos de la ImageView y Vista de texto los widgets también deben actualizarse para mostrar los detalles asociados con la nueva canción.

albumArt? .imageURI = song.albumArt songTitle? .text = song.title songArtist? .text = song.artist

Finalmente, para comenzar realmente a tocar la canción, puedes llamar al comienzo() Método del reproductor multimedia. Ahora también sería el momento adecuado para actualizar el Botón de imagen Widget para cambiar el icono de "juego" a un icono de "pausa".

mediaPlayer? .start () playButton? .imageResource = R.drawable.ic_pause_black_24dp

8. Pausar y reanudar

En un paso anterior, llamamos a un método llamado playOrPause () dentro del click-handler de uno de los Botón de imagen widgets Definirlo como otro método del componente Anko..

fun playOrPause () // Más código aquí

La lógica que necesita implementar dentro de este método debe ser bastante obvia. Si el reproductor de medios ya está reproduciendo una canción, que puede verificar usando el está jugando propiedad, llama a su pausa() Método y mostrar el icono "jugar" en el Botón de imagen. De lo contrario, llame al comienzo() Método y mostrar el icono de "pausa".

val songPlaying: Boolean? = mediaPlayer? .isPlaying if (songPlaying == true) mediaPlayer? .pause () playButton? .imageResource = R.drawable.ic_play_arrow_black_24dp else mediaPlayer? .start () playButton?

Nuestro componente Anko ya está listo.

9. Viendo el componente Anko

Simplemente crear un componente Anko no es suficiente. También debe asegurarse de representarlo llamando a su setContentView () Método y pasándole una actividad. Por ahora, puedes pasarle la actividad principal..

Opcionalmente, si desea que la aplicación comience a reproducir una canción tan pronto como el usuario la abra, puede llamar al playRandom () método de nuevo ahora.

playerUI.setContentView (this @ MainActivity) playerUI.playRandom ()

Nuestra aplicación está lista. Si lo ejecuta en un dispositivo que tiene uno o más archivos MP3 con etiquetas ID3 con el formato correcto y la carátula del álbum incrustada, debería ver algo similar a esto:

Conclusión

En este tutorial, aprendió a crear una aplicación de reproductor de música con una jerarquía de vistas complejas utilizando solo Anko y Kotlin. Mientras lo hacía, trabajó con varias características avanzadas de ambos, como coroutines y ayudantes de parámetros de diseño. También aprendió cómo hacer que el código Anko sea más modular y reutilizable al crear componentes Anko.

Siéntase libre de agregar más funcionalidad a la aplicación o modificar su apariencia para darle un toque personal!

Y mientras estás aquí, echa un vistazo a algunas de nuestras otras publicaciones sobre Kotlin y aplicaciones de codificación de Android!