android programming stop mediaplayer stream on exit? - java

so i have this code to stream an mp3, now i was wondering how can i make the music stop when someone exits the app with the back button/home button. Even if i exit the app and close it the music is still playing in the background and i have no way to make it stop.
package com.hrupin.streamingmedia;
import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnBufferingUpdateListener;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.os.Handler;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.SeekBar;
import com.hrupin.media.R;
public class StreamingMp3Player extends Activity implements OnClickListener, OnTouchListener, OnCompletionListener, OnBufferingUpdateListener{
private ImageButton buttonPlayPause;
private SeekBar seekBarProgress;
public EditText editTextSongURL;
private MediaPlayer mediaPlayer;
private int mediaFileLengthInMilliseconds; // this value contains the song duration in milliseconds. Look at getDuration() method in MediaPlayer class
private final Handler handler = new Handler();
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initView();
}
/** This method initialise all the views in project*/
private void initView() {
buttonPlayPause = (ImageButton)findViewById(R.id.ButtonTestPlayPause);
buttonPlayPause.setOnClickListener(this);
seekBarProgress = (SeekBar)findViewById(R.id.SeekBarTestPlay);
seekBarProgress.setMax(99); // It means 100% .0-99
seekBarProgress.setOnTouchListener(this);
//editTextSongURL = (EditText)findViewById(R.id.EditTextSongURL);
//editTextSongURL.setText(R.string.testsong_20_sec);
mediaPlayer = new MediaPlayer();
mediaPlayer.setOnBufferingUpdateListener(this);
mediaPlayer.setOnCompletionListener(this);
}
/** Method which updates the SeekBar primary progress by current song playing position*/
private void primarySeekBarProgressUpdater() {
seekBarProgress.setProgress((int)(((float)mediaPlayer.getCurrentPosition()/mediaFileLengthInMilliseconds)*100)); // This math construction give a percentage of "was playing"/"song length"
if (mediaPlayer.isPlaying()) {
Runnable notification = new Runnable() {
public void run() {
primarySeekBarProgressUpdater();
}
};
handler.postDelayed(notification,1000);
}
}
#Override
public void onClick(View v) {
if(v.getId() == R.id.ButtonTestPlayPause){
/** ImageButton onClick event handler. Method which start/pause mediaplayer playing */
try {
mediaPlayer.setDataSource("http://www.metalgeardroid.com/music/OST.mp3"); // setup song from http://www.hrupin.com/wp-content/uploads/mp3/testsong_20_sec.mp3 URL to mediaplayer data source
mediaPlayer.prepare(); // you must call this method after setup the datasource in setDataSource method. After calling prepare() the instance of MediaPlayer starts load data from URL to internal buffer.
} catch (Exception e) {
e.printStackTrace();
}
mediaFileLengthInMilliseconds = mediaPlayer.getDuration(); // gets the song length in milliseconds from URL
if(!mediaPlayer.isPlaying()){
mediaPlayer.start();
buttonPlayPause.setImageResource(R.drawable.button_pause);
}else {
mediaPlayer.pause();
buttonPlayPause.setImageResource(R.drawable.button_play);
}
primarySeekBarProgressUpdater();
}
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if(v.getId() == R.id.SeekBarTestPlay){
/** Seekbar onTouch event handler. Method which seeks MediaPlayer to seekBar primary progress position*/
if(mediaPlayer.isPlaying()){
SeekBar sb = (SeekBar)v;
int playPositionInMillisecconds = (mediaFileLengthInMilliseconds / 100) * sb.getProgress();
mediaPlayer.seekTo(playPositionInMillisecconds);
}
}
return false;
}
#Override
public void onCompletion(MediaPlayer mp) {
/** MediaPlayer onCompletion event handler. Method which calls then song playing is complete*/
buttonPlayPause.setImageResource(R.drawable.button_play);
}
#Override
public void onBufferingUpdate(MediaPlayer mp, int percent) {
/** Method which updates the SeekBar secondary progress by current song loading from URL position*/
seekBarProgress.setSecondaryProgress(percent);
}
}

Override the onPause() method
#Override
public void onPause() {
if( mediaPlayer.isPlaying() ) {
mediaPlayer.stop();
}
super.onPause();
}
This method is called when the user leaves your app via the back button, home button, or if they launch another app (via notification etc)

Override the onBackPressed method and stop the player.
#Override
public void onBackPressed() {
if( mediaPlayer.isPlaying() ) {
mediaPlayer.stop();
 }
super.onBackPressed();
}

Related

How to get text from url and put it inside textView?

