runOnUiThread doesn't work - java

This is one of my first apps, and I don't know what I have to do.
package com.example.stopuhr;
import android.os.Bundle;
import android.app.Activity;
import android.view.View;
import android.widget.TextView;
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public int hs, sek, min;
public boolean running = false;
public String mode = "gestoppt";
public void setLabelText(){
TextView textView1 = (TextView)findViewById(R.id.textView1);
String ht = "";
String st = "";
String mt = "";
if (hs<10){
ht = "0" + hs;
}else{
ht = String.valueOf(hs);
}
if (sek<10){
st = "0" + sek;
}else{
st = String.valueOf(sek);
}
if (min<10){
mt = "0" + min;
}else{
mt = String.valueOf(min);
}
textView1.setText(mt + " : " + st + " : " + ht);
}
public void onClickStart (View view){
Thread timer = new Thread(){
Here's are the first errors
Multiple markers at this line
- Syntax error, insert "}" to complete ClassBody
- Syntax error, insert ";" to complete ConstructorDeclaration
- Syntax error, insert ";" to complete BlockStatements
- Return type for the method is missing
- Syntax error, insert ")" to complete ConstructorDeclaration
runOnUiThread(new Runnable() {
public void run(){
if (mode.equals("gestoppt")){
running = true;
mode = "läuft";
while (running){
try{Thread.sleep(9);}
catch(Exception e){}
if(hs<=99){
hs++;
}else{
hs = 0;
if(sek<=59){
sek++;
}else{
sek = 0;
}
if(min<=99){
min++;
}else{
min = 0;
}
}
}
setLabelText();
}
}
Here is the second mistake:
Syntax error on token "}", MethodHeaderName expected
I don't know what I have to do with this error.
});
};
timer.start();
}
public void onClickStop (View view){
if (mode.equals("läuft"));
running = false;
mode = "gestoppt";
}
public void onClickReset (View view){
if(mode.equals("gestoppt")){
hs = 0;
sek = 0;
min = 0;
setLabelText();
}
}
}
Thank you for your help.

