Sound Effects Player with MediaPlayer in Kotlin: Play, Stop, and Pause Controls

In this tutorial, you will learn how to develop an Android application using Kotlin that plays sound effects using the `MediaPlayer` class. The tutorial will guide you through implementing features to play, stop, and pause sound effects, supporting both local and web-based MP3 files. You'll create a user interface with a `ListView` inside cards to list and select different sound files for playback. Key steps include setting up `MediaPlayer` instances, handling play, stop, and pause controls, loading MP3 files from local storage or URLs, and integrating these functionalities into a responsive and user-friendly Kotlin-based Android application. By following this guide, you'll gain practical experience in managing media playback and enhancing user interaction through sound effects in your Android apps.
Submitted on July 07, 2024

To create an Android app that plays sound effects using ‘MediaPlayer’, with controls to play, stop, and pause, and supports both local and web MP3 files listed in a ‘ListView’ inside cards, you can follow these steps. This example will demonstrate how to implement this functionality in Kotlin.

Step-by-Step Implementation

1. Add Permissions (Optional):

If you're targeting API level 23 (Android 6.0) or higher, you might need to request permissions to access the internet for playing web MP3 files. Add the following to your ‘AndroidManifest.xml’ inside the <manifest> tag:


<uses-permission android:name="android.permission.INTERNET" />

    

2. Define Layout for MainActivity (activity_main.xml):

Open ‘res/layout/activity_main.xml’ and define the layout for the main activity. It will contain a ‘ListView’ to display the sound effects with play controls.


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/listView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:divider="@null"
        android:dividerHeight="0dp" />

</RelativeLayout>

    

3. Create Card Layout (list_item_card.xml):

  • Create a layout file res/layout/list_item_card.xml for each item in the ListView. Each item will be displayed as a card with play, pause, and stop controls.

<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_margin="8dp"
    app:cardCornerRadius="8dp">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <TextView
            android:id="@+id/textTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:padding="8dp"
            android:text="Sound Effect"
            android:textSize="18sp"
            android:textStyle="bold" />

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            android:padding="8dp">

            <Button
                android:id="@+id/btnPlay"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Play" />

            <Button
                android:id="@+id/btnPause"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Pause"
                android:layout_marginStart="8dp"
                android:visibility="gone" />

            <Button
                android:id="@+id/btnStop"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Stop"
                android:layout_marginStart="8dp" />

        </LinearLayout>

    </LinearLayout>

</androidx.cardview.widget.CardView>

    

4. Create Data Model (SoundItem.kt):

  • Create a Kotlin data class ‘SoundItem’ to represent each sound effect item. This will hold information such as the title and the URI of the MP3 file.

data class SoundItem(val title: String, val uri: String)

5. Create Adapter (SoundAdapter.kt)

  • Create a custom adapter ‘SoundAdapter’ to populate the ‘ListView’ with ‘SoundItem’ data and handle the play, pause, and stop functionality.

import android.content.Context
import android.media.MediaPlayer
import android.view.LayoutInflater
import import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Button
import android.widget.TextView
import androidx.cardview.widget.CardView
import kotlinx.android.synthetic.main.list_item_card.view.*

class SoundAdapter(private val context: Context, private val soundItems: List<SoundItem>) : BaseAdapter() {

    private var mediaPlayer: MediaPlayer? = null
    private var isPaused = false

    override fun getCount(): Int {
        return soundItems.size
    }

    override fun getItem(position: Int): Any {
        return soundItems[position]
    }

    override fun getItemId(position: Int): Long {
        return position.toLong()
    }

    override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View {
        val view: View = convertView ?: LayoutInflater.from(context).inflate(R.layout.list_item_card, parent, false)

        val soundItem = soundItems[position]
        view.textTitle.text = soundItem.title

        view.btnPlay.setOnClickListener {
            playSound(soundItem.uri)
        }

        view.btnPause.setOnClickListener {
            pauseSound()
        }

        view.btnStop.setOnClickListener {
            stopSound()
        }

        return view
    }

    private fun playSound(uri: String) {
        mediaPlayer?.release()
        mediaPlayer = MediaPlayer().apply {
            setDataSource(uri)
            prepare()
            start()
        }
        isPaused = false
        updateButtonVisibility()
    }

    private fun pauseSound() {
        mediaPlayer?.let {
            if (it.isPlaying) {
                it.pause()
                isPaused = true
                updateButtonVisibility()
            }
        }
    }

    private fun stopSound() {
        mediaPlayer?.let {
            if (it.isPlaying || isPaused) {
                it.stop()
                it.reset()
                isPaused = false
                updateButtonVisibility()
            }
        }
    }

    private fun updateButtonVisibility() {
        if (isPaused) {
            view.btnPause.visibility = View.GONE
            view.btnPlay.visibility = View.VISIBLE
        } else {
            view.btnPause.visibility = View.VISIBLE
            view.btnPlay.visibility = View.GONE
        }
    }
}

    

6. MainActivity Implementation (MainActivity.kt)

  • Implement ‘MainActivity’ to set up the ‘ListView’ with ‘SoundAdapter’ and handle interactions.

package com.example.soundeffects

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private val soundItems = listOf(
        SoundItem("Local Sound 1", "android.resource://${packageName}/${R.raw.sound1}"),
        SoundItem("Local Sound 2", "android.resource://${packageName}/${R.raw.sound2}"),
        SoundItem("Web Sound 1", "https://www.soundeffects.com/1.mp3"),
        SoundItem("Web Sound 2", "https://www.soundeffects.com/2.mp3")
    )

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val adapter = SoundAdapter(this, soundItems)
        listView.adapter = adapter
    }
}

    

