How can I change the sleep time of thread in run time? - java

I am developing a flashlight app. I want to change the sleep time of thread when I change the value on seek bar, but it is not implementing on runtime instead I have to stop the thread every time to get the new value of from seeking bar.` seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
value = progress;
Toast.makeText(getApplicationContext(), "changing"+value, Toast.LENGTH_SHORT).show();
}
> Here the code for creating and setting the value for the thread
public void threadinit(final int value)
{
this.value= value;
t = new Thread(new Runnable() {
#Override
public void run() {
boolean stopExecution;
final boolean toExit = false;
//while( blinks=true)
while (!t.isInterrupted()) {
params = camera.getParameters();
params.setFlashMode(Camera.Parameters.FLASH_MODE_OFF);
camera.setParameters(params);
camera.stopPreview();
try {
Thread.sleep(value);
Would be very thankful for your answers

Thread.sleep() is not guaranteed. This means that it may or may not sleep for the duration you desire for various reasons that are out of topic for this question.
check this link
How to change the delay of sleep/timer thread in android during runtime?

I would not use sleep() and interrupt() for this but rather the wait() and notify() mechanism.

Related

java.lang.illegalStateException when getting mediaPlayer.getCurrentPosition and SeekBar going to Intial on Pause

I'm getting java.lang.IllegalStateException in my Android Music Player Application every time when I closes the Activity
mCurrentPosition = mediaPlayer.getCurrentPosition()/1000; // In milliseconds
I've tried nearly all the codes available and even all at java.lang.illegalStateException randomly occurs when getting mediaPlayer.getCurrentPosition also
Here's my Java code where I'm using it:
protected void initializeSeekBar(){
mSeekBar.setMax(mediaPlayer.getDuration()/1000);
mRunnable = new Runnable() {
#Override
public void run() {
int mCurrentPosition;
if(mediaPlayer!=null && mediaPlayer.isPlaying()){
mCurrentPosition = mediaPlayer.getCurrentPosition()/1000; // In milliseconds
}
else {
mCurrentPosition = 0;
}
if (mSeekBar != null) {
mSeekBar.setProgress(mCurrentPosition);
getAudioStats();
}
handler.postDelayed(mRunnable,1000);
}
};
handler.postDelayed(mRunnable,1000);
}
Please Help me out of this. Thanks in Advance
Edit 1
Also, my Seekbar goes to start when the music pauses and on play, it continues from where it was before pausing
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
#Override
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
getAudioStats();
initializeSeekBar();
if(mediaPlayer != null && fromUser) {
mediaPlayer.seekTo(progress * 1000);
}
}
#Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
#Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
protected void getAudioStats(){
long duration = mediaPlayer.getDuration()/1000; // In milliseconds
long due = (mediaPlayer.getDuration() - mediaPlayer.getCurrentPosition())/1000;
long pass = duration - due;
String test = DateUtils.formatElapsedTime(pass);
String test1 = DateUtils.formatElapsedTime(due);
current_time.setText("" + test);
//mDuration.setText("" + duration + " seconds");
total_time.setText("" + test1);
}
You need to remove your runnable from the handler queue when the activity closes (or, better yet, when it pauses). Try putting this in your activity's onPause() method:
handler.removeCallbacks(mRunnable);
For additional robustness, inside the runnable itself, you should only re-queue the runnable if the activity is still active. So instead of this:
handler.postDelayed(mRunnable,1000);
you should do this (assuming this code is in the activity class):
if (!isDestroyed()) {
handler.postDelayed(mRunnable,1000);
}
Also make sure you are stopping the media player before the activity is destroyed.
P.S. If you call initializeSeekBar() multiple times, you will be reassigning mRunnable and leaving the old one in the handler queue where it can cause trouble later. To fix this, you should add this at the start of initializeSeekBar():
protected void initializeSeekBar(){
if (mRunnable != null) {
handler.removeCallbacks(mRunnable);
}
// ... the rest of the method that you currently have

removeCallbacks() doesn't seems to delete the specified Runnable in Handler

I developed an standalone app for a smartwatch, and I want to have an OnTouchListner which detect if a Touch lasted for at least 3 sec and perform action only in that case.
Here is the code I use : (a simple boolean state which is set to false when MotionEvent is up and a PostDelayed action on the Handler)
private int longClickDuration = 3000;
private boolean isLongPress = false;
static Runnable longTouchRunnable;
mContainerView.setOnTouchListener(new View.OnTouchListener() {
#Override
public boolean onTouch(View v, MotionEvent event) {
longTouchRunnable = new Runnable() {
#Override
public void run() {
if (isLongPress) {
Vibrator vibrator = (Vibrator) getSystemService(VIBRATOR_SERVICE);
long[] vibrationPattern = {0, 500, 50, 300};
//-1 - don't repeat
final int indexInPatternToRepeat = -1;
vibrator.vibrate(vibrationPattern, indexInPatternToRepeat);
// set your code here
setStateStarting(); //Block the GUI, only one click and waiting for tablet
presenter.onStartClick();
Log.d("Long","LONG CLICK PERFORMED");
// Don't forgot to add <uses-permission android:name="android.permission.VIBRATE" /> to vibrate.
}
}
};
switch (currentState) {
case START: {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
isLongPress = true;
Log.e("Long touch","Start");
myUIHandler.postDelayed(longTouchRunnable, longClickDuration);
} else if (event.getAction() == MotionEvent.ACTION_UP) {
isLongPress = false;
myUIHandler.removeCallbacks(longTouchRunnable);
Log.e("Long touch", "Stop");
}
return true;
}
}
return false;
}
});
My problem :
Everything work perfectly expect that the Runnable doesn't seem to be delete when it's necessary.
--> If I click quickly two times on the view and then a third time and holding it (So the boolean state is true for the three PostDelayed which came after 3 sec) I will have my specific action code executed 3 times --> the Runnable task wasn't removed with the ACTION_UP event.
Info : The message debug are prompt as expected...
How can I properly destroy a Runnable that was postdelayed in a handler ?
Thanks
handler.removeCallbacksAndMessages(null);
In the docs for removeCallbacksAndMessages it says...
Remove any pending posts of callbacks and sent messages whose obj is token. If a token is null, all callbacks and messages will be removed.
removeCallbacks only stops pending messages (Runnables). If your runnable has already started, then there's no stopping it (at least not this way).
Alternatively, you can extend the Runnable class and give it some kind of kill switch like this:
public class MyRunnable implements Runnable
{
public boolean killMe = false;
public void run()
{
if(killMe)
return;
/* do your work */
}
public void killRunnable()
{
killMe = true;
}
}
This will only prevent it from starting, but you could occasionally check killMe and bail out. If you are looping the runnable (like some kind of background thread) you can say:
while(!killMe) {
/* do work */
}

Avoid Thread has already been started exception (Android)

java.lang.IllegalThreadStateException: Thread already started
at java.lang.Thread.checkNotStarted(Thread.java:849)
at java.lang.Thread.start(Thread.java:1059)
at com.name.MainActivity$MenuView$1.surfaceCreated(MainActivity.java:496)
How can I avoid this? I have an inner class MenuView which extends SurfaceView. It updates a canvas on a thread. onSurfaceCreated() I start the thread, and onSurfaceDestroyed() I call thread.join() to stop the thread. However, if the Google Play Sign in window pops up, and I press the home button while it is in focus, and reopen the app. I get a force close error and the exception that I posted above.
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceCreated(SurfaceHolder holder) {
allow_thread_to_run = true;
boolean retry = true;
while (retry) {
if (t!=null && !t.isAlive()) {
t.start();
retry = false;
}
}
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
allow_thread_to_run = false;
boolean retry = true;
if(t!=null && t.isAlive()) {
while (retry) {
try {
t.join();
retry = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
});
}
So why does this Google Play window coming into focus cause my thread to start twice. From what I see, my setup has the necessary check isAlive() to make sure to avoid this!
I agree with #adelphus's view.If you care for the code of Thread calss,you will find that.Every Thread object has a flag that reflects whether this Thread has already been started.
boolean hasBeenStarted = false;
Once you invoke start() method,it will check the state and change if it is false,otherwise throw an exception like what you have got.see,
public synchronized void start() {
checkNotStarted();
hasBeenStarted = true;
nativeCreate(this, stackSize, daemon);
}
later,the state will never be changed. When you invoke start() again,it will throw an exception.

Avoid multi-click in image view android

I try to use this code to prevent multi-click in ImageView but it doesn't help.
Boolean isClicked = false;
#Override
public void onClick(View v)
{
if (v == imgClick && !isClicked)
{
//lock the image
isClicked = true;
Log.d(TAG, "button click");
try
{
//I try to do some thing and then release the image view
Thread.sleep(2000);
} catch (InterruptedException e)
{
e.printStackTrace();
}
isClicked = false;
}
}
In the log cat, I can see 5 lines "button click" when I click on ImageView for 5 times as quickly as possible. I can see the log cat print the first line, wait for a while (2 seconds) and then print the next line. I think when I click the ImageView, the fired event is moved to queue in order, isn't it?. So how can I stop that?
I also try to use setEnable() or setClickable() instead of isClicked variable but it doesn't work too.
Just try this working code
Boolean canClick = true; //make global variable
Handler myHandler = new Handler();
#Override
public void onClick(View v)
{
if (canClick)
{
canClick= false; //lock the image
myHandler.postDelayed(mMyRunnable, 2000);
//perform your action here
}
}
/* give some delay..*/
private Runnable mMyRunnable = new Runnable()
{
#Override
public void run()
{
canClick = true;
myHandler.removeMessages(0);
}
};
Instead of sleeping in 2 seconds, I use some task like doSomeThing() method (has accessed UI thread), and I don't know when it completed. So how can I try your way?
//I referred this android link. You can handle thread more efficiently but i hope below code will work for you..
//you try this and
Boolean canClick = true; //make global variable
public void onClick(View v) {
if(canClick){
new DownloadImageTask().execute();
}
}
private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
protected Bitmap doInBackground(String... urls) {
Log.d("MSG","Clicked");
canClick =false;
//perform your long operation here
return null;
}
protected void onPostExecute(Bitmap result) {
canClick =true;
}
}
You could keep track of the last consumed click upon your View, and based on it either perform the necessary actions, or simply return:
private long calcTime;
private boolean isClickedLately(final long millisToWait)
{
if (System.currentTimeMillis() - calcTime < millisToWait)
return true;
return false;
}
#Override
public void onClick(View v)
{
if (isClickedLately(2000))
return;
calcTime = System.currentTimeMillis();
Log.d(TAG, "consuming button click");
// perform the necessary actions
}
With the millisToWait parameter you can adjust the threshold of "waiting", but if you know that you want to wait exactly 2 seconds between two consecutive clicks, you can eliminate it.
This way you don't have to deal with Threads, which is good, since it's not a great idea to make the gui thread wait.

Game Over and Pause/Resume taking care of the thread

I have a few issues I am having a hard time find good information on how to fix. First off I have a Game Over screen that shows up when it should. I have tried to use setting the Threads running to false so it stop running and then when the screen is touched to set it back to true, but it does not take the screen back to it running. Also I'm going to need to be able to actually clear all the times so that it resets it (what is a good way to do that). This similarly I will need I am assuming for the Pause and Resume. If running isnt set to false it appears to continue running even with sleep() just in slower increments. Here is my thread to see if you notice what I can do.
public class GameLoopThread extends Thread {
private GameView view;
public static boolean running = false;
static final long FPS = 10;
public GameLoopThread(GameView view) {
this.view = view;
}
public void setRunning(boolean run) {
running = run;
}
#Override
public void run() {
long ticksPS = 1000 / FPS;
long startTime;
long sleepTime;
while (running) {
Canvas c = null;
startTime = System.currentTimeMillis();
try {
c = view.getHolder().lockCanvas();
synchronized (view.getHolder()) {
view.onDraw(c);
}
} finally {
if (c != null) {
view.getHolder().unlockCanvasAndPost(c);
}
}
sleepTime = ticksPS-(System.currentTimeMillis() - startTime);
try {
if (sleepTime > 0)
sleep(sleepTime);
else
sleep(10);
} catch (Exception e) {}
}
}
}
Now this part is causing a large issue for the Pause/Resume. I have a handler.postDelayed handling the spawning of my sprites. Basically when the screen appears paused (cause it looks like it is if i use the sleep) the problem is that the handler (which is in the GameView) is seeming like the time is still running for it. Is there a way to reset it back to zero... preferably on both the classes for the Game Over and to pause the handler as well during the Pause? Thanks
EDIT: As of right now I'm trying to use an options menu to make a new game by making it reopen the activity that runs the game. It appears to reset it but it freezes it in the process. Anyone know how I can fix this?
#Override
public boolean onCreateOptionsMenu(Menu menu){
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case R.id.newgame:
GameView.gameState=0;
GameLoopThread.running=true;
Intent game = new Intent(PlayGame.this, PlayGame.class);
startActivity(game);
break;
case R.id.pause: Toast.makeText(this, "You pressed Pause", Toast.LENGTH_LONG).show();
break;
case R.id.quit: Toast.makeText(this, "You pressed Quit", Toast.LENGTH_LONG).show();
break;
}
return true;
}
Thats my options menu.
This may not seem like the anwser you are looking for, but if you want to create code that's easily extendable (and learn a new desgin pattern!) then this is the way to go.
Most games use a State Machine for these kind of things.
For example
interface GameState{
public void render(long elapsedTime);
}
Now you can create different states, like a MenuState, GameState, PauseState, OptionState, GameOverState, etc.
Some pseudo code to get the idea across:
State currentState = null;
public void run(){
while(true){
// Do your loop here
currentState.render(time);
}
}
public void setState(State state){
currentState = state;
}
States Example:
public class MenuState implements GameState{
public void render(long elapsedTime){
//Render menu here
}
}
Or
public class GameState implements GameState{
public void render(long elapsedTime){
//Render gameplay here
}
}
currentState points to the current state and decides which one gets rendered/updated. Just change it's reference and your pause menu gets drawn.
This is a very common design pattern in games, search around!
Good luck!

Categories