In your code you have:
public void onClickStart (View view){
Thread timer = new Thread(){
runOnUiThread(new Runnable() {
public void run() {
...
}
});
};
}
The problem here is that you have the call runOnUiThread just inside a class - not in a method. In general you seem to be confused with threads, runnable and runOnUi. There's no point starting a new thread if you then want to invoke its run method on UI thread. The only thing you need to do on the UI thread is update the label text. Without going through your logic, one way of fixing the syntax errors would be:
public void onClickStart (View view) {
Thread timer = new Thread(){
public void run() {
...
runOnUiThread(new Runnable() {
public void run() {
setLabelText();
}
}
};
timer.start();
}
Finally, note that this is not the best way of performing this kind of logic. An AsyncTask with onProgressUpdate seems to me a much better solution.

I think it is better to put your functionality into a method in the MainActivity class:
private void doMyOperation() {
runOnUiThread(.....);
}
and call that method in your thread.

It looks like there is a Thread.sleep in your code that is blocking the UI. This might stop the UI from updating.

Related

pause program between adding and removing a TextView

I'm working on a tank-game and I have a TextView which represents the shot. Now I want to display the TextView at the specific point and remove it after a second that it looks like the shot goes further step by step. But when I add a countdown or a Thread.sleep the program stops for a second but the TextView doesn't disappear. i want to move the TextView over the screen and after every iteration of my for loop i want to wait a second and then rearrange it again?
Here is the code :
public void shot(float power, float winkel, Button button) {
if(winkel>90) {
winkel = winkel - 10;
}else if(winkel<90){
winkel = winkel +10;
}
for (double i = 0; i<100;i = i+ 1) {
final TextView textView = new TextView(context);
textView.setText(".");
double x = tanks.get(currentTank).getxPos()+(i*power*Math.cos(winkel *(Math.PI/180)));
double y = tanks.get(currentTank).getyPos()+(-1*(i*power*Math.sin(winkel *(Math.PI/180))));
double gravity = (-1*((9.81/2)*Math.pow(i,2)));
y = (y-gravity);
textView.setX((float) x);
textView.setY((float) y);
layout.addView(textView);
for (int j = 0;j<tanks.size();j++){
if(textView.getX()>tanks.get(j).getxPos()&&textView.getX()<tanks.get(j).getxPos()+100){
if(textView.getY()>tanks.get(j).getyPos()&&textView.getY()<tanks.get(j).getyPos()+100){
float k = tanks.get(j).getxPos()-textView.getX();
if(k<0){
k = k*-1;
}
makeDamage(k,tanks.get(j));
}
}
}
new CountDownTimer(2000,1000){
#Override
public void onTick(long millisUntilFinished) {
}
#Override
public void onFinish() {
layout.removeView(textView);
}
}.start();
}
newTurn();
}
I want to pause the program after adding the TextView for one second and the remove it. The program stops but the TextView doesn't disappear till the for-loop finished. Then all TextViews disappear.
Problem solved:
i've added all positions in a array and then this
public void drawShot(final Button firework, final ArrayList<TextView> toDraw){
final int[] i = {0};
final Handler mHandler = new Handler();
firework.setOnClickListener(new View.OnClickListener() {
#RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
#Override
public void onClick(View v) {
firework(firework,toDraw.get(i[0]).getX(),toDraw.get(i[0]).getY());
}
});
Runnable runnable = new Runnable() {
#Override
public void run() {
layout.addView(toDraw.get(i[0]));
if(!check(toDraw.get(i[0]))) {
mHandler.postDelayed(this, (long) 1);
}
i[0]++;
}
};
// start it with:
mHandler.post(runnable);
}
probably need to run the remove command on main thread
Handler mainHandler = new Handler(context.getMainLooper());
Runnable myRunnable = new Runnable() {
#Override
public void run() {
layout.removeView(textView);
}
};
mainHandler.post(myRunnable);

Display values in ArrayList one by one in textView

I am trying to display values inside ArrayList on single line textView one by one after some interval. How to achieve this without blocking the main thread?
I have written code which is able to do this with Thread.sleep but, after a few seconds of running, activity is getting crashed. I have used For Loop & Thread.sleep to iterate every ArrayList value after some interval.
When activity crashes, I am getting IndexOutOfBondException after a few seconds of running.
public void errorRepeater() {
Thread t = new Thread() {
#Override
public void run() {
// !isInterrupted()
while (!isInterrupted()) {
for (xz = 0; xz < errorList.size(); xz++) {
try {
Thread.sleep(2000); //1000ms = 1 sec
runOnUiThread(new Runnable() {
#Override
public void run() {
String sErrorList = errorList.get(xz);
String sErrorListOkBox = errorListOkBox.get(xz);
Log.i("MQTT sErrorList", sErrorList);
TextView tvC1HPLP = findViewById(R.id.errormsg);
tvC1HPLP.setText(sErrorList);
TextView tvok = findViewById(R.id.ok);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
}
});
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
t.start();
}
textView should display values inside ArrayList one by one without crashing activity.
Just for reference, you can try something like this.
// You can define those both textview globally.
TextView tvC1HPLP = findViewById(R.id.errormsg);
TextView tvok = findViewById(R.id.ok);
Handler mHandler = new Handler();
final Runnable runnable = new Runnable() {
int count = 0;
#Override
public void run() {
String sErrorList = errorList.get(count%errorList.size);
String sErrorListOkBox = errorListOkBox.get(count%errorListOkBox.size);
tvC1HPLP.setText(sErrorList);
tvok.setText(sErrorListOkBox);
rl.setBackgroundResource(R.drawable.errorred);
tvC1HPLP.setTextColor(Color.RED);
count++;
mHandler.postDelayed(this, 4000); // four second in ms
}
};
mHandler.postDelayed(runnable, 1000);

Why doesn't my delay happen?

currently developing an app where I need to take a number of wifi measurements, take an average of these measurements and store the averages. However I've found that I have to implement a delay between measurements otherwise there's not enough time to see any variation between measurements.
In the Handler.postDelayed() method I've tried to implement a 2000ms delay, however when I view the timestamp of the logs generated by TAKEWIFI, there appears to be no delay at all.
Any help would be greatly appreciated :)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_takewifi);
final String[] strArr = new String[60];
for (int i=0;i<60;i++)
{
strArr[i] = "EMPTY";
}
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
final int state = wifi.getWifiState();
if(state == WifiManager.WIFI_STATE_ENABLED) {
RawData rD = new RawData();
Toast.makeText(TakeWifi.this,
"Taking RSS measurement, hold still!",
Toast.LENGTH_SHORT).show();
for(int a=0;a<30;a++)
{
wifi.startScan();
final Handler handler = new Handler();
handler.post(new Runnable() {
#Override
public void run() {
handler.postDelayed(this, 2000);
}
});
List<ScanResult> results = wifi.getScanResults();
String index = (String) results.toString();
int forCount = 0;
int ifCount = 0;
for (String retval: index.split(",")){
if (((forCount%5==1)||(forCount%5==3))&&(ifCount<60)){
strArr[ifCount] = retval;
strArr[ifCount] = strArr[ifCount].replace(" BSSID:", "BSSID:");
strArr[ifCount] = strArr[ifCount].replace(" level:", "level:");
ifCount++;
}
forCount++;
}
for(int check=0;check<60;check++)
{
Log.d("TAKEWIFI","strArr[" + check + "]: " + strArr[check]);
}
rD.setStrArr(strArr,rD);
}
final String[] temp = rD.getStrArr(rD);
for(int b=0;b<20;b++)
{
strArr[b]=temp[b];
}
for(int i=0;i<20;i++)
{Log.d("STRARR",strArr[i]);}
List<String> stringList = Arrays.asList(temp);
for (int i = 0; i < 20; i++) {
Log.d("STRLIST",stringList.get(i));
}
ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, stringList);
ListView listview = (ListView) findViewById(R.id.listview);
if (listview==null)
{
Log.d("LISTVIEW","NULL");
}listview.setAdapter(adapter);
Toast.makeText(TakeWifi.this,"RSS measurement complete",Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(TakeWifi.this,"Wifi Not Enabled",Toast.LENGTH_SHORT).show();
}
final Button commitBut=(Button)findViewById(R.id.button4);
commitBut.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
if(state == WifiManager.WIFI_STATE_ENABLED){
commit(strArr);
}
else
{
Toast.makeText(TakeWifi.this,"Wifi Not Enabled",Toast.LENGTH_SHORT).show();
}
}
});
}
Replace your handle with this and put everything you want delayed into it.
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// Everything you want to be delayed needs to go inside this runnable
}
}, 2000);
You are waiting in another thread (hence the run() method in your handler) :) Try removing that whole handler magic and call Thread.sleep directly.

