কম্পিউটার টিউটোরিয়াল

অ্যান্ড্রয়েডে MediaPlayer ব্যবহার করে বেসিক অডিও প্লেয়ার তৈরির পদ্ধতি

MediaPlayer ক্লাস ব্যবহার করে অডিও প্লেয়ার অ্যাপ তৈরি

এই উদাহরণটি দেখায় কীভাবে MediaPlayer, SeekBar এবং Handler ব্যবহার করে একটি ফাংশনাল অডিও প্লেয়ার তৈরি করা যায় যার মাধ্যমে প্লে, পজ, ফরওয়ার্ড, রিওয়াইন্ড এবং প্রগ্রেস ট্র্যাকিং করা যায়।

ধাপ ১: নতুন প্রজেক্ট তৈরি করুন

Android Studio-তে File → New Project থেকে প্রজেক্ট তৈরি করুন।

ধাপ ২: রিসোর্স ফাইল যোগ করুন

  • res/raw/bohemian_rhapsody.mp3 - অডিও ফাইল রাখুন
  • res/drawable/ic_play.xml, ic_pause.xml, ic_back.xml, ic_forward.xml - ভেক্টর আইকন রাখুন

ধাপ ৩: লেআউট XML (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:padding="16dp">
    
    <TextView
        android:id="@+id/textView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:text="Now Playing:"
        android:textAppearance="?android:attr/textAppearanceMedium" />
    
    <TextView
        android:id="@+id/txtSongName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@id/textView"
        android:layout_toEndOf="@id/textView"
        android:textStyle="bold" />
    
    <SeekBar
        android:id="@+id/seekBar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_above="@id/btnBackward"
        android:layout_marginBottom="16dp"
        android:layout_toEndOf="@id/txtStartTime"
        android:layout_toStartOf="@id/txtSongTime" />
    
    <TextView
        android:id="@+id/txtStartTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/seekBar"
        android:layout_marginEnd="8dp"
        android:text="0:00" />
    
    <TextView
        android:id="@+id/txtSongTime"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@id/seekBar"
        android:layout_marginStart="8dp"
        android:layout_toEndOf="@id/seekBar"
        android:text="0:00" />
    
    <LinearLayout
        android:id="@+id/controls"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true"
        android:layout_marginBottom="44dp"
        android:orientation="horizontal"
        android:gravity="center">
        
        <ImageButton
            android:id="@+id/btnBackward"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_margin="8dp"
            android:src="@drawable/ic_back"
            android:contentDescription="Rewind 5s"
            android:background="?attr/selectableItemBackgroundBorderless" />
        
        <ImageButton
            android:id="@+id/btnPlay"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_margin="8dp"
            android:src="@drawable/ic_play"
            android:contentDescription="Play"
            android:background="?attr/selectableItemBackgroundBorderless" />
        
        <ImageButton
            android:id="@+id/btnPause"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_margin="8dp"
            android:src="@drawable/ic_pause"
            android:contentDescription="Pause"
            android:background="?attr/selectableItemBackgroundBorderless" />
        
        <ImageButton
            android:id="@+id/btnForward"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_margin="8dp"
            android:src="@drawable/ic_forward"
            android:contentDescription="Forward 5s"
            android:background="?attr/selectableItemBackgroundBorderless" />
    </LinearLayout>
</RelativeLayout>

ধাপ ৪: MainActivity.java বাস্তবায়ন

import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ImageButton;
import android.widget.SeekBar;
import android.widget.TextView;
import android.widget.Toast;
import java.util.concurrent.TimeUnit;

public class MainActivity extends AppCompatActivity {
    private ImageButton btnBackward, btnForward, btnPause, btnPlay;
    private MediaPlayer mediaPlayer;
    private TextView txtSongName, txtStartTime, txtSongTime;
    private SeekBar seekBar;
    
    private static final int FORWARD_TIME = 5000; // 5 seconds
    private static final int BACKWARD_TIME = 5000;
    private Handler handler = new Handler();
    private boolean isPlaying = false;

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

    private void initViews() {
        btnBackward = findViewById(R.id.btnBackward);
        btnForward = findViewById(R.id.btnForward);
        btnPlay = findViewById(R.id.btnPlay);
        btnPause = findViewById(R.id.btnPause);
        txtSongName = findViewById(R.id.txtSongName);
        txtStartTime = findViewById(R.id.txtStartTime);
        txtSongTime = findViewById(R.id.txtSongTime);
        seekBar = findViewById(R.id.seekBar);
        
        txtSongName.setText("Bohemian Rhapsody");
        seekBar.setMax(100); // Temporary, will update after media prepared
        seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
            @Override
            public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
                if (fromUser && mediaPlayer != null) {
                    mediaPlayer.seekTo(progress);
                }
            }
            @Override public void onStartTrackingTouch(SeekBar seekBar) {}
            @Override public void onStopTrackingTouch(SeekBar seekBar) {}
        });
    }

    private void setupMediaPlayer() {
        mediaPlayer = MediaPlayer.create(this, R.raw.bohemian_rhapsody);
        mediaPlayer.setOnPreparedListener(mp -> {
            seekBar.setMax(mp.getDuration());
            updateTimeDisplay();
        });
        mediaPlayer.setOnCompletionListener(mp -> {
            resetPlayer();
        });
    }

    private void setupClickListeners() {
        btnPlay.setOnClickListener(v -> playAudio());
        btnPause.setOnClickListener(v -> pauseAudio());
        btnForward.setOnClickListener(v -> seekForward());
        btnBackward.setOnClickListener(v -> seekBackward());
    }

    private void playAudio() {
        if (mediaPlayer != null && !mediaPlayer.isPlaying()) {
            mediaPlayer.start();
            isPlaying = true;
            updatePlayPauseButtons();
            startProgressUpdater();
            Toast.makeText(this, "Playing", Toast.LENGTH_SHORT).show();
        }
    }

    private void pauseAudio() {
        if (mediaPlayer != null && mediaPlayer.isPlaying()) {
            mediaPlayer.pause();
            isPlaying = false;
            updatePlayPauseButtons();
            handler.removeCallbacks(updateProgressRunnable);
            Toast.makeText(this, "Paused", Toast.LENGTH_SHORT).show();
        }
    }

    private void seekForward() {
        if (mediaPlayer != null) {
            int newPosition = Math.min(mediaPlayer.getCurrentPosition() + FORWARD_TIME, mediaPlayer.getDuration());
            mediaPlayer.seekTo(newPosition);
        }
    }

    private void seekBackward() {
        if (mediaPlayer != null) {
            int newPosition = Math.max(mediaPlayer.getCurrentPosition() - BACKWARD_TIME, 0);
            mediaPlayer.seekTo(newPosition);
        }
    }

    private void updatePlayPauseButtons() {
        btnPlay.setEnabled(!isPlaying);
        btnPause.setEnabled(isPlaying);
    }

    private void startProgressUpdater() {
        handler.postDelayed(updateProgressRunnable, 100);
    }

    private final Runnable updateProgressRunnable = new Runnable() {
        @Override
        public void run() {
            if (mediaPlayer != null && isPlaying) {
                int currentPosition = mediaPlayer.getCurrentPosition();
                seekBar.setProgress(currentPosition);
                updateTimeDisplay();
                handler.postDelayed(this, 100);
            }
        }
    };

    private void updateTimeDisplay() {
        if (mediaPlayer != null) {
            int current = mediaPlayer.getCurrentPosition();
            int total = mediaPlayer.getDuration();
            
            txtStartTime.setText(formatTime(current));
            txtSongTime.setText(formatTime(total));
        }
    }

    private String formatTime(int millis) {
        return String.format("%d:%02d", 
            TimeUnit.MILLISECONDS.toMinutes(millis),
            TimeUnit.MILLISECONDS.toSeconds(millis) - TimeUnit.MINUTES.toSeconds(TimeUnit.MILLISECONDS.toMinutes(millis))
        );
    }

    private void resetPlayer() {
        isPlaying = false;
        updatePlayPauseButtons();
        handler.removeCallbacks(updateProgressRunnable);
        seekBar.setProgress(0);
        updateTimeDisplay();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mediaPlayer != null) {
            mediaPlayer.release();
            mediaPlayer = null;
        }
        handler.removeCallbacks(updateProgressRunnable);
    }
}