I'm new in android development and I really can't figure out how to do that. So, I'm building an android app that stream music online via url. There is an url that shows current song. here is the url
I created a textView in my activity_main file to put current song text inside it, but I can't figure out how. I understand that I need to make variable url, then I need to parse that URL and put it inside text view. Or not?
Here is my MainActivity.java:
import androidx.appcompat.app.AppCompatActivity;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
private Button btn;
private TextView currentSong;
private boolean playPause;
private MediaPlayer mediaPlayer;
private boolean initialStage = true;
private ProgressBar pgsBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.audioStreamBtn);
currentSong = (TextView) findViewById(R.id.currentSong);
mediaPlayer = new MediaPlayer();
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
pgsBar = findViewById(R.id.progressBar);
pgsBar.setVisibility(View.GONE);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!playPause) {
btn.setText("Stop");
if (initialStage) {
new Player().execute("stream url ...");
} else {
if (!mediaPlayer.isPlaying())
mediaPlayer.start();
}
playPause = true;
} else {
btn.setText("Play");
if (mediaPlayer.isPlaying()) {
mediaPlayer.pause();
}
playPause = false;
}
}
});
}
class Player extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... strings) {
Boolean prepared = false;
try {
mediaPlayer.setDataSource(strings[0]);
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mediaPlayer) {
initialStage = true;
playPause = false;
btn.setText("Play");
mediaPlayer.stop();
mediaPlayer.reset();
}
});
mediaPlayer.prepare();
prepared = true;
} catch (Exception e) {
prepared = false;
}
return prepared;
}
#Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
if (pgsBar.getVisibility() == View.VISIBLE) {
pgsBar.setVisibility(View.GONE);
btn.setEnabled(true);
}
mediaPlayer.start();
initialStage = true;
}
#Override
protected void onPreExecute() {
mediaPlayer.reset();
super.onPreExecute();
pgsBar.setVisibility(View.VISIBLE);
btn.setEnabled(false);
}
}
}
How do I pull out this text and put it in my textView "currentSong"?
You can use okHttp library to make a network request to URL and it will get back the response as string. Modify the response according to your liking and use that value for setText() of text view .
Use Retrofit or Volley to make a URL request.
possible duplicate of Make an HTTP request with android

How to prevent a service from terminating?

MainActivity.java
import android.content.Intent;
import android.os.Bundle;
import android.support.wearable.activity.WearableActivity;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends WearableActivity {
private TextView mTextView;
private static MainActivity instance;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mTextView = (TextView) findViewById(R.id.text);
// Enables Always-on
setAmbientEnabled();
final TextView text = findViewById(R.id.text);
text.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (text.getText().toString().equals("Started")) {
text.setText("Stoped");
stopService(new Intent(MainActivity.this,service.class));
} else {
text.setText("Started");
startService(new Intent(MainActivity.this,service.class));
}
}
});
}
public static MainActivity getInstance() {
return instance;
}
public void showToast(String toastMsg){
Toast.makeText(MainActivity.this, toastMsg, Toast.LENGTH_SHORT).show();
}
}
Service.java
import android.app.Service;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.MainThread;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public class service extends Service {
private boolean started = false;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("serviceTest", "Service started by user.");
start();
return START_STICKY;
}
#Override
public void onDestroy() {
//Toast.makeText(this, "Service destroyed by user.", Toast.LENGTH_LONG).show();
Log.i("serviceTest", "Service destroyed by user.");
stop();
super.onDestroy();
}
private Timer timer;
private TimerTask timerTask = new TimerTask() {
#Override
public void run() {
if(started) {
start();
}
Log.i("serviceTest", "ServiceCalled!");
}
};
public void start() {
if(timer != null) {
return;
}
timer = new Timer();
timer.scheduleAtFixedRate(timerTask, 0, 10000);
}
public void stop() {
timer.cancel();
timer = null;
}
}
The code runs okay for about 13 or 14 times (i.e. the timer keeps on running for about 13 or 14 times) but suddenly the service stops and onDestroy is called.
Also, during debugging, I have noticed one strange condition: If I delete/comment the onDestroy() method form the code then the service runs always. It never closes on its own. (it only closes upon user input, which is fine)
Please suggest a solution so that the services do not get killed/ destroyed. Or if the OS/ System kills it, then the service starts again on its own.
Thnx
You will have to turn that background service into a foreground service, because of the limitations called Background Execution Limits that started from android Oreo.
Please check out this link for more better understanding: https://developer.android.com/about/versions/oreo/background

Adding onClick method inside onPrepare

