This post describes an example of a music player which plays the audio file picked. The MediaPlayer runs in Service class which continues to run even when app is closed. The MediaPlayer is controlled by the Activity bound to the Service, which unbinds when the Activity exits and binds again when the Activity starts.
Create your layout in activity_main.xml.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PICK FILE"
app:layout_constraintBottom_toTopOf="@+id/linear1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:id="@+id/linear1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="10dp"
android:background="#ffffdd"
android:gravity="center_horizontal"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView2"
android:textSize="18dp"
android:text="Title"/>
<SeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/seekbar1"
android:max="100"
android:padding="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/textView3"
android:textSize="20dp"
android:padding="10dp"
android:text="00:00 / 00:00"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="PLAY"
android:id="@+id/button2"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>Create a java file, PlayerService.java and add following code.
package com.example.pickfile;
import android.app.Service;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.media.AudioAttributes;
import android.media.MediaPlayer;
import android.net.Uri;
import android.os.Binder;
import android.os.IBinder;
import android.provider.MediaStore;
import androidx.annotation.Nullable;
import java.io.IOException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class PlayerService extends Service {
private final IBinder binder = new LocalBinder();
MediaPlayer mediaPlayer;
String duration;
ScheduledExecutorService timer;
SharedPreferences sp;
Uri mUri;
String filename;
public class LocalBinder extends Binder {
PlayerService getService() {
// Return this instance of LocalService so clients can call public methods
return PlayerService.this;
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
mUri = intent.getData();
createMediaPlayer(mUri);
sp = getSharedPreferences("sp", MODE_PRIVATE);
return START_STICKY;
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return binder;
}
public void createMediaPlayer(Uri uri){
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioAttributes(
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build()
);
try {
mediaPlayer.setDataSource(getApplicationContext(), uri);
mediaPlayer.prepare();
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
releaseMediaPlayer();
stopSelf();
}
});
filename = getNameFromUri(uri);
int millis = mediaPlayer.getDuration();
long total_secs = TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS);
long mins = TimeUnit.MINUTES.convert(total_secs, TimeUnit.SECONDS);
long secs = total_secs - (mins*60);
duration = mins + ":" + secs;
} catch (IOException e){
MainActivity.textview2.setText(e.toString());
}
}
public void updateMediaData(){
MainActivity.textview2.setText(filename);
MainActivity.button2.setEnabled(true);
int millis = mediaPlayer.getDuration();
MainActivity.textview3.setText("00:00 / " + duration);
MainActivity.seekbar1.setMax(millis);
MainActivity.seekbar1.setProgress(0);
}
public String getNameFromUri(Uri uri){
String fileName = "";
Cursor cursor = null;
cursor = getContentResolver().query(uri, new String[]{
MediaStore.Images.ImageColumns.DISPLAY_NAME
}, null, null, null);
if (cursor != null && cursor.moveToFirst()) {
fileName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DISPLAY_NAME));
}
if (cursor != null) {
cursor.close();
}
return fileName;
}
public void releaseMediaPlayer(){
if (timer != null) {
timer.shutdown();
}
if (mediaPlayer != null) {
mediaPlayer.release();
mediaPlayer = null;
}
sp.edit().putString("created", "false").commit();
MainActivity.button2.setEnabled(false);
MainActivity.textview2.setText("TITLE");
MainActivity.textview3.setText("00:00 / 00:00");
MainActivity.seekbar1.setMax(100);
MainActivity.seekbar1.setProgress(0);
}
public void playOrPause() {
if (mediaPlayer != null) {
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
MainActivity.button2.setText("PLAY");
timer.shutdown();
} else {
mediaPlayer.start();
MainActivity.button2.setText("PAUSE");
timer = Executors.newScheduledThreadPool(1);
timer.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
if (mediaPlayer != null) {
if (!MainActivity.seekbar1.isPressed()) {
MainActivity.seekbar1.setProgress(mediaPlayer.getCurrentPosition());
}
}
}
}, 10, 10, TimeUnit.MILLISECONDS);
}
}
}
public void updatePlayingTime(){
if (mediaPlayer != null){
int millis = mediaPlayer.getCurrentPosition();
long total_secs = TimeUnit.SECONDS.convert(millis, TimeUnit.MILLISECONDS);
long mins = TimeUnit.MINUTES.convert(total_secs, TimeUnit.SECONDS);
long secs = total_secs - (mins*60);
MainActivity.textview3.setText(mins + ":" + secs + " / " + duration);
}
}
public void seekMediaPlayer(){
if (mediaPlayer != null) {
mediaPlayer.seekTo(MainActivity.seekbar1.getProgress());
}
}
}
In AndroidManifest.xml add the Service class.
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.pickfile">
<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/Theme.PickFile">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".PlayerService"/>
</application>
</manifest>In MainActivity.java put following codes.
package com.example.pickfile;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.widget.Button;
import android.widget.SeekBar;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
static TextView textview2;
static TextView textview3;
Button button1;
static Button button2;
static SeekBar seekbar1;
boolean mBound;
PlayerService mService;
public static final int PICK_FILE =99;
SharedPreferences sp;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1 = findViewById(R.id.button1);
button2 = findViewById(R.id.button2);
textview2 = findViewById(R.id.textView2);
textview3 = findViewById(R.id.textView3);
seekbar1 = findViewById(R.id.seekbar1);
sp = getSharedPreferences("sp", MODE_PRIVATE);
button1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("audio/*");
startActivityForResult(intent, PICK_FILE);
}
});
button2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (mBound){
mService.playOrPause();
}
}
});
seekbar1.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (mBound) {
mService.updatePlayingTime();
}
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
if (mBound) {
mService.seekMediaPlayer();
}
}
});
button2.setEnabled(false);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == PICK_FILE && resultCode == RESULT_OK){
if (data != null){
Uri uri = data.getData();
Intent intent = new Intent(MainActivity.this, PlayerService.class);
intent.setData(uri);
startService(intent);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
sp.edit().putString("created", "true").commit();
}
}
}
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
PlayerService.LocalBinder binder = (PlayerService.LocalBinder) service;
mService = binder.getService();
if (mService != null){
mService.updateMediaData();
}
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName arg0) {
mBound = false;
}
};
@Override
protected void onStop() {
super.onStop();
if (mService != null){
if (mBound){
unbindService(connection);
mBound=false;
}
}
}
@Override
protected void onStart() {
super.onStart();
if (!mBound){
if (sp.getString("created", "").equals("true")) {
Intent intent = new Intent(MainActivity.this, PlayerService.class);
bindService(intent, connection, Context.BIND_AUTO_CREATE);
}
}
}
}Now run the app.