runOnUiThread() and infinite loop on Android - java

I do not understand the behaviour of my code. To summarize, I have an editText (variable hours in my code) that start with "00". I am creating a thread which prevents this editText to not have 2 digit. Let s assume that this editText cannot have more than 2 digits. What I am doing is that I create a thread. In this thread, whenever this editText does not have 2 digits(so 1 digit), I add to it a "0".
However, whenever I just put one digit on the editText, it is getting crazy and go into an infinite loop and other stuff that I don't understand. Here is my code:
Thread digitLessThanTwoThread;
EditText hours = (EditText) findViewById(R.id.hours);
digitLessThanTwoThread= new Thread(){
#Override
public void run()
{
while(true) {
if (hours.getText().toString().length() != 2 && !hours.isFocused()) {
main_activity.runOnUiThread(new Runnable() {
#Override
public void run() {
hours.setText("0" + hours.getText().toString());
}
});
}
}
}
};
digitLessThanTwoThread.start();
Moreover, at the end, The editText hours displayed "00".
I also get a message "suspending all threads took: XXX seconds" before doing anything actually!

There are two problems here. First, the simple one:
while(true)
This will run the thread at full power until as you seem to be noticing, the OS steps in to stop the runaway thread. You should instead add an addTextChangedListener() listener, for example.
The more complex one is:
main_activity.runOnUiThread(new Runnable() {
#Override
public void run() {
hours.setText("0" + hours.getText().toString());
}
});
I think you are assuming that this is executed synchronously, that is the setText() is executed before runOnUiThread() returns. However, it is asynchronous, so next time round the loop your if is still true, and you queue another action on the UI thread to set the text and so on, so the UI thread may never get a chance to run until the OS steps in to halt the runaway thread.

Related

onClick is not working until I comment the while Loop inside my function

I have a function goClicked which is a onClick method of "Go" button, but when clicking the button, the function is not executed (I am able to say this because the toast is not showing).
But if I comment the while loop then click on the "Go" button, the function is executed (the toast is appearing).
public void goClicked(View view) {
afterGoPressed();
Toast.makeText(MainActivity.this,"pressed",Toast.LENGTH_SHORT).show();
countDown();
correctCount = 0;
totalCount = 0;
TextView time = (TextView) findViewById(R.id.time);
String timetext = time.getText().toString();
while (!timetext.equals("0")) {
int sum = generateQuestion();
pickOption = generateOptions(sum);
}
}
By putting a tight loop like that into your code the Event Dispatch Thread (EDT) is "starved" and so the GUI never gets a chance to do anything.
A simple workaround would be add a bit of a sleep in the loop to let the EDT have a turn. But you really need to do a bit more research into how to do GUI programming.
As it stands the code looks like an infinite loop because the timetext variable used in the loop condition does not change inside the loop. timetext is presumably supposed to change in reaction to GUI events. If the GUI is starved and so doesn't get to run then timetext never changes.
I think you're dealing with an infinite loop.
If when you create the variable timetext the text contained in time is not 0, the variable timetext will never be 0, hence the condition to exit the loop is never met.
public void goClicked(View view) {
afterGoPressed();
Toast.makeText(MainActivity.this,"pressed",Toast.LENGTH_SHORT).show();
countDown();
correctCount = 0;
totalCount = 0;
TextView time = (TextView) findViewById(R.id.time);
String timetext = time.getText().toString(); // <--- this will never change
while (!timetext.equals("0")) {
int sum = generateQuestion();
pickOption = generateOptions(sum);
}
}
Sorry, I know this doesn't offer much of a practical solution to your issue. Maybe if you let us know what you're trying to achieve with that loop we can help a little better.
But for all I know, if you block a thread inside of the public void onClick(View view) method of a View.OnClickListener instance (either by making it sleep with Thread.sleep() or by running an infinite loop), it will also freeze the rest of your app until the onClick(View view) method finishes. That's why you can't even see the Toast appear, although it's before the while loop. Because the main Thread was notified that there has been a click event, but the response from that event is never arriving.