First of all, I'm new to Java. Second, my intents here are as follows:
User clicks button (playPause) -> button toggles to pause drawable (pause1) and stream begins and user clicks button -> stream pauses and button toggles to play drawable(play1).
Now my problem is how to implement this behavior, an onClick method, inside of the current method playPauseMusic which contains an onPrepared method that is used to prepare the MediaPlayer asynchronously.
My intuition is to make a check for isPlaying and toggle from there, but my attempts so far have ended in failure.
Here is the relevant code and thank you for your time:
radio.java
package com.example.jacob.wutk;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import java.io.IOException;
public class radio extends AppCompatActivity {
/** Called when the user touches the button */
public void playMusic(View view) throws IOException {
String url = "http://streamer.cci.utk.edu:8000/wutk-vorbis"; // your URL here
MediaPlayer mediaPlayer = new MediaPlayer();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mediaPlayer){
mediaPlayer.start();
}
});
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_radio);
}
}
I hope this helps.
public class radio extends AppCompatActivity {
MediaPlayer mediaPlayer;
boolean prepared=false;
public void playMusic(View view) throws IOException {
playpause();
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_radio);
mediaPlayer = new MediaPlayer();
String url = "http://streamer.cci.utk.edu:8000/wutk-vorbis";
mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
mediaPlayer.setDataSource(url);
mediaPlayer.prepareAsync();
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
public void onPrepared(MediaPlayer mediaPlayer){
prepared=ture;
}
});
}
}
public void playPause() {
if (!mediaplayer.isPlaying()&&prepared) {
mediaplayer.start();
mediaplayer.setImageResource(R.drawable.ic_pause);
} else if(mediaplayer.isPlaying()) {
mediaplayer.pause();
mediaplayer.setImageResource(R.drawable.ic_play);
}
}

Custom view has setOnTouchListener called on it but does not override performClick (class extends Activity NOT View)

