how to stop a Runnable running on an UIThread - java

I have a Runnable on a UIThread updating a SeekBar while a MediaPlayer is playing. Yet, when I switch to another activity my application crashes with an exception cause the Runnable keeps on forever even after the MediaPlayer has been destroyed.
This is my code:
public class Guide extends AppCompatActivity implements MediaPlayer.OnPreparedListener {
Button back;
private MediaPlayer m_audio_player;
private Handler m_handler_seek_bar = new Handler();
private SeekBar m_seek_bar;
private Runnable m_seek_bar_runnable;
private void set_up_audio(){
m_audio_player = MediaPlayer.create(this, g_audio[NativeLib.get_active_landmark()] );
m_audio_player.setOnPreparedListener(this);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_guide);
implement_back_button();
set_up_audio();
}
#Override
protected void onStart() {
super.onStart();
set_up_seek_bar();
}
private void set_up_seek_bar() {
m_seek_bar = (SeekBar) findViewById(R.id.seek_bar);
m_seek_bar.setMax(m_audio_player.getDuration());
m_seek_bar_runnable = new Runnable() {
#Override
public void run() {
if(m_audio_player != null ){
m_seek_bar.setProgress(m_audio_player.getCurrentPosition());
}
m_handler_seek_bar.postDelayed(this, 1000);
}
};
// update Seekbar on UI thread
Guide.this.runOnUiThread(m_seek_bar_runnable);
m_seek_bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onStopTrackingTouch(SeekBar seekBar) { }
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if(m_audio_player != null && fromUser){
m_audio_player.seekTo(progress);
}
}
});
}
#Override
protected void onStop() {
if (debug_mode) Log.d(TAG, "onStop");
if (m_audio_player.isPlaying()) {
m_audio_player.stop();
}
m_audio_player.release();
super.onStop();
findViewById(R.id.activity_guide).removeCallbacks(m_seek_bar_runnable);
}
// return button
private void implement_back_button() {
final Intent intent = new Intent(/* pointing at some other activity */);
back = (Button) findViewById(R.id.back_button);
back.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(intent);
}
});
}
}

You need to use:
m_handler_seek_bar.removeCallbacks(m_seek_bar_runnable);
to remove the runnable from handler
#Override
protected void onStop() {
if (debug_mode) Log.d(TAG, "onStop");
if (m_audio_player.isPlaying()) {
m_audio_player.stop();
}
m_audio_player.release();
m_handler_seek_bar.removeCallbacks(m_seek_bar_runnable);
super.onStop();
}
Alternatively you can override the onPause() method of the activity:
#Override
protected void onPause() {
m_handler_seek_bar.removeCallbacks(m_seek_bar_runnable);
super.onPause();
}

Remove all the callbacks from the Handler in onStop using handler.removeCallbacks

Related

using BackPress method to release MediaPlayer class problem