view.setText happening after loop?

i'm new to android programming. I have the following code happening on a button click
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.morse_btn);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
loopCode();
}
});
}
which calls this:
public void loopCode()
{
String code = "Hello There";
TextView view = (TextView) findViewById(R.id.code_txt);
String s = "";
for(int i = 0; i < code.length(); i++)
{
s+=code.charAt(i);
view.setText(s);
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
but when i run it on my phone, the text does not get appended until after the for loop has gone through, i.e i press the button, and after a few seconds, the whole string "Hello There" appears.
How can I make it write the text one character at a time, like a typewriter style.
Thanks
You need to use view.append("") which will append new text to the existing one.
Try this code:
int i = 0; //declare this globally
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(i != 10) {
text.append(" " + i);
i++;
handler.postDelayed(this, 1000);
}
}
}, 1000);
}
This code will append a new number to the TextView every one second until it has reached the count 10. You can apply the same logic.
I had provided this solution to a question here -
[EDIT]
Try this:
String code = "Hello There"; //declare variable globally
int i = 0; //declare globally
TextView view; //declare globally
public void loopCode()
{
view = (TextView) findViewById(R.id.code_txt);
//String s = "";
final Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
if(i != code.length()) {
view.append(" " + code.charAt(i));
i++;
handler.postDelayed(this, 1000);
}
}
}, 1000);
}
}
Don't forget to declare int i = 0 and String code = "Hello There" globally.
Exist 2 different method setText in TextView.
public final void setText (int resid)
public final void setText (CharSequence text)
when you put variable int in setText, the android try find String in classe R variable in same code.
To resolve this you then cast int to string using String.valueOF(...)
see more in;
http://developer.android.com/reference/android/widget/TextView.html#setText(java.lang.CharSequence)
http://docs.oracle.com/javase/6/docs/api/java/lang/String.html#valueOf(int)
try
public void loopCode()
{
String code = "Hello There";
TextView view = (TextView) findViewById(R.id.code_txt);
String s = "";
for(int i = 0; i < code.length(); i++)
{
view.setText(String.valueOf(i));
try {
TimeUnit.SECONDS.sleep(1);
} catch(InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}

Avoiding threads restarting when changing activity

Right now, when I change the activity, my thread seams to go to sleep or something. And when I come back to the main activity, there are two threads running, doing the same things. I'm not sure if this is the case, but it seems like it's something equal.
...
public class MainActivity extends Activity {
public static double cowCount = 195;
public static double income = 0.100;
static boolean twiceCow = false, Threadrunning = false;
...
public void inc() {
new Thread(new income()).start();
}
class income implements Runnable {
#Override
public void run() {
for (int i = 0; i < 20;) {
final int value = i;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
handler.post(new Runnable() {
#Override
public void run() {
cowCount = cowCount + income;
refresh();
}
});
}
}
}
This is how my thread looks like.
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
handler = new Handler();
checkThread();
}
private void checkThread() {
if (Threadrunning == false)
inc();
Threadrunning = true;
}
public void inc() {
new Thread(new income()).start();
}
...
public void refresh () {
TextView myTextView = (TextView)findViewById(R.id.myText);
myTextView.setText("You Have " + String.valueOf((nf.format(cowCount)) + " Cows!"));
}
I don't really understand what I've done wrong.
Please review this post: http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
Consider your activity re-start as the same thing as a config change.
This pattern, i.e. using a retained Fragment as a container for your thread, and proxying UI updates via callbacks to your activity, is a pattern that will work much better for you.
In your case you'd need only a single TaskCallback for your UI refresh(), e.g. onRefreshCowCount(int cows);

Categories