7. Local MP3 Files

  • Place ‘1.mp3’ and ‘2.mp3’ in the ‘res/raw directory’ of your Android project. You can reference them using ‘android.resource://${packageName}/${R.raw.sound1}’ and ‘android.resource://${packageName}/${R.raw.sound2}’ in SoundItem as shown above.

8. Testing

  • Run the app on an Android device or emulator.
  • Click on the play button in the list items to play the corresponding sound effect.
  • Use the pause and stop buttons to control playback as desired.

Notes:

  • Ensure you handle ‘MediaPlayer’ lifecycle properly to release resources when they are no longer needed (‘release()’ method).
  • Consider adding error handling and UI updates (like changing button states) based on the playback state (playing, paused, stopped).
  • For web URLs, ensure you handle network operations on a background thread to avoid blocking the UI thread.

This example provides a foundation for building a more robust sound effects player in your Android app, including both local and web-based MP3 files, with basic playback controls. Adjustments can be made based on your specific requirements or additional functionality needed in your application.

Sound Effects Player with MediaPlayer in Java: Play, Stop, and Pause Controls

Android application implemented in Java that allows playing sound effects using ‘MediaPlayer’. It supports both local MP3 files (from ‘res/raw’ directory) and web URLs, displayed in a ListView inside cards with play, pause, and stop controls.

Create Data Model (SoundItem.java):

  • Create a Java class ‘SoundItem’ to represent each sound effect item. This will hold information such as the title and the URI of the MP3 file.

1. Add Permissions

2. Define Layout for MainActivity (activity_main.xml):

3. Create Card Layout (list_item_card.xml):

4.Create Data Model (SoundItem.java):

  • Create a Java class ‘SoundItem’ to represent each sound effect item. This will hold information such as the title and the URI of the MP3 file.

public class SoundItem {
    private String title;
    private String uri;

    public SoundItem(String title, String uri) {
        this.title = title;
        this.uri = uri;
    }

    public String getTitle() {
        return title;
    }

    public String getUri() {
        return uri;
    }
}

    

5. Create Adapter (SoundAdapter.java):

  • Create a custom adapter SoundAdapter to populate the ListView with SoundItem data and handle the play, pause, and stop functionality.

import android.content.Context;
import android.media.MediaPlayer;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.TextView;
import androidx.cardview.widget.CardView;

import java.io.IOException;
import java.util.List;

public class SoundAdapter extends BaseAdapter {

    private Context context;
    private List<SoundItem> soundItems;
    private MediaPlayer mediaPlayer;
    private boolean isPaused;

    public SoundAdapter(Context context, List<SoundItem> soundItems) {
        this.context = context;
        this.soundItems = soundItems;
    }

    @Override
    public int getCount() {
        return soundItems.size();
    }

    @Override
    public Object getItem(int position) {
        return soundItems.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = convertView;
        ViewHolder holder;
        if (view == null) {
            LayoutInflater inflater = LayoutInflater.from(context);
            view = inflater.inflate(R.layout.list_item_card, null);
            holder = new ViewHolder();
            holder.textTitle = view.findViewById(R.id.textTitle);
            holder.btnPlay = view.findViewById(R.id.btnPlay);
            holder.btnPause = view.findViewById(R.id.btnPause);
            holder.btnStop = view.findViewById(R.id.btnStop);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }

        final SoundItem soundItem = soundItems.get(position);

        holder.textTitle.setText(soundItem.getTitle());

        holder.btnPlay.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                playSound(soundItem.getUri());
            }
        });

        holder.btnPause.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                pauseSound();
            }
        });

        holder.btnStop.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                stopSound();
            }
        });

        return view;
    }

    private void playSound(String uri) {
        stopSound();
        mediaPlayer = new MediaPlayer();
        try {
            mediaPlayer.setDataSource(uri);
            mediaPlayer.prepare();
            mediaPlayer.start();
            isPaused = false;
            updateButtonVisibility();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private void pauseSound() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
            isPaused = true;
            updateButtonVisibility();
        }
    }

    private void stopSound() {
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
            isPaused = false;
            updateButtonVisibility();
        }
    }

    private void updateButtonVisibility() {
        // Update button visibility based on playback state
        if (isPaused) {
            // Show Play button and hide Pause button
            holder.btnPlay.setVisibility(View.VISIBLE);
            holder.btnPause.setVisibility(View.GONE);
        } else {
            // Show Pause button and hide Play button
            holder.btnPlay.setVisibility(View.GONE);
            holder.btnPause.setVisibility(View.VISIBLE);
        }
    }

    static class ViewHolder {
        TextView textTitle;
        Button btnPlay;
        Button btnPause;
        Button btnStop;
    }
}

    

6. MainActivity Implementation (MainActivity.java)

  • Implement MainActivity to set up the ListView with SoundAdapter and handle interactions.

package com.example.soundeffects;

import android.os.Bundle;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

    private ListView listView;
    private List<SoundItem> soundItems;
    private SoundAdapter soundAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        listView = findViewById(R.id.listView);

        // Initialize sound items
        soundItems = new ArrayList<>();
        soundItems.add(new SoundItem("Local Sound 1", "android.resource://" + getPackageName() + "/" + R.raw.sound1));
        soundItems.add(new SoundItem("Local Sound 2", "android.resource://" + getPackageName() + "/" + R.raw.sound2));
        soundItems.add(new SoundItem("Web Sound 1", "https://www.soundeffects.com/1.mp3"));
        soundItems.add(new SoundItem("Web Sound 2", "https://www.soundeffects.com/2.mp3"));

        // Initialize adapter and set it to ListView
        soundAdapter = new SoundAdapter(this, soundItems);
        listView.setAdapter(soundAdapter);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Release MediaPlayer resources
        if (soundAdapter != null) {
            soundAdapter.releaseMediaPlayer();
        }
    }
}