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.