MediaPlayer লাইফসাইকেল এবং স্টেট ম্যানেজমেন্ট

MediaPlayer একটি স্টেট-বেসড অবজেক্ট। সঠিক স্টেট ম্যানেজমেন্ট ছাড়া ক্র্যাশ হতে পারে:

  • Idle: create() এর পর
  • Initialized: setDataSource() এর পর
  • Prepared: prepare()/prepareAsync() এর পর
  • Started: start() কল করলে
  • Paused: pause() কল করলে
  • PlaybackCompleted: গান শেষ হলে
  • Released: release() কল করলে (অবশ্যই কল করতে হবে)

ধাপ ৫: AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="https://schemas.android.com/apk/res/android"
    package="app.com.sample">
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

অ্যাপ্লিকেশন টেস্ট করুন

অ্যাপ রান করুন। প্লে বাটনে ক্লিক করলে গান বাজতে শুরু হবে। SeekBar ドラگ করে কোনো নির্দিষ্ট সময়ে যাওয়া যাবে। ফরওয়ার্ড/ব্যাকওয়ার্ড বাটনে ৫ সেকেন্ড লাফ দেয়া যাবে।

  1. Android-এ ScrollView ব্যবহার করার পদ্ধতি

  2. অ্যান্ড্রয়েড অ্যাপে TextToSpeech তৈরি করার পদ্ধতি

  3. Android অ্যাপ ভালনারেবিলিটি স্ক্যানার: AndroBugs Framework

  4. আপনার অ্যান্ড্রয়েড ফোনকে হাই-রেজ অডিও প্লেয়ারে রূপান্তর করুন