the app works fine my only problem is I don't want to put a stop button rather I want the default backPress to stop and release MediaPlayer, so I added this:
public void onBackPressed(){
super.onStop();
mediaPlayer.release();
it works 1 time but pressing it again would crash the app
2020-07-10 16:23:54.943 6315-6315/com.example.schoolwork E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.schoolwork, PID: 6315
java.lang.IllegalStateException
at android.media.MediaPlayer.getCurrentPosition(Native Method)
at com.example.schoolwork.play_bidlisiw1.changeSeekbar(play_bidlisiw1.java:63)
at com.example.schoolwork.play_bidlisiw1.access$200(Play_bidlisiw1.java:12)
at com.example.schoolwork.play_bidlisiw1$3.run(play_bidlisiw1.java:69)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:941)
I am a beginner in coding java and new at using android studio. I am hoping anyone can teach me.
Thank you for your advice.
public class ark_play_bidlisiw1 extends AppCompatActivity implements View.OnClickListener {
private Button btnFor, btnBack, btnPlay;
private SeekBar seekBar;
private MediaPlayer mediaPlayer;
private Runnable runnable;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.play_bidlisiw1);
btnPlay = findViewById(R.id.btnPlay);
btnBack = findViewById(R.id.btnBack);
btnFor = findViewById(R.id.btnFor);
handler = new Handler();
seekBar = findViewById(R.id.seekbar);
mediaPlayer = MediaPlayer.create(this, R.raw.bidlisiw1);
btnFor.setOnClickListener(this);
btnBack.setOnClickListener(this);
btnPlay.setOnClickListener(this);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
seekBar.setMax(mediaPlayer.getDuration());
mediaPlayer.start();
changeSeekbar();
}
});
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
if(b){
mediaPlayer.seekTo(i);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
private void changeSeekbar() {
seekBar.setProgress(mediaPlayer.getCurrentPosition());
if(mediaPlayer.isPlaying()){
runnable = new Runnable() {
#Override
public void run() {
changeSeekbar();
}
};
handler.postDelayed(runnable, 1000);
}
}
#Override
public void onClick(View v) {
switch (v.getId()){
case R.id.btnPlay:
if(mediaPlayer.isPlaying()){
mediaPlayer.pause();
btnPlay.setText(">");
}else {
mediaPlayer.start();
btnPlay.setText("||");
changeSeekbar();
}
break;
case R.id.btnFor:
mediaPlayer.seekTo(mediaPlayer.getCurrentPosition()+5000);
break;
case R.id.btnBack:
mediaPlayer.seekTo(mediaPlayer.getCurrentPosition()-5000);
break;
}
}
public void onBackPressed(){
super.onStop();
mediaPlayer.release();
}
}

Android app to play mp3 file in specific time with countdown timer

I was trying to create an android app that should get time in minutes from a seek bar then it should begin to play a sound file until the countdown timer ends.
Things are mostly fine with the countdown timer BUT my question is how should I call some methods of the countdown timer instance when a button is pressed.
In the code below, I want to call onFinish() whenever the stop button pressed.
Here is my code:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
SeekBar sb = (SeekBar) findViewById(R.id.seekBar);
Button bt_stop = (Button) findViewById(R.id.btn1);
final TextView tv = (TextView)findViewById(R.id.textView);
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
int millisec_time = (i*60)/1000;
new CountDownTimer(millisec_time, 1000) {
public void onTick(long millisUntilFinished) {
tv.setText("seconds remaining: " + millisUntilFinished / 1000);
}
public void onFinish() {
tv.setText("done!");
}
}.start();
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
// Toast.makeText(getApplicationContext(),"GOT",Toast.LENGTH_LONG).show();
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
// Toast.makeText(getApplicationContext(),"OFF",Toast.LENGTH_LONG).show();
}
});
bt_stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
}
}
First, I'd recommend you only start your CountdownTimer in onStopTrackingTouch - reason being that currently you're creating a brand new timer every time the progress changes on your seekbar (which could be happening a lot).
Secondly, you'll need to retain a reference to your timer in order to cancel it. So:
public class MainActivity extends AppCompatActivity {
private CountdownTimer timer = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final SeekBar sb = (SeekBar) findViewById(R.id.seekBar);
sb.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
restartTimer(seekBar);
}
}
final Button bt_stop = (Button) findViewById(R.id.btn1);
bt_stop.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if(timer != null) {
timer.cancel();
}
}
});
}
private void restartTimer(SeekBar sb) {
if(timer!=null) {
timer.cancel();
}
final long millis = TimeUnit.SECONDS.toMillis(sb.getProgress());
final long interval = TimeUnit.SECONDS.toMillis(1);
timer = new CountdownTimer(millis, interval) {
#Override
public void onTick(long millisUntilFinished) {
tv.setText(String.format("Seconds Remaining: %d", TimeUnit.MILLIS.toSeconds(millisUntilFinished));
}
#Override
public void onFinish() {
tv.setText("done!");
}
}
timer.start();
}
}

How to implement admob rewarded video ads in a list view?