I have created an Android Activity implementing a bit of OpenCV. What it does is to simply create a Custom Camera View, and when the screen is touched, the photo will be saved.
My only problem is that the code mOpenCvCameraView.setOnTouchListener(MainActivity.this); inside the BaseLoaderCallback contains a warning.
mOpenCvCameraView.setOnTouchListener(MainActivity.this); warns about
Custom view com/example/zcameratestv2/Version2CameraView has setOnTouchListener called on it but does not override performClick
Unlike other questions, my class extends an Activity not View, so when i try to override the function private boolean performClick() { ...super.performClick(); } it is not recognized. Here are my classes
package com.example.zcameratestv2;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.OpenCVLoader;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.core.Mat;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.Toast;
public class MainActivity extends Activity implements CvCameraViewListener, OnTouchListener {
private Version2CameraView mOpenCvCameraView;
private static final String TAG = "Version 2::Activity";
private BaseLoaderCallback mLoaderCallback = new BaseLoaderCallback(this) {
#Override
public void onManagerConnected(int status) {
switch (status) {
case LoaderCallbackInterface.SUCCESS:
{
Log.i(TAG, "OpenCV loaded successfully");
mOpenCvCameraView.enableView();
mOpenCvCameraView.setOnTouchListener(MainActivity.this);
} break;
default:
{
super.onManagerConnected(status);
} break;
}
}
};
public MainActivity() {
Log.i(TAG, "Version 2 Class instantiated");
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.activity_main);
mOpenCvCameraView = (Version2CameraView) findViewById(R.id.java_surface_view);
mOpenCvCameraView.setVisibility(SurfaceView.VISIBLE);
mOpenCvCameraView.setCvCameraViewListener(this);
}
public void onPause()
{
super.onPause();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
#Override
public void onResume()
{
super.onResume();
OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
}
public void onDestroy() {
super.onDestroy();
if (mOpenCvCameraView != null)
mOpenCvCameraView.disableView();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void onCameraViewStarted(int width, int height) {
// TODO Auto-generated method stub
}
#Override
public void onCameraViewStopped() {
// TODO Auto-generated method stub
}
#Override
public Mat onCameraFrame(Mat inputFrame) {
// TODO Auto-generated method stub
return null;
}
#SuppressLint("SimpleDateFormat")
#Override
public boolean onTouch(View v, MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//some code....
break;
case MotionEvent.ACTION_UP:
Log.i(TAG,"onTouch event");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd_HH-mm-ss");
String currentDateandTime = sdf.format(new Date());
String fileName = Environment.getExternalStorageDirectory().getPath() +
"/sample_picture_" + currentDateandTime + ".jpg";
mOpenCvCameraView.takePicture(fileName);
Toast.makeText(this, fileName + " saved", Toast.LENGTH_SHORT).show();
v.performClick();
break;
default:
break;
}
return true;
}
}
Previously the public boolean onTouch(View v, MotionEvent event) event had a similar warning similar to the OnTouchListener, it displays that I should use a performClick(); method but I cant override it since I extend to an Activity not a View. And I have discovered that applying v.PerformClick(); fixes this.
This other class handles the camera processes
package com.example.zcameratestv2;
import java.io.FileOutputStream;
import org.opencv.android.JavaCameraView;
import android.content.Context;
import android.hardware.Camera;
import android.hardware.Camera.PictureCallback;
import android.util.AttributeSet;
import android.util.Log;
public class Version2CameraView extends JavaCameraView implements PictureCallback {
private static final String TAG = "Version2::CameraView";
private String mPictureFileName;
public Version2CameraView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void takePicture(final String fileName) {
Log.i(TAG, "Taking picture");
this.mPictureFileName = fileName;
// Postview and jpeg are sent in the same buffers if the queue is not empty when performing a capture.
// Clear up buffers to avoid mCamera.takePicture to be stuck because of a memory issue
mCamera.setPreviewCallback(null);
// PictureCallback is implemented by the current class
mCamera.takePicture(null, null, this);
}
#Override
public void onPictureTaken(byte[] data, Camera camera) {
Log.i(TAG, "Saving a bitmap to file");
// The camera preview was automatically stopped. Start it again.
mCamera.startPreview();
mCamera.setPreviewCallback(this);
// Write the image in a file (in jpeg format)
try {
FileOutputStream fos = new FileOutputStream(mPictureFileName);
fos.write(data);
fos.close();
} catch (java.io.IOException e) {
Log.e("PictureDemo", "Exception in photoCallback", e);
}
}
}
I have included the required permissions in the Manifest File such as the CAMERA and the WRITE_EXTERNAL_STORAGE
Can someone determine the problem? Need your help. Thanks in advance!
onTouch() method gets every touch event from underlying view that hasn't been marked as "processed". If your Version2CameraView doesn't handle touch events, they are processed in Activity and your Version2CameraView is passed as View v parameter.
Unfortunately, your JavaCameraView doesn't override performClick(), but you're trying call it on this view. Solution? Add this method to your Version2CameraView class:
#Override
public boolean performClick() {
// do what you want
return true;
}
I think it is a little bit late but the solution is simple. Classes like Button, TextView are subclasses of View as well as SurfaceView which is the parent of JavaCameraView and Version2CameraView subclasses.
Then what is the difference?
The difference is that TextView implements a 'ViewTreeObserver.OnPreDrawListener' interface. For this reason, Button (which is subclass of TextView) can override the performClick() method.
How can I do with my Version2CameraView class?
Just implement an interface to override the performClick() method.
Which one, ViewTreeObserver.OnPreDrawListener? Nope, you should use SurfaceHolder.Callback like this:
public class Version2CameraView extends JavaCameraView implements PictureCallback, SurfaceHolder.Callback
{
...
/**
* Process the MotionEvent.
*/
#Override
public boolean onTouchEvent(MotionEvent event) {
synchronized (getHolder()) {
// Do something
...
return true;
}
}
#Override
public boolean performClick() {
// Calls the super implementation, which generates an AccessibilityEvent
// and calls the onClick() listener on the view, if any
super.performClick();
// Handle the action for the custom click here
return true;
}
...
}
This solution must remove the warning that you have.
You need to add a method to handle the touch events since your view has called setOnTouchListener(), add an override of the default method, be sure to call the super method inside to avoid errors like "Method does not override method from its superclass", you can leave it like my sample if you are not going to process the touch events in there:
#Override
public boolean performClick() {
super.performClick();
return true;
}

How to use a flag in event listener callback in Android app

Expected result
A button can act in a way like a toggle, such that,
(1) first time clicking on it, the button moves rightward
(2) second time clicking on it, the button moves leftward
(3) third time clicking on it, the button moves rightward
and so on....
Problem
The flag variable flagToggleButton cannot be used in button's OnClickListener event listener callback function.
Main.java
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
public class Main extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
final Button b = (Button) findViewById(R.id.button1);
boolean flagToggleButton = false;
b.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View arg0) {
if (flagToggleButton == false) {
Animation anim = AnimationUtils.loadAnimation(Main.this,
R.anim.animation_move_right);
b.startAnimation(anim);
flagToggleButton = true;
}
else {
Animation anim = AnimationUtils.loadAnimation(Main.this,
R.anim.animation_move_left);
b.startAnimation(anim);
flagToggleButton = false;
}
}
});
}
}
Make it a member variable of your class. In other words, define it outside onCreate()
public class Main extends Activity {
boolean flagToggleButton = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
// rest of your code
Put globally
boolean flagToggleButton = false;
b.setOnClickListener(new OnClickListener () {
#Override
public void onClick(View arg0) {
if (!(flagToggleButton)) {
// do stuff..
flagToggleButton = true;
}
else {
// do stuff..
flagToggleButton = false;
}
}
});

Categories

Resources