Wait Function not working Android Studio - java

I am using Android Studio. I am trying to fix a clock in which I pressed the button, it will return the time to 12:00. I got it working but I want it to be executed by waiting 250 miliseconds. The problem is that they only wait for 250 miliseconds (but there are two executions so that's 5 seconds) and then it goes to 12:00 right away without showing it to the Text View. Is there something I am doing wrong? Also if I applied handler function here, I'm afraid I don't have much knowledge to use that.
Edit: This is from my MainActivity method. Example, change from 1 to 2 then wait for 250 miliseconds, change from 2 to 3 then wait for 250 miliseconds
synchronized (this){
try {
while(minuteHand != 0 || hourHand != 12){
if (hourHand != 12){
hourHand++;
hourText.setText(Integer.toString(hourHand));
wait(250);
}
if (minuteHand != 0) {
minuteHand += 5;
minuteHand %= 60;
minuteText.setText(Integer.toString(minuteHand));
wait(250);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}

Below is the proper way to update UI elements from an asynchronous thread:
public class SampleActivity extends Activity {
private TextView hourText;
private TextView minuteText;
private void updateHourText(final String text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
hourText.setText(text);
}
});
}
private void updateMinuteText(final String text) {
runOnUiThread(new Runnable() {
#Override
public void run() {
minuteText.setText(text);
}
});
}
private class ClockTask extends AsyncTask<Void, Void, Void>
{
private int hourHand;
private int minuteHand;
public ClockTask(int hourHand, int minuteHand) {
this.hourHand = hourHand;
this.minuteHand = minuteHand;
}
#Override
protected Void doInBackground(Void... voids) {
try {
while(minuteHand != 0 || hourHand != 12){
if (hourHand != 12){
hourHand++;
updateHourText(Integer.toString(hourHand));
Thread.sleep(250);
}
if (minuteHand != 0) {
minuteHand += 5;
minuteHand %= 60;
updateMinuteText(Integer.toString(minuteHand));
Thread.sleep(250);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
return null;
}
}
}
And then call this from your button's onClickListener():
new ClockTask(hourHand, minuteHand).execute();
As you can see, in order to update TextView's text, a helper method was needed, which would always execute TextView.setText() inside your main thread. That way, your business logic can execute within its own thread (without causing main thread to wait, which would lead to unresponsive UI), while updating your TextViews asynchronously.
Also, you should never try to update UI elements outside your main thread's context as it will lead to an exception being thrown.

Related

Thread freezes UI

I have this button that when clicked calls a thead to update user ui:
averageButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new Testing().execute();
}
});
The method gets executed but it freezes the UI for 10 seconds. I want to update the UI everytime I call the averageMiles.append(mile) method.
class Testing extends AsyncTask<Void, Void, Void> {
#Override
protected void onPostExecute(Void unused) {
int x = 0;
while (true) {
if (x == 10) {
break;
}
ArrayList<Double> milesList = new ArrayList<>();
if (x == 0) {
averageMiles.setText("mph: ");
}
String mile = milesValue.getText().toString();
if (!isNum(mile)) {
continue;
}
averageMiles.append(mile);
milesList.add(Double.valueOf(mile.trim()));
x++;
if (x == 10) {
averageMiles.append("\nAverage: " + getAverage(milesList));
return ;
} else {
averageMiles.append(", ");
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Use ThreadPool executor from official oracle and android developer documentations
Oracle Docs - java.util.concurrent.ThreadPoolExecutor
Android Docs - java.util.concurrent.ThreadPoolExecutor
as you have specified you are using java the above two documentation is recommended by google as show below for AsyncTask
This class was deprecated in API level 30.
Use the standard java.util.concurrent or Kotlin concurrency utilities instead.
The ultimate objective is the android is saying that, if you want to update UI, simply use runOnUiThread with a new runnable you update the UI, which means for each UI update you may be creating fresh short term thread which only updates the UI and thread finishes and garbage collected
Sample Code
public class MainActivity extends AppCompatActivity {
int count = 0;
Executor ex;
MyThread th;
class MyThread extends Thread implements Runnable {
private boolean running=false;
public void setRunning(boolean running) {
this.running = running;
}
#Override
public void run() {
while(running) {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
count++;
TextView tv = findViewById(R.id.textView);
tv.setText(String.valueOf(count));
}
});
}
}
}
public void onStartClick(View view) {
th = new MyThread();
ex = Executors.newSingleThreadExecutor();
th.setRunning(true);
ex.execute(th);
}
public void onStopClick(View view) {
if(th!=null) {
th.setRunning(false);
}
}
}
all the member variables of the class should be only accessed inside runOnUiThread, for example count++ count is a variable of the MainActivity if you want any value specific to the thread you put only inside the MyThread class
Never try to access any of the MainActivity variable inside the run() method
You can also write MyThread as separate class, and set values similar to th.setRunning before starting the thread.
If you want a callback after the thread is completed use an interface which will give you a callback method in your MainActivity
So it is simply core java
I have created an example with interface
Concurrent Executor Interface Example

Android Java: Update a TextView every x seconds without user input

I'm making an app in Android Java, using Android Studio.
Every 0.1 seconds I want to update the text within a certain TextView.
I already managed to use a Handler to execute a method every 0.1 seconds (100 ms), but it doesn't automatically update the TextView.
It only updates the TextView to what I want when the user interacts with the app. It only updates it when, for example, the user slides the SeekBar or presses a button. It doesn't update when the user clicks on the screen, and not automatically without input either.
How can I make it such that it will update the value automatically, without user input?
Thanks in advance.
P.S: I'm new to Android and Java, and I'm using threads to get the value, in xml format, from a website.
Should I post any code, and if so, what exactly?
you can try updating the value of text view on the UI thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
//update TextView here
}
});
Thread t = new Thread() {
#Override
public void run() {
try {
while (!isInterrupted()) {
Thread.sleep(100);
runOnUiThread(new Runnable() {
#Override
public void run() {
// update TextView here!
}
});
}
} catch (InterruptedException e) {
}
}
};
t.start();
You can update your textview using thread also, like this.
int prStatus = 0;
new Thread(new Runnable() {
public void run() {
while (prStatus < 100) {
prStatus += 1;
handler.post(new Runnable() {
public void run() {
tv.setText(prStatus + "/");
}
});
try {
Thread.sleep(150);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(prStatus == 100)
prStatus = 0;
}
}
}).start();

Codename One - Show Next Form Only after Animation on SplashScreen is Complete

I have a splash screen implementation on Codename One with an animated text sequence. I do not want to use the nextForm property on my Splash Form since I want the sequence complete before I navigate. Hence, I have used showForm. It works fine on the emulator but when I test on a real device, the next form I have loaded programmatically takes time to load, the transition is slow and sometimes it crashes. I cant seem to figure out why...
I have included the sample code below:
#Override
protected void beforeSplash(Form f) {
// If the resource file changes the names of components this call will break notifying you that you should fix the code
super.beforeSplash(f);
final String text = "Sample text to be animated here for testing purpose!";
final SpanLabel l = findSloganLabel(f);
Animation anim = new Animation() {
private long lastTime = System.currentTimeMillis();
public boolean animate() {
long t = System.currentTimeMillis();
int i = l.getText().length();
if (t - lastTime >= 450) {
if (i == text.length()) {
showForm("Register", null);
return false;
} else {
System.out.println("Animating Label...");
if (i == text.length() - 1) {
l.setText(text);
l.revalidate();
} else {
l.setText(text.substring(0, i) + "_");
l.revalidate();
}
}
lastTime = t;
}
return false;
}
public void paint(Graphics g) {
}
};
f.registerAnimated(anim);
}
You can do something like this:
#Override
protected void postSplash(Form f) {
UITimer timer = new UITimer(new Runnable() {
public void run() {
showForm("MainForm", null);
}
});
timer.schedule(XX-MiliSec, false, f);
}
So in your splash form's postForm method add timer..
And schedule it after XX Milli-seconds (whatever your animation duration is)
It will execute showForm() method after that mentioned Milli-seconds
You have two simple options, the first which I think it better is to not use the "next form" property and then just invoke showForm("mainFormName", null) when the animation completes.
The second is really how the next form was designed to work, its designed for you to do a background process on a background thread that might take time, to simulate this we sleep for a few seconds but you should override that method to do whatever you want. Just override this in your state machine and do whatever you want:
protected boolean processBackground(Form f) {
try {
Thread.sleep(3000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
return true;
}
You're looking for an AnimationListener
anim.setAnimationListener(new Animation.AnimationListener() {
#Override public void onAnimationStart(Animation animation) {
}
#Override public void onAnimationEnd(Animation animation) {
showForm();
}
#Override public void onAnimationRepeat(Animation animation) {
}
});)