For Loop delay not working Android

I am a newbie to android development so bear with me. I have scoured the site and implemented several suggested answers but I am still running into a problem. I want to iterate through an object array and display the contents of the array with delay to allow user interaction(The user gets to say if the object and the text displayed is what they were looking for by clicking on a yes or no button). My objects however display last first and then start zooming real fast in a seemingly endless loop. Here is the method I call to load the images:
private void displayInstructions() {
for (Emergency_Instructions instruction : instructions) {
final Emergency_Instructions instruction2 = instruction;
final Handler handler = new Handler();
handler.postDelayed(new Runnable()
{
public void run() {
displayimages(instruction2.getStep(), instruction2.getStepImage());
handler.postDelayed(this, 5000);
}
}, 5000);
}
void displayimages(String text, Bitmap image)
{
instructiontext.setText(text);
instructionbmp.setImageBitmap(image);
}
Any help will be greatly appreciated
You create multiple Handlers where you need only one. You tell each one to post a Runnable to the current thread's message queue, to be run after the same delay. That delay expires at pretty much the same time for all the tasks, so they are then executed one right after another, as fast as the queue can go. Each of those tasks also posts a message via the handler, to be run after the same delay. Once that delay expires, that will produce a second group of messages posted rapidly one right after the other, as fast as the device can go.
If you just want to schedule what is effectively a slide show, you might do it like this:
private void displayInstructions() {
final Handler handler = new Handler();
int delay = 0;
int step = 5000;
for (Emergency_Instructions instruction : instructions) {
final Emergency_Instructions instruction2 = instruction;
handler.postDelayed(new Runnable() {
public void run() {
displayimages(instruction2.getStep(), instruction2.getStepImage());
// handler.postDelayed(this, 5000);
}
}, delay);
delay += step;
}
}
Note there that each task is posted with a larger delay than the last -- this is a delay with respect to when the message it posted, not with respect to when the preceding message was displayed.
With that said, I'm doubtful that this is really what you want to do, or at least that it is all you want to do. As it stands, this approach will cause all the messages to be displayed (eventually) regardless of any user interaction. At minimum, you will probably want to provide for subsequent messages to be canceled in the event that the user accepts one, or cancels the overall operation.

Problems increasing an integer in android studio

I am making an android studio app and am trying to get my screen to loop through the digits 0-9 until the user clicks and stops the loop on a particular number. The code I have written so far is:
public void loop () {
for (int a = 0; a<10; a = ++a % 10) {
textView2.setText("" + a);
}
Relevant xml section
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="0"
android:id="#+id/textView2"
.../>
This code doesn't output anything onscreen. I have tried a few different variations of the code and if it does display a number, it only displays the last digit, '9'. This makes me think that it has worked but it goes through the numbers too quickly for me to see and stops on the last one instead of looping indefinitely. Is anyone able to point out where I may be going wrong? I'm still learning so apologies for the relatively simple query.
Also when I do get it to work, and I want to make it clickable, do I put the onclicklistener in the for-loop?
Many thanks.
You were right, when it displays 9, it just looped through the numbers very quickly, you couldn't even see them changing.
You are not doing anything wrong, you just have to take pauses between changing the numbers. The very easy and ugly fix would be adding: wait(1000) after the setText(...) method.
However, this is not recommended, because Android draws and receives events on the main thread. When you block the thread for 1000 milliseconds with the wait, you make the thread unable to accept any events for that one second, which makes your app freeze.
To fix the freezing, you need to update your TextView, and then post a message on the main thread, that it should update again over 1 second. Because of the separation, it won't really look like a loop.
For posting messages on the main thread, I will use a Handler (android.os.Handler), which executes messages on the thread it was created, unless you use a different Looper.
Here's a rough example:
private int a = 0;
private Handler handler = new Handler();
private TextView textView2;
public void loop() {
handler.post(new Runnable() {
#Override
public void run() {
updateText();
a = a++ % 10;
if (a < 10) {
handler.postDelayed(this, 1000);
}
}
});
}
public void updateText() {
textView2.setText("" + a);
}
Just call loop() when the button was clicked, the rest will be handled automatically.

Is it possible to pause a sleeping thread in Java

Edit, found a work around, code is posted at the bottom.
Is it possible to pause a thread that's in the middle of using thread.sleep(sleeptime)? And then when it's resumed, sleep for the remaining time?
I tried implementing the wait/notify set up here to pause a thread
How to pause/resume thread in Android?
However, it looks like it waits until thread.sleep is finished with it's sleeping time.
The reason why I am asking this because I am using a while loop inside a thread to play music from a play list, and I need the thread to sleep for the duration of the music track so that the music track finishes before the while loop plays the next song on the playlist.
For example, the while loop will play a song that has a duration of 50 seconds, so the thread.sleep method will pause the thread that contains the while loop. But, the user wants to the pause the song, and the whole play list 25 seconds into the song. So the user will press the pause button 25 seconds into thread.sleep's 50 second sleep. After the user unpauses, I would like the thread.sleep to continue the rest of 50 second wait (25 seconds left at this point) to complete playing the rest of the song. Then the while loop will play the next track on the playlist.
Runnable whilePlay2 = new Runnable() {
#Override
public void run(){
while (k <= myIntArray2.size()-1 ) {
System.gc();
if( myIntArray2.get(k)>count){
video_column_index = videocursor
.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
videocursor.moveToPosition(myIntArray2.get(k)-count);
filename2 = videocursor.getString(video_column_index);
}
else{
music_column_index = musiccursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
musiccursor.moveToPosition(myIntArray2.get(k));
filename2 = musiccursor.getString(music_column_index);
}
try {
if (m2MediaPlayer.isPlaying()) {
m2MediaPlayer.reset();
}
m2MediaPlayer.setDataSource(filename2);
m2MediaPlayer.prepare();
m2MediaPlayer.start();
Thread.sleep(m2MediaPlayer.getDuration());
synchronized(Lock){
while(onS){
Log.i("should be", "waiting");
Lock.wait();
}
}
Log.i("what is on", "on is"+onS);
Log.i("k Check", "k is" +k);
} catch (Exception e) {
}
m2MediaPlayer.stop();
m2MediaPlayer.reset();
k++;
}
} //closes public void run(){
// TODO Auto-generated method stub
};
Thread whilePlay2T = new Thread(whilePlay2);
whilePlay2T.start();
And here is my pause button
public void onToggleClicked(View view) {
// Is the toggle on?
boolean on = ((ToggleButton) view).isChecked();
if (on) {
mMediaPlayer.pause();
length=mMediaPlayer.getCurrentPosition();
m2MediaPlayer.pause();
length2=m2MediaPlayer.getCurrentPosition();
synchronized (Lock){
onS=true;
}
} else {
mMediaPlayer.seekTo(length);
mMediaPlayer.start();
m2MediaPlayer.seekTo(length2);
m2MediaPlayer.start();
synchronized (Lock){
onS=false;
Lock.notifyAll();
}
}
}
EDIT
Looks like I can't use it. So now I am using a recursive function instead of a while loop to set up my play list. Here's what one of them looks like.
public void hiplaylist2(int t2) {
k=t2;
if(k <= myIntArray2.size()-1 ){
System.gc();
if( myIntArray2.get(k)>count){
video_column_index = videocursor
.getColumnIndexOrThrow(MediaStore.Video.Media.DATA);
videocursor.moveToPosition(myIntArray2.get(k)-count);
filename2 = videocursor.getString(video_column_index);
}
else{
music_column_index = musiccursor
.getColumnIndexOrThrow(MediaStore.Audio.Media.DATA);
musiccursor.moveToPosition(myIntArray2.get(k));
filename2 = musiccursor.getString(music_column_index);
}
try {
if (m2MediaPlayer.isPlaying()) {
m2MediaPlayer.reset();
}
m2MediaPlayer.setDataSource(filename2);
m2MediaPlayer.prepare();
m2MediaPlayer.start();
//Thread.sleep(mMediaPlayer.getDuration());
//SystemClock.sleep(mMediaPlayer.getDuration());
Log.i("k Check", "k is" + k);
} catch (Exception e) {
}
}
m2MediaPlayer.setOnCompletionListener(new OnCompletionListener()
{
public void onCompletion(MediaPlayer m2MediaPlayer){
m2MediaPlayer.stop();
m2MediaPlayer.reset();
if(k < myIntArray2.size()-1 ){
k++;
hiplaylist2(k);
}
}
});
};
And then I ues a thread to have more than one of these run at the same time.
I don't really get it. I'm not sure about what you want to do, but i guess that there are at least two problems into your algorithm.
Firstly, when you work on concurrent tasks take care of your race conditions, your m2MediaPlayer seems to be one of them.
Concerning your Thread.sleep(m2MediaPlayer.getDuration()); I believe that you shouldn't do it this way, if you want to wait until your song is finished you just have to :
Launch your song from Thread 1
Pause your Thread 1 (wait)
The song is playing in Thread 2
When the song is finished wake up (notify) your Thread 1 from Thread 2 (and let T2 die)
Note that you have to keep your code as simple as you can, because concurrency is hell.
Is it possible to pause a thread that's in the middle of using thread.sleep(sleeptime)? And then when it's resumed, sleep for the remaining time?
Assuming that you are asking about the behaviour of the Java runtime libraries, then the answer is No.
There is no safe way to pause and resume a thread. The Thread suspend / resume methods for doing this are unsafe and were deprecated in Java 1.1. (Read this if you want an explanation.)
Even if you use the unsafe methods, they do not magically pause a sleep timer. In fact, it is not clear what would happen to a sleeping thread: it is not specified.
Indeed, I would not totally be surprised if you found that a sleeping thread whose sleep time expired while suspended never woke up ...
I'll leave it to others to deal with the rest of your question.
(I can't figure out from your description what it is you are trying to do here ... and why you even need to pause a sleeping thread. On the face of it, it sounds like you should be using wait / notify or a higher level synchronization class ... rather than sleeping. The fact that you apparently tried and failed does not make that the wrong solution.)

With each successive call to this `timerMethod` , timerInt's value increases faster than before

I am working on an app, which gets a sort of restart with an event. On the first run, the timer works perfect (1sec = 1 increment). but, on next run (1sec = 2 increment) on third run (1sec = 4 increment) and so on...
I think there is something wrong with the new TimerTask object being created. but, dunno how to handle it. any suggestion or alternate ?
CODE SNIPPET:
Timer t = new Timer();
void timerMethod()
{
t.schedule(new TimerTask() {
public void run() {
timerInt++;
//TODO bug in timer in consecutive runs. To confirm, see log
Log.d("timer", "timer " + timerInt);
/* runOnUiThread(new Runnable() {
#Override
public void run() {
timerDisplayPanel.setText( timerInt + " Sec");
}
});*/
}
}, 1000, 1000);
}
It sounds like you're calling timerMethod() multiple times.
When you've called it three times, you've got three timer tasks scheduled - so they'll all fire each second, and all increment timerInt. You either need to not call it multiple times, or cancel the existing timer tasks before adding more.
If that's not the case, please provide a short but complete program to show what's happening. The context is fairly vague at the moment.
The snippet you provided is working properly
1 sec 1 increment
2 sec 2 increment
3 sec 3 increment
etc
So probably the problem is somewhere else in your code.

Categories

Resources