I am starting a thread when invoking a method to play an audio file.
The code runs ok the first time but when I call the play method again I need the thread to start as if it were being called the first time. I have tried to interrupt the thread and even stop it but nothing seems to work.
How can I properly restart the thread?
Here is some code to help explain.
Global variable
private Thread thread1;
Thread code:
thread1 = new Thread(new Runnable()
{
#Override
public void run()
{
try {
int i=0;
final TextView timeDuration = (TextView) findViewById(R.id.timeDisplay);
final SeekBar seekBar = (SeekBar)findViewById(R.id.seekBar1);
while (running)
{
info();
j = 0;
while(i>0 && running)
{
while(j<duration && running && (playStatus.getValue() == "TRANSITIONING" || playStatus.getValue() == "PLAYING"))
{
seekBar.setMax((int) duration);
seekBar.setProgress(0);
runOnUiThread(new Runnable()
{
public void run()
{
System.out.println("PLAYBACK STATUS: "+playStatus.getValue());
timeDuration.setText(""+(j+1));
seekBar.setProgress(j+1);
if(j==(duration-1))
{
setRunning(false);
}
}
});
Thread.sleep(1 * 1000);
j++;
if(seekBar.getProgress() == seekBar.getMax())
{
runOnUiThread(new Runnable()
{
public void run()
{
playButton.setVisibility(View.VISIBLE);
pauseButton.setVisibility(View.GONE);
timeDuration.setText(""+"0");
seekBar.setProgress(0);
flag = false;
System.out.println("J VALUE 1: = "+j);
duration = 0;
setRunning(false);
}
});
}
}
}
j = 0;
i++;
Thread.sleep(1 * 1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
play();
This code works fine and plays the track. It then resets the seekbar and awaits for the play method to be called again.
public void play()
{
try
{
thread1.start();
}
catch(Exception e)
{
return;
}
}
Here is the setRunning method recommended to me.
public void setRunning(boolean b)
{
this.running = b;
}
If anyone know of a solution to this problem I would really appreciate it.
Threads are not supposed to be stopped manually. You should use a boolean instead of true in your while loop, and put the boolean to false through a setter when you want to stop:
private boolean running;
#Override
public void run(){
running = true;
while(running) {...}
}
public void setRunning(boolean b){
this.running = b;
}
To restart your player you need to prepare again.
public void restartAudio() {
Log.e(TAG, "restartAudio");
if (mp.isPlaying()) {
mp.seekTo(0);
}else{
mp.stop();
try {
mp.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
When using extra boolean flag to controll thread's while loop don't forget to use volatile modifier on it:
private volatile boolean running;
or put appropriate synchronization.
Apart from that, I'd think about using Thread.isInterrupted() method instead of the additional 'running' flag:
http://docs.oracle.com/javase/6/docs/api/java/lang/Thread.html#isInterrupted()
here's why:
https://stackoverflow.com/a/3196058/1350225
Related
I am trying to update seekbar with respect to the progress of the song in MediaPlayer.
I am using Thread to do that task.
First i have used Thred inside thread and trying to update the UI but it crashing the app and says that only original thread can attached to the view.
Then i have try to update it with handler inside the thread runnable. which works fine but it is not updating the seekbar. When i have do log then i come to know loop is not going inside my handler. I dont know where is the problem. Please help me to updating SeekBar.
Code:
private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
try {
if ((musicPath != mIRemoteService.getPath())) {
System.out.println("..... MUSIC CHANGE.....");
setOrUpdateData();
updateFragmentLayout();
}
// Displaying Current Duration time/Progress
new Handler().post(new Runnable() {
#Override
public void run() {
try {
songCurrentDurationLabel.setText(""+ Utilities.milliSecondsToTimer(mIRemoteService.position()));
songProgressBar.setProgress((int)mIRemoteService.position());
System.out.println("Runnnnn.........");
//songProgressBar.invalidate();
} catch (RemoteException e) {
e.printStackTrace();
System.out.println("Runnnnn......... EXCEPTION....");
}
}
});
System.out.println("Runnnnn.........MAIN....");
if (!(mIRemoteService.isPlayerRunning())) {
btnPlay.setImageDrawable(getResources().getDrawable(R.drawable.play_now_playing));
mHandler.removeCallbacks(mUpdateTimeTask);
System.out.println("Runnnnn.........MAIN....IF");
}else{
System.out.println("Runnnnn.........MAIN....ELSE");
mHandler.post(mUpdateTimeTask);
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
you can use either a handler or a thread, with thread you should make sure to post the modifications on the UI thread:
private class UpdateSeekBar extends Thread
{
#Override
public void run()
{
super.run();
while (null != mp && mp.isPlaying() && this.isAlive())
{
//final int min = (mp.getCurrentPosition() / 1000) / 60;
//final int sec = (mp.getCurrentPosition() / 1000) % 60;
MainActivity.this.runOnUiThread(new Runnable()
{
#Override
public void run()
{
try
{
songCurrentDurationLabel.setText("" + Utilities.milliSecondsToTimer(mIRemoteService.position()));
songProgressBar.setProgress((int) mIRemoteService.position());
System.out.println("Runnnnn.........");
// songProgressBar.invalidate();
}
catch (RemoteException e)
{
e.printStackTrace();
System.out.println("Runnnnn......... EXCEPTION....");
}
}
});
try
{
Thread.sleep(1000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
I'm facing with a problem. I want to get duration of video when i 'm recording it.
I can get duration of video when it's finish by code
MediaPlayer mp = MediaPlayer.create(mContext, Uri.parse(video));
if(mp == null)
return -1;
int duration = mp.getDuration();
mp.release();
But i want to get duration everytime when i record video to update to progressbar.
Hope your reply!
private class PlaybackObserver extends Thread {
public void run() {
currentPosition = 0;
try {
while (!killObserverThread) {
Thread.sleep(1000);
currentPosition = (int) mediaPlayer.getCurrentPosition();
runOnUiThread(new Runnable() {
public void run() {
yourProgressBar.setProgress(currentPosition);
}
});
}
} catch (IllegalStateException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
#Override
protected void onDestroy() {
super.onDestroy();
killObserverThread = false;
}
#Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
if (task == null || !task.isAlive()) {
task = new PlaybackObserver();
task.start();
}
startPlaying();
}
add a private class for your UiThread to update your seekbar/progressbar. Then start it from onResume()
I have searched about kill the Runnable but i could not find the true answer with this code.I have tried boolean and stop() method.Can somebody help me to kill this runnable? Thanks.
Runnable runnable = new Runnable() {
#Override
public void run() {
while(true) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
myL.setBackgroundResource(R.drawable.close);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MainActivity.this.runOnUiThread(new Runnable() {
#Override
public void run() {
myL.setBackgroundResource(R.drawable.open);
}
});
}
}
};
new Thread(runnable).start();
you can set your exit condition:
private class MyThread extends Thread {
private boolean volatile exit = false;
#Override
public void run() {
while(!exit) {
}
}
public void stopMyThread() {
exit = true;
}
}
and from your code you call
myThreadInstance.stopMyThread();
when you need to make you run method finish
You are repeating infinitely a one-second-wait. This will never stop. You need to have a boolean flag which will serve as the continue/stop condition and you need to negate its value when the Thread needs to stop.
If you want to stop it from another Thread, then call Thread.interrupt.
public class MainActivity extends Activity implements Runnable{
private int progressBarStatus = 0;
private Handler progressBarHandler = new Handler();
ProgressBar linProgressBar;
private long fileSize = 0;
Thread t1;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button b1 = (Button)findViewById(R.id.button1);
Button b2 = (Button)findViewById(R.id.button2);
b2.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
linProgressBar.setProgress(0);
t1.interrupt();
}
});
b1.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View arg0)
{
basicInitializations();
}
});
}
public void basicInitializations(){
linProgressBar = (ProgressBar) findViewById(R.id.progressBar1);
linProgressBar.setProgress(0);
linProgressBar.setMax(100);
try{
t1 = new Thread()
{
public void run() {
while (progressBarStatus < 100) {
// process some tasks
progressBarStatus = doSomeTasks();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Update the progress bar
progressBarHandler.post(new Runnable() {
public void run() {
linProgressBar.setProgress(progressBarStatus);
}
});
}
if (progressBarStatus >= 100) {
try {
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
t1.start();
}catch (Exception e) {
}
}
public int doSomeTasks() {
while (fileSize <= 1000000) {
fileSize++;
if (fileSize == 100000) {
return 10;
} else if (fileSize == 200000) {
return 20;
} else if (fileSize == 300000) {
return 30;
}else if (fileSize == 400000) {
return 40;
}else if (fileSize == 500000) {
return 50;
}
}
return 100;
}
#Override
public void run() {
// TODO Auto-generated method stub
}
}
this is my main code and i could not stop this thread .
i want to stop it when i click the button b2(say cancel button).
the above code is not the original code and is a model , so please tell me how to stop that thread .
thankyou in advance . . . .
I have a alternate answer can try the same, inside your runnable loop always check a flag as run_flag, create it as a member variable and set it as true once you stared the loop, you can make it run_flag as false wenever you are done and at the same time you can set null to your thread also ... a safer way to come out through runnable loop and thread.
try{
t1 = new Thread()
{
public void run() {
while (progressBarStatus < 100 && run_flag == true) { // added run_flag here
// process some tasks
progressBarStatus = doSomeTasks();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// Update the progress bar
progressBarHandler.post(new Runnable() {
public void run() {
linProgressBar.setProgress(progressBarStatus);
}
});
}
if (progressBarStatus >= 100) {
try {
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
};
t1.start();
}catch (Exception e) {
}
Your thread spends most of its time in Thread.sleep(), which is helpful. The thread pointer, t1, is a class member, which is also helpful. From your button handler, you can check to see if t1 is still alive and, if so, call t1.interrupt();. This will cause the thread's current sleep and future sleeps to throw the InterruptedException... now you just need to modify your exception handler to quit the thread in that case.
So I am trying to create a "strobe" light effect in my app.
To do this I need a time delay, one of 100ms the other of 20.
Here is the code I'm using.
Thread timer = new Thread();
long longTime = 100;
long shortTime = 20;
for (int x = 0; x < 2000000; x++)
{
layout.setBackgroundColor(background);
try {
timer.sleep(longTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
layout.setBackgroundColor(backgroundBlack);
try {
timer.sleep(shortTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
The issue I have is that when I click the button to call that code, nothing happens. So I've done a bit of debugging and am pretty sure it is the timing call. I have never programmed in Java before so I am unsure how to call a Thread Sleep.
You could use a Handler as below to achieve this.
public class Strobe extends Activity {
private LinearLayout mLinearLayout;
private Handler mHander = new Handler();
private boolean mActive = false;
private boolean mSwap = true;
private final Runnable mRunnable = new Runnable() {
public void run() {
if (mActive) {
if (mSwap) {
mLinearLayout.setBackgroundColor(Color.WHITE);
mSwap = false;
mHander.postDelayed(mRunnable, 20);
} else {
mLinearLayout.setBackgroundColor(Color.BLACK);
mSwap = true;
mHander.postDelayed(mRunnable, 100);
}
}
}
};
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mLinearLayout = (LinearLayout) findViewById(R.id.strobe);
startStrobe();
}
private void startStrobe() {
mActive = true;
mHander.post(mRunnable);
}
}
Set a Theme to the Activity to make it full screen.
android:theme="#android:style/Theme.NoTitleBar.Fullscreen"
I think this article would benefit you.
http://oreilly.com/catalog/expjava/excerpt/index.html
specifically this
http://oreilly.com/catalog/expjava/excerpt/index.html#EXJ-CH-6-FIG-1
Your problem is that you are not running in the Thread. In order to run code in the thread you must override it's run() method. Based on your current code, the following may capture what you want to do.
Thread timer = new Thread(){
public void run(){
long longTime = 100;
long shortTime = 20;
for (int x = 0; x < 2000000; x++)
{
layout.setBackgroundColor(background);
try {
Thread.sleep(longTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
layout.setBackgroundColor(backgroundBlack);
try {
Thread.sleep(shortTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}
timer.start();
However, threads don't play that well with the Android OS. For your application, it may be better to use Android services. See http://developer.android.com/guide/topics/fundamentals/services.html .