How can I show a value on the screen without blocking the UI and make it fade out with style in android activity?

I'm making a word game for android, and basically whenever a user enters something right I'm updating the score in the application, and I want to show the score on the screen to make it show in big then fade out slowly and get smaller, how can I do that? and is it possible to implement it in an AsyncTask class?
This is the method I'm using to check if the word entered is right.
public class checkWord extends AsyncTask<String, String, Void> {
private String c;
#Override
protected Void doInBackground(String... arg0) {
int size = correctWords.size();
String word = arg0[0];
for (int i = 0; i < size; i++) {
if (word.equalsIgnoreCase(correctWords.get(i))) {
publishProgress("bad");
}
}
try {
c = bufferedReader.readLine();
while (c != null && !c.equalsIgnoreCase(word)) {
c = bufferedReader.readLine();
}
if (c != null) {
correctWords.add(0, word);
score += word.length();
publishProgress("good");
} else {
incorrectWords.add(0, word);
publishProgress("bad");
}
} catch (IOException e) {
e.printStackTrace();
}
closeWordFile();
openWordFile();
return null;
}
So is there anyway I could pass a param to the publishProgress so that in onProgressUpdate I draw the score they got, for example +3 then make it fade out?
This is my onProgressUpdate where I add seconds to the timer and play a sound if it's a valid word or not
#Override
protected void onProgressUpdate(String... values) {
super.onProgressUpdate(values);
if (values[0].matches("bad"))
failureSound.start();
if (values[0].matches("good")) {
successSound.start();
if (countDownTimer != null) {
countDownTimer.cancel();
startTimer(countDownTime + c.length() / 2);
}
}
}
Because of Single threaded model in Android, only main thread can update UI, You can try the same in
runOnUiThread(new Runnable()
{
public void run()
{}
}
method.
Instead use a toast message. It will not affect your UI.

Run loop every second java

int delay = 1000; // delay for 1 sec.
int period = 10000; // repeat every 10 sec.
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask()
{
public void run()
{
displayData(); // display the data
}
}, delay, period);
And other:
while(needToDisplayData)
{
displayData(); // display the data
Thread.sleep(10000); // sleep for 10 seconds
}
Both of them doesn't work (application is force closed). What other options I can try?
You code is failed because you perform sleep in background thread but display data must be performed in UI thread.
You have to run displayData from runOnUiThread(Runnable) or define handler and send message to it.
for example:
(new Thread(new Runnable()
{
#Override
public void run()
{
while (!Thread.interrupted())
try
{
Thread.sleep(1000);
runOnUiThread(new Runnable() // start actions in UI thread
{
#Override
public void run()
{
displayData(); // this action have to be in UI thread
}
});
}
catch (InterruptedException e)
{
// ooops
}
}
})).start(); // the while thread will start in BG thread
Use onPostDelayed() accessed from any of your View or a Handler. You save memory by not creating a Timer or new Thread.
private final Handler mHandler = new Handler();
private final Runnable mUpdateUI = new Runnable() {
public void run() {
displayData();
mHandler.postDelayed(mUpdateUI, 1000); // 1 second
}
}
};
mHandler.post(mUpdateUI);
Try this :
#Override
public void run() {
TextView tv1 = (TextView) findViewById(R.id.tv);
while(true){
showTime(tv1);
try {
Thread.sleep(1000);
}catch (Exception e) {
tv1.setText(e.toString());
}
}
}
U can also try this
There is an another way also that you can use to update the UI on specific time interval. Above two options are correct but depends on the situation you can use alternate ways to update the UI on specific time interval.
First declare one global varialbe for Handler to update the UI control from Thread, like below
Handler mHandler = new Handler();
Now create one Thread and use while loop to periodically perform the task using the sleep method of the thread.
new Thread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
while (true) {
try {
Thread.sleep(10000);
mHandler.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
// Write your code here to update the UI.
}
});
} catch (Exception e) {
// TODO: handle exception
}
}
}
}).start();
There several mistakes you have done:
You should never invoke Thread.sleep() on the main thread (and you should never block it for a long time as well). Once main thread is blocked for more then 5 seconds, an ANR (application not responding) happens and it is force closed.
You should avoid using Timer in android. Try Handler instead. Good thing about handler is that it is created on the main thread -> can access Views (unlike Timer, which is executed on its own thread, which cannot access Views).
class MyActivity extends Activity {
private static final int DISPLAY_DATA = 1;
// this handler will receive a delayed message
private Handler mHandler = new Handler() {
#Override
void handleMessage(Message msg) {
if (msg.what == DISPLAY_DATA) displayData();
}
};
#Override
void onCreate(Bundle b) {
//this will post a message to the mHandler, which mHandler will get
//after 5 seconds
mHandler.postEmptyMessageDelayed(DISPLAY_DATA, 5000);
}
}
I came across this thread when i tried to get around the problem that you can't hide seconds in DigitalClock widget for Android. DigitalClock is deprecated now and the recommended widget to use now is TextClock. That don't work on old APIs tho... Therefore i had to write my own 24 hour clock. I don't know if this is a good implementation but it seems to work (and it is updated every second):
import java.util.Calendar;
import android.os.Handler;
import android.view.View;
import android.widget.TextView;
/**
* A 24 hour digital clock represented by a TextView
* that can be updated each second. Reads the current
* wall clock time.
*/
public class DigitalClock24h {
private TextView mClockTextView; // The textview representing the 24h clock
private boolean mShouldRun = false; // If the Runnable should keep on running
private final Handler mHandler = new Handler();
// This runnable will schedule itself to run at 1 second intervals
// if mShouldRun is set true.
private final Runnable mUpdateClock = new Runnable() {
public void run() {
if(mShouldRun) {
updateClockDisplay(); // Call the method to actually update the clock
mHandler.postDelayed(mUpdateClock, 1000); // 1 second
}
}
};
/**
* Creates a 24h Digital Clock given a TextView.
* #param clockTextView
*/
public DigitalClock24h(View clockTextView) {
mClockTextView = (TextView) clockTextView;
}
/**
* Start updating the clock every second.
* Don't forget to call stopUpdater() when you
* don't need to update the clock anymore.
*/
public void startUpdater() {
mShouldRun = true;
mHandler.post(mUpdateClock);
}
/**
* Stop updating the clock.
*/
public void stopUpdater() {
mShouldRun = false;
}
/**
* Update the textview associated with this
* digital clock.
*/
private void updateClockDisplay() {
Calendar c = Calendar.getInstance();
int hour = c.get(Calendar.HOUR_OF_DAY); // 24 hour
int min = c.get(Calendar.MINUTE);
String sHour;
String sMin;
if(hour < 10) {
sHour = "0" + hour;
} else sHour = "" + hour;
if(min < 10) {
sMin = "0" + min;
} else sMin = "" + min;
mClockTextView.setText(sHour + ":" + sMin);
}
}
Thankyou biegleux for pointing me in the, i suppose, correct direction!

Categories

Resources