No errors, compiles, no run time error.
Hey, I have a simple question about Android sum. I'm doing a simple summation, the code compiles, it does technically do what it suppose to do, sum the number until its greater than 120. However, I wanted the output to show each sum as it goes through the loop. Unfortunately, it just jumps immediately to the last sum on the textview. I tried using a sleep function, wait function, but what ended up happening was it would wait the amount of time for all the loops until the sum was greater than 120, then output the final sum. In this case 4950. Any suggestions for showing each sum on the text view?
I also tried using this line of code, which worked in showing each sum individually, however, it started the timer immediately. Which it should not do.
Toast.makeText(MainActivity.this, "SUM:"+sum1, Toast.LENGTH_SHORT).show();
Basic goal of my simple application
1) Show each sum
2) When the sum is greater than 120 start timer
Question: How do I get it to show each sum individually on the text-view instead of jumping to the final summation?
public void onClick(View v)
for(i=0;i<100;i++)
{
sum1 = sum1 + i;
sum.setText("Sum:"+sum1);
if(sum1 > 120)
{
timer.start();
}
}
}
Thank you for your time.
The reason it "Jumps" to the last one is because the act of clicking runs the for loop while blocking the UI thread. You are in effect not able to see the text changing, but its changing. You can accomplish what you need by using a Timer or TimerTask, which basically creates a separate thread for you. It also handles the delays which you need. Simply do the math in the Timers execution method.
//make sure these are global
int i = 0;
int sum1 = 2;//not really sure where your sum starts so you choose
TimerTask leTask = new TimerTask() {
public void run() {
sum1 = sum1+i;
i++;
/*I don't actually remember if you must go back to the main thread
* when in the tasks run method. Incase you get an error because
* of that then just do that quickly. I have included a link for
* you on how to do that if necessary.*/
sum.setText("Sum:"+sum1);
if(sum1 > 120){
/*Start your actually timer here
* and stop execution of leTask by calling the cancel method*/
}
}
int delay = 0;//you don't really want a delay since you want it immediately after click
int everySecond = 1000;
timer.scheduleAtFixedRate(leTask, 0, everySecond);
Keep in mind the way I set ti up is just an example. You should make sure that you have access to leTask (or whatever you call it) when its cancelled. i and sum1 should also be global. delay and everySecond don't have to be in variables. I did that to kind of explain what they do so it makes a bit more sense. I like this method better because you aren't worried about UI thread stuff with the exception of updating the TextView.
Edit: You can also access the UI from the timer using the post method from TextView. It would look something like this:
sum.post(new Runnable() {
public void run() {
sum.setText("Sum:"+sum1);
});
}
EDIT2:
I have to include this edit to be thorough for future user who come across this as I just found out that Timer and TimerTask is no longer becoming the preferred method for scheduling commands, etc. It should be ScheduledThreadPoolExecutor now. Although this has been the case for some time it hasn't really been reported much in questions on here that i've come across. In either case, android has it in the docs here. It's literally like the second sentence.
This is my proposed solution :D
activity_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" >
<TextView
android:id="#+id/resultView"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button
android:id="#+id/startButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start counting" />
</LinearLayout>
MainActivity.java
public class MainActivity extends Activity implements OnClickListener {
private static final long SUM_DELAY = 100;
private TextView mResultView;
private Button mStartButton;
private Handler mHandler = new Handler();
private int mSum = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mResultView = (TextView) findViewById(R.id.resultView);
mStartButton = (Button) findViewById(R.id.startButton);
mStartButton.setOnClickListener(this);
}
private Runnable sumTask = new Runnable() {
#Override
public void run() {
mSum += 1;
if (mSum > 120) {
mSum = 0;
mStartButton.setEnabled(true);
return;
}
mResultView.setText(String.valueOf(mSum));
mHandler.postDelayed(this, SUM_DELAY);
}
};
#Override
public void onClick(View view) {
if (view.getId() == mStartButton.getId()) {
mStartButton.setEnabled(false);
sumTask.run();
}
}
}
The thing is that onClick() runs on the UI thread. That means that the whole method has to be finished before the UI can update again, hence the sudden jump to the last number. That is also the reason why nothing happens when you use Thread.Sleep(). sleep() applies in that case to the UI thread, so the whole app will freeze.
If you want the TextView to count up, you have to use an AsyncTask. Add the loop and a Thread.sleep() to doInBackground(), publish the progress and set the text in onProgressUpdate(). The link actually contains a nice example that should work for you.
Related
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.
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.
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.
I am using freeTTS to speak out some text, in the background i want a animated gif to keep playing
When i try this: as soon as the voice starts speaking, the image in background gets hanged even if i keep it in some other JFrame... and after the speech is completed it starts moving. I want it to run properly without pauses.
I am placing a animated gif in a label by importing it to my application and changing the icon to that image in label' properties.
Edit
Here is my code:
private void RandomjBActionPerformed(java.awt.event.ActionEvent evt) {
Voice voice;
voice = voiceManager.getVoice(VOICENAME);
voice.allocate();
voice.speak("Daksh");
}
I am actually using a lot of setVisible, setText, declaration of integers, calculating on them but i have removed them to simplify the code for you to understand. Still it gives the same problem if executed.
The button 'RandomjB' is clicked from another button by the following code:
final Timer timer = new Timer(zad, new ActionListener() {
int tick = 0;
#Override
public void actionPerformed(ActionEvent e) {
System.out.println("Success" + ++tick);
RandomjB.doClick();
final int col = Integer.parseInt(t3.getText());;
if (tick >= col) {
((Timer) e.getSource()).stop();
for(int g=0; g<col; g++){
jButton2.setVisible(true); // Check Button -> Visible
}
}
}
});
timer.setInitialDelay(0);
System.out.format("About to schedule task.%n");
timer.start();
System.out.format("Task scheduled.%n");
It is hard to tell without the code, I however assume that you loop the speech synthesis within the one and only Swing-Thread and therefore block all kind of window updates as long as the speech loop is in progress.
As stated by Shaun Wild: you need to use a second Thread for the speech loop.
You may want to do some research on Threads and Concurrency
These allow two things to operate simultaneously, this is just my assumption.
Assuming that you instantiate some kind of class for the FreeTTS you may want to do something like this
FreeTTSClass tts;
new Thread(new Runnable(){
public void run(){
tts = new FreeTTSClass();
}
}).start();
Sorry I am a noob I've read countless tutorials about making a simple timer and was wondering why it doesn't work until I noticed it is the while-loop causing the issue o.O I have removed it and then it works but only 1 time I need to use the loop though so the movement finishes :C
Heres the code:
old_x is the coordinate from an ImageView and new_x from the onTouch Event, maybe the problem because I am casting them as an int? I don't know what I need to do so it works please help O:
while(old_x != new_x)
{
timedMoveIV(100);
old_x = (int)img.getX();
}
It calls this method which works if I do it without the loop.
public void timedMoveIV(int time_ms)
{
//sleep for time_ms milliseconds
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run() {
if(new_x > img.getX())
{
img.setX(img.getX() + 1);
}
else
{
img.setX(img.getX() - 1);
}
}
}, time_ms);
}
Your main problem is that your loop doesn't take a break, so it's constantly running the function, posting a gazillion runnables.
What you want to do is make the runnable call itself after another 100 ms. Take a look at this example:
if(old_x != new_x)
timedMoveIV(100);
Here you simply call the function once. After that, you let the posted runnable decide whether or not it needs to move again:
public void timedMoveIV(final int time_ms)
{
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
public void run()
{
if(new_x > img.getX())
img.setX(img.getX() + 1);
else
img.setX(img.getX() - 1);
// if not in position, call again
if((int)img.getX() != new_x)
timedMoveIV(time_ms);
}
}, time_ms);
}
It should stop once img.getX() == new_x. Notice the cast to int, though, because if you leave it out, you might get some oscillation as it gets within a pixel of the destination.
This assumes that new_x is an int. If it's a float as well, you should either cast both to int to compare, or compare them to a minimum threshold. For instance, if there's less than 0.5 difference, treat it as "done".