I want to know how to implement AdMob rewarded video ads in a list view?
I'm using the source code from here
and I want to use it in this class StickerPackDetailsActivity.java
and the layout is gonna like this
![layout][1]
I want to lock add to WhatsApp and unlock it by watching video reward.
but this stickerdetails showed from listview from
![here][2]
so, how to implement video reward ads only in 1 specified item of the listview not all of them?
public class MainActivity extends AppCompatActivity implements RewardedVideoAdListener {
private RewardedVideoAd mRewardedVideoAd;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MobileAds.initialize(this,"ca-app-pub111111111");
mRewardedVideoAd = MobileAds.getRewardedVideoAdInstance(this);
listitem.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
loadRewardedVideoAd();
}
});
}
private void loadRewardedVideoAd() {
mRewardedVideoAd.loadAd("ca-app-pub-",
new AdRequest.Builder().build());
}
#Override
public void onRewardedVideoAdLoaded() {
}
#Override
public void onRewardedVideoAdOpened() {
}
#Override
public void onRewardedVideoStarted() {
}
#Override
public void onRewardedVideoAdClosed() {
loadRewardedVideoAd();
}
#Override
public void onRewarded(RewardItem rewardItem) {
}
#Override
public void onRewardedVideoAdLeftApplication() {
}
#Override
public void onRewardedVideoAdFailedToLoad(int i) {
}
#Override
public void onRewardedVideoCompleted() {
}
#Override
protected void onPause() {
mRewardedVideoAd.pause(this);
super.onPause();
}
#Override
protected void onResume() {
mRewardedVideoAd.resume(this);
super.onResume();
}
}

New bie : Why is this code not able to read anything from the firebase database

The Following is my main activity, in another activity the user can login and upload audio files to the firebase storage; after that it saves the link and the current date time in the firebase database in reverse order.
The structure of the database is Audios> Feb 26,2018> "http:// link to firebase storage"
What I am trying to achieve in this activity is to read the link from the database> Store the value in the string value> and play it on mediaplayer but the following code is not able to read the link from the database for the life of me Please help me I am a new bie
package com.shresthawebworks.dailydevotional;
public class MainActivity extends AppCompatActivity implements MediaPlayer.OnPreparedListener{
private MediaPlayer mMediaplayer;
private ImageButton dplayButton;
private ImageButton dpauseButton;
private ImageButton dstopButton;
private SeekBar seekBar;
private Handler handler;
private Runnable runnable;
private TextView durl;
private TextView drealurl;
private String currentDateTimeString = DateFormat.getDateInstance().format(new Date());
private static final String TAG = null;
private String value = "Udated";
FirebaseDatabase database = FirebaseDatabase.getInstance();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
dplayButton = findViewById(R.id.playButton);
dpauseButton = findViewById(R.id.pauseButton);
dstopButton = findViewById(R.id.stopButton);
durl = findViewById(R.id.dateString);
drealurl = findViewById(R.id.urlText);
handler = new Handler();
seekBar = findViewById(R.id.seekBar1);
mMediaplayer = new MediaPlayer();
mMediaplayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
DatabaseReference myRef = database.getReference("Audios");
// Read from the database
myRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
value = (String) dataSnapshot.child(currentDateTimeString).getValue();
// do your stuff here with value
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
fetchAudioUrlFromFirebase();
//.setDataSource();
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean input) {
if (input){
mMediaplayer.seekTo(progress);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
configureNextButton();}
public void playCycle(){
seekBar.setProgress(mMediaplayer.getCurrentPosition());
if (mMediaplayer.isPlaying()){
runnable =new Runnable() {
#Override
public void run() {
playCycle();
}
};
handler.postDelayed(runnable,1000);
}
}
#Override
protected void onResume() {
super.onResume();
// mMediaplayer.resu;
playCycle();
}
#Override
protected void onPause() {
super.onPause();
mMediaplayer.pause();
playCycle();
}
#Override
protected void onDestroy() {
super.onDestroy();
mMediaplayer.release();
handler.removeCallbacks(runnable);
}
private void fetchAudioUrlFromFirebase() {
final FirebaseStorage storage = FirebaseStorage.getInstance();
durl.setText(currentDateTimeString);
drealurl.setText(value);
// Create a storage reference from our app
StorageReference storageRef = storage.getReferenceFromUrl("https://firebasestorage.googleapis.com/v0/b/dailydevotional-9f982.appspot.com/o/audios%2Ftwoprincess.mp3?alt=media&token=e3f98223-68e8-461a-8452-54eca96af4fd");
storageRef.getDownloadUrl().addOnSuccessListener(new OnSuccessListener<Uri>() {
#Override
public void onSuccess(Uri uri) {
try {
// Download url of file
final String url = uri.toString();
mMediaplayer.setDataSource(url);
// wait for media player to get prepare
mMediaplayer.setOnPreparedListener(MainActivity.this);
mMediaplayer.prepareAsync();
} catch (IOException e) {
e.printStackTrace();
}
}
})
.addOnFailureListener(new OnFailureListener() {
#Override
public void onFailure(#NonNull Exception e) {
Log.i("TAG", e.getMessage());
}
});
}
#Override
public void onPrepared(final MediaPlayer mp) {
dplayButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
seekBar.setMax(mp.getDuration());
mp.start();
playCycle();
}
});
dpauseButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mp.pause();
}
});
dstopButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
playCycle();
mp.stop();
mp.reset();
//fetchAudioUrlFromFirebase();
}
});
}
private void configureNextButton(){
ImageButton dButton= (ImageButton) findViewById(R.id.starLogin);
dButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
startActivity(new Intent(MainActivity.this, UploadActivity.class));
}
});
}
}

Need a sound to play every second if a button is toggled

I have a toggle button and i need the 'mp' sound to play every second if that button is toggled.The code below is what i tried and it does play the sound every second but the button stops responding so i can't turn it off.
ToggleButton btn = findViewById(R.id.button);
final MediaPlayer mp = MediaPlayer.create(this, R.raw.beat);
btn.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
while (isChecked) {
mp.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
Thank you in advance.
Never use Thread.sleep(1000) it is the terrible thing you can do to the app. Your app is not
responsding because you are putting Main thread of app to sleep.
I have created this class for you for desmonstration. you can tweak is further to your needs.
private Handler soundHandler = new Handler();
private int delay = 1000;
private Runnable soundRunnable;
private MediaPlayer mediaPlayer;
private boolean isToggleChecked;
#Override protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ToggleButton toggleButton = findViewById(R.id.button);
mediaPlayer = MediaPlayer.create(this, R.raw.beat);
toggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked){
isToggleChecked = isChecked;
if(isChecked){
playSound();
}else {
stopSound();
}
}
});
}
#Override protected void onResume(){
super.onResume();
if(isToggleChecked){
playSound();
}
}
// this will make sure sound stops when app stops or goes in background
#Override
protected void onPause() {
soundHandler.removeCallbacks(soundRunnable);
super.onPause();
}
private void playSound(){
soundHandler.postDelayed(new Runnable() {
public void run() {
soundRunnable = this;
if(mediaPlayer != null) {
mediaPlayer.start();
}
soundHandler.postDelayed(soundRunnable, delay);
}
}, delay);
}
private void stopSound(){
if(mediaPlayer != null){
if(mediaPlayer.isPlaying()){
mediaPlayer.stop();
soundHandler.removeCallbacks(soundRunnable);
}
}
}
I found an answer to another question and modified it to fit my needs and now it works perfectly.Here is the solution/code.
public class MainActivity extends AppCompatActivity {
MediaPlayer mediaPlayer = null;
int delayMillis;
Handler handler;
Runnable runnable;
private boolean isToggleChecked;
private ToggleButton toggleButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toggleButton = findViewById(R.id.button);
handler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
mediaPlayer.start();
}
};
toggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
if (isChecked) {
isToggleChecked = true;
toggleMediaPlayer();
}
else {
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
handler.removeCallbacks(runnable);
isToggleChecked = false;
}
}
});
}
#Override
public void onResume() {
super.onResume();
if (isToggleChecked) {
toggleButton.setChecked(true);
}
else {
toggleButton.setChecked(false);
}
}
private void toggleMediaPlayer(){
if(mediaPlayer != null){
mediaPlayer.stop();
mediaPlayer.release();
mediaPlayer=null;
handler.removeCallbacks(runnable);
}else{
mediaPlayer = MediaPlayer.create(this, R.raw.beat);
mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
#Override
public void onPrepared(MediaPlayer mp) {
mp.start();
}
});
mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
#Override
public void onCompletion(MediaPlayer mp) {
delayMillis = 1000;
handler.postDelayed(runnable,delayMillis);
}
});
}
}
}

Categories

Resources