I am trying to write a new feature for a flashlight app. I am pretty sure I need a new Thread to do this. HOWEVER, I am new to Threads and do not know how to do it at all. What I am trying to do is on the change of a SeekBar, I want the strobe to get faster/ slower. If it is 0 or 1 resume to constant light.
This is wrong, but this is what I have. Whenever I move the SeekBar it correctly strobes, but you cannot make it stop..
In onCreate():
mSeekBar.setOnSeekBarChangeListener(new OnSeekBarChangeListener(){
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
final int myInt = progress;
new Thread (new Runnable() {
public void run() {
if (myInt>1)
strobeLight(myInt);
else {}
// Stop Strobe
} }).start();
}
public void onStartTrackingTouch(SeekBar seekBar) {}
public void onStopTrackingTouch(SeekBar seekBar) {}
});
strobeLight() method:
public void strobeLight(int myInt){
do {
if (myInt>1){
if (strobe){
processOffClick();
try { Thread.sleep(300/myInt); }
catch (InterruptedException e) {}
strobe=false;
strobeActivated=true;}
else{
processOnClick();
try { Thread.sleep(300/myInt); }
catch (InterruptedException e) {}
strobe=true; }
}
else{
processOnClick();
strobe=false;
Thread.currentThread().interrupt();
strobeActivated=false;}
} while (strobeActivated);
}
I am unsure about the need of creating a new thread every time the progress changes, a better approach might be to create a final runnable in which you change the integer value:
onProgressChange:
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromTouch) {
toRun.interval = progress;
}
A runnable-implementation:
class StrobeRunnable implements Runnable {
volatile boolean running;
volatile int interval = 0;
private boolean lightIsOn = false;
#Override
public void run() {
while(running){
if (interval > 1){
Thread.sleep(300/interval);
lightIsOn = !lightIsOn;
switchLight(lightIsOn);
}
else{
Thread.sleep(600/interval);
if( !lightIsOn ){
lightIsOn = true;
switchLight(lightIsOn);
}
}
}
}
};
Note that I created new names for some methods,
switchLight(boolean isLightOn) is what I believe your processXClick did before, namely switch the light on or of.
And interval used to be called myInt.
To start a thread I prefer to use Executors:
StrobeRunnable toRun = new StrobeRunnable();
Executor exec = Executors.newSingleThreadExecutor();
exec.execute(toRun);
To completely stop the thread from running, set the toRun.running to false, and this will stop the running loop.
I haven't tested this but it should work. It also depends a bit on how your processClick-method looks.
Related
I have looked everywhere to fix my problem but i just cant seem to get it going.
How do i make seekbar automatically with voice recorder ?
I have checked these links but did not find any solution
Move Seekbar not smooth
how to get seekbar to automatically move on song play?
lstfile.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
player = new MediaPlayer();
try {
player.setDataSource(listFiles[i].toString());
player.prepare();
player.start();
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
int videoduration=player.getDuration();
float progress=i/100.0f;
float time=videoduration*progress;
player.seekTo((int) time);
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
} catch (IOException e) {
e.printStackTrace();
}
}
});
You can use Handler with delay of 500ms or whatever you wish and update the seekbar inside the runnable method.
Refer below code,
Handler seekBarHandler = new Handler();
private final Runnable updateSeekBarPosRunnable = new Runnable() {
#Override
public void run() {
updateSeekPosition();
}
};
//UPDATE_FREQUENCY = 500ms or reduce/increase it as per your requirement
private void updateSeekPosition() {
seekBarHandler.removeCallbacks(updateSeekBarPosRunnable);
seekBarMusic.setProgress(mediaPlayer.getCurrentPosition());
seekBarHandler.postDelayed(updateSeekBarPosRunnable, UPDATE_FREQUENCY);
}
Now when you start recording start handler,
seekBarHandler.postDelayed(updateSeekBarPosRunnable, UPDATE_FREQUENCY);
when you stop the recorder remove the callback,
seekBarHandler.removeCallbacks(updateSeekBarPosRunnable);
I hope this may help you.
I have a code that plays 5 sounds with 1 second delay between the sounds and I want this part of code to be executed every 5 seconds (so it will run in a row so far as a boolean variable is true, and when it becomes false the tread run stopped - I have a button to both start and stop this executions). Everything works perfectly, but the issue is that I can't get rid of the 5 seconds delay in the first time I click the button, so when I first click, the sounds beggins only after 5 seconds. How can I make it start right away and only after the first time start taking the delays?
Here is the button onClick code:
public void clickHandlerStartTempo(final View view) {
if (!tempoOn) {
Toast toast = Toast.makeText(getApplicationContext(), "Start Tempo!", Toast
.LENGTH_SHORT);
toast.show();
tempoOn = true;
final Handler handler = new Handler();
final int delay = 5000; //milliseconds
handler.postDelayed(new Runnable() {
public void run() {
if (tempoOn) {
runCode(view);
handler.postDelayed(this, delay);
}
}
}, delay);
} else {
Toast toast = Toast.makeText(getApplicationContext(), "Stop Tempo!", Toast
.LENGTH_SHORT);
toast.show();
tempoOn = false;
}
}
And here is the runCode method:
public void runCode(View view) {
Runnable runnable = new Runnable() {
#Override
public void run() {
playSound(0);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i = 0; i < 4; i++) {
if (tempoOn) {
playSound(1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
return;
}
}
}
};
Thread thread = new Thread(runnable);
Log.i(TAG, "runCode: Thread id = " + thread.getId());
thread.start();
}
I'm new to android development and any help would be very much appreciated.
Thanks.
First you need to playsound without thread after that you will execute your reaming 5 second logic stop thread after 4 count.
public void onStartPress(){
playSound();
someMethod();
}
public void someMethod(){
Handler uiHandler = new Handler(Looper.getMainLooper());
uiHandler.postDelayed(new Runnable() {
#Override
public void run() {
playSound();
someMethod();
}
},1000);
}
Don't use actual Threads unless you really want to do something off the Ui thread. Most of the time you do want to keep things on the Ui thread.
For simple repeating tasks, you can easily repurpose the CountDownTimer class. Often with an (almost) infinite run time or Long.MAX_VALUE (292 million years). The fist onTick happens immediately after starting.
private CountDownTimer mTimer;
private void start() {
if (mTimer == null) {
mTimer = new CountDownTimer(Long.MAX_VALUE, 5000) {
#Override
public void onTick(long millisUntilFinished) {
// start a beeping countdown
new CountDownTimer(5000, 1000) {
private int state = 1;
#Override
public void onTick(long millisUntilFinished) {
playSound(state);
state = state + 1 % 2;
}
#Override
public void onFinish() {
playSound(0);
}
}.start();
}
#Override
public void onFinish() { /* ignore, never happens */ }
};
mTimer.start();
}
}
private void stop() {
if (mTimer != null) {
mTimer.cancel();
mTimer = null;
}
}
My Timer doesn't stop running if I cancel it!
The Timer only stops if I shut down the whole app!
I don't know why the Timer is not cancelled. If I print out every try on cancelling the Timer I get hundrets of lines but the Timer does not stop!
My Class:
public class PlayActivity extends AppCompatActivity
implements View.OnClickListener, SeekBar.OnSeekBarChangeListener, MediaplayerEvent {
//region Activity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Initialize_Layout();
Initialize_Objects();
}
#Override
protected void onResume() {
super.onResume();
MusicService.setMediaPlayerEvent(this);
txvSongtitle.setText(serviceInterface.MP_getActualSong().getTitle());
Start_Timer();
}
#Override
protected void onPause() {
timer.cancel();
MusicService.clearMediaPlayerEvent();
super.onPause();
}
#Override
public boolean onSupportNavigateUp() {
finish();
return super.onSupportNavigateUp();
}
//endregion
//region Methods
private void Start_Timer() {
timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
if (serviceInterface.MP_isPlaying()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
seekBar.setMax(serviceInterface.MP_getDuration());
seekBar.setProgress(serviceInterface.MP_getCurrentPosition());
}
});
}
else {
runOnUiThread(new Runnable() {
#Override
public void run() {
timer.cancel();
}
});
}
}
}, 0, 200);
}
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
if (fromUser) {
serviceInterface.MP_seekTo(progress);
Start_Timer();
}
}
//endregion
}
I hope you can help me!
Thanks!
I would suggest using a Thread instead of a Timer. Your Start_Timer()code would change to something like the following:
private Thread mTimerThread;
...
private void Start_Timer() {
mTimerThread = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
if (serviceInterface.MP_isPlaying()) {
runOnUiThread(new Runnable() {
#Override
public void run() {
seekBar.setMax(serviceInterface.MP_getDuration());
seekBar.setProgress(serviceInterface.MP_getCurrentPosition());
}
});
} else {
interrupt();
}
Thread.sleep(200);
}
} catch (InterruptedException e) {
}
}
}
mTimerThread.start();
}
Threads are more efficient and lightweight and perfect for your needs. Plus, by setting the Thread to a global variable, you can make sure to call mTimerThread.interrupt(); during Android lifecycle events, such as onPause().
I hope this fixes your issue. Remember, the Java Thread is your friend!
You're creating and starting a new timer the user moves the seekbar (in onProgressChanged()). That also means you lose the reference to the old one. When isPlaying turns false, all the timers will try to cancel timer -- which only references the most recent one.
I am writing a game in which after a specified amount of time a thread must be stopped.The user has failed to complete a particular level.I am using a thread.How do i stop this thread after a specified amount of time and display another view.How do i do this.The following code delays the launching of the thread by timelimit.
Thread t = ... t.join(timelimit);
if (t.isAlive)
t.interrupt();
How do i run the thread and close it after a period of time.
Your working thread
public class Worker extends Thread {
private boolean isRunning = true;
public void run() {
while (isRunning) {
/* do your stuff here*/
}
}
public void stopWorker() {
isRunning = false;
}
}
Your stopping thread
public class Stopper extends Thread {
private Worker worker;
public void Stopper(Worker w) {
worker = w;
}
public void run() {
// wait until your timeout expires
worker.stopWorker();
}
}
you should declare your thread with something like this
public class GameLoopThread extends Thread{
private boolean running = false;
public void setRunning(boolean run){
running = run;
}
#Override
public void run(){
while(running){
}
}
}
This is the safer way, In order to stop you should set the running variable to false. Otherwise If you stop the thead you will get an android exception .
I prefer interrupting the Thread from outside and checking interrupted state in short intervals:
try {
while (!Thread.currentThread.interrupted()) {
doSth();
}
} catch (InterruptedException e) {
// finished
}
you can use below code is run after given specified time.
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
// after this is rung
}
}, 5000);
Originally, I had a MediaPlayer mPlayers to play/pause/stop my Audio file. Now, I'm trying to add a seek bar for my media. I tried using Threads and this is what I came up with:
In onCreate() :
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
// TODO Auto-generated method stub
mPlayer.seekTo(progress);
}
////........Omitted Code..........\\\\
//At the very end of the method:
seekThread = new Thread(this); //My Activity implements:Runnable
seekThread.start();
Then, I implemented a method run() to update my seek bar every 1 sec:
public void run() {
try {
while(mPlayer != null){
int currentPosition = mPlayer.getCurrentPosition();
Message msg = new Message();
msg.what = currentPosition;
threadHandler.sendMessage(msg);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private Handler threadHandler = new Handler(){
public void handleMessage(Message msg){
seekBar.setProgress(msg.what);
}
};
However, In my HTC Magic, the audio run inefficiently. Some words are repeated. It seems like the seek bar is going back a little bit every some time.
To make you understand the problem well, Let's say this: if the audio says that: abcdefghijklmn , then it will be like this: abccdeffghijjklmnn.
Any improvement you suggest to my thread ? Am I doing it right?
Not sure this will help, but try:
seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
if (fromUser) {
mPlayer.seekTo(progress);
}
}
Without this condition, mPlayer.seekTo(progress); is called every time you call seekBar.setProgress(msg.what);