I want a thread loop that changes String each time. (e.g. d -> dd -> ddd -> dddd...) I expected it to update the view as well as the Thread is excuted , but the screen stops at the first run() excution (which is "dd"). What is wrong? Thanks!
package com.example.name.app;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
thread t1 = new thread();
t1.start();
}
});
}
private class thread extends Thread {
TextView textView = (TextView) findViewById(R.id.tv);
#Override
public synchronized void run() {
String text = "d";
while (true) {
try {
text += "d";
textView.setText(text);
sleep(5000);
} catch (Exception e) {
return;
}
}
}
}
}
MainActivity.java
public class MainActivity extends AppCompatActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.tv);
final Button button = (Button) findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
thread t1 = new thread();
t1.start();
}
});
}
private class thread extends Thread {
String text = "d";
#Override
public synchronized void run() {
while (true) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(text);
}
});
sleep(5000);
text += "d";
} catch (Exception e) {
return;
}
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="digitdemo.com.myapplication.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical">
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Count"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="#+id/btn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Press"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</LinearLayout>
</android.support.constraint.ConstraintLayout>
Output:
Hope this helps you.
All the ui elements are handled on main thread. Hence to update any ui element you must do it from the main thread (UI Thread). you can use runOnUiThread to switch to UI thread:
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.tv);
final Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
thread t1 = new thread();
t1.start();
}
});
}
private class thread extends Thread {
#Override
public synchronized void run() {
String text = "d";
while (true) {
try {
text += "d";
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(text);
}
});
sleep(5000);
} catch (Exception e) {
return;
}
}
}
}
Try this..it will give same output as you want.
public class TestActivity extends AppCompatActivity {
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
textView = (TextView) findViewById(R.id.tv);
final Button button = findViewById(R.id.btn);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
thread t1 = new thread();
t1.start();
}
});
}
private class thread extends Thread {
String text = "d";
#Override
public synchronized void run() {
while (true) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
textView.setText(text);
}
});
sleep(5000);
text += "d";
} catch (Exception e) {
return;
}
}
}
}
Instead of extending the thread class for simple task of incrementing and updating UI use handler.Handler runs in the same main thread with different execution environment.
create a simple handler and update main thread if you want.
TextView textView = (TextView) findViewById(R.id.tv);
String text = "d";
Runnable runnable=null;
Handler newHandler=null;
private void runTask() {
newHandler = new Handler();
runnable = new Runnable() {
#Override
public void run() {
try {
//update UI
text += "d";
textView.setText(text);
newHandler.post(runnable);
} catch (Exception e) {
e.printStackTrace();
}
}
};
newHandler.post(runnable);
}
}
and to stop the handler use
newHandler.removeCallbacks(runnable);
Related
I have a button and two images, i want the default image for the button to be btn1.jpg and when the button is clicked, the image should immediately change to btn2.jpg and after 3 seconds, it should again revert back to btn1.jpg. please tell me how do i achieve this?
package com.example.btn;
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
public class MainActivity extends Activity {
private View ButtonName;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void yolo(View v) {
switch (v.getId()) {
case R.id.buttonName:
ButtonName.setBackgroundResource(R.drawable.btn2);
//Disable click on Button
ButtonName.setEnabled(false);
try {
Thread.sleep(3000);
}
catch (Exception e) {
e.printStackTrace();
}
ButtonName.setBackground(getResources().getDrawable(R.drawable.btn1));
break;
case default:
ButtonName.setBackgroundResource(R.drawable.btn1);
}
}
}
You must change the button background image in the OnClick method to btn2.jpg. After that, you must start a timer to count down 3 seconds and, after that, change again the button image to btn1.jpg
private final int interval = 3000;
private Handler handler = new Handler();
private Runnable runnable
btn.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
btn.setBackground(getResources().getDrawable(R.drawable.btn2))
//Start runnable after 3 seconds
handler.postDelayed(runnable, interval);
}
});
runnable = new Runnable(){
public void run() {
btn.setBackground(getResources().getDrawable(R.drawable.btn1))
}
};
finally figured it out myself!
Set background for button in xml
use this code:
package com.example.btn;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
public class MainActivity extends Activity {
Handler mHandler; // global instance
Runnable your_runnable; // global instance
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void yolo(final View view) {
if (view == view) {
view.setBackgroundResource(R.drawable.btn1);
mHandler = new Handler();
your_runnable = new Runnable() {
#Override
public void run() {
view.setBackgroundResource(R.drawable.btn2);
}
};
mHandler.postDelayed(your_runnable, 3000L);// 3sec timer
}
}
}
This may work for you!!
public class MainActivity extends Activity {
Button button;
private Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button=(Button)findViewById(R.id.yourbuttonid);
button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
button.setBackgroundResource(getresources().getDrawable(R.drawable.btn1));
handler=new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
button.setBackgroundResource(getresources().getDrawable(R.drawable.btn2));
}
}, 3000);
}
});
}
Ok so first, you have a mistake here :
ButtonName.setBackgroundResource(getresources().getDrawable(R.drawable.btn2));
And after, add a clickListener on your button :
private Thread t = new Thread(new Runnable {
#Override
public void run() {
ButtonName.setBackgroundResource(getresources().getDrawable(R.drawable.btn2));
//Disable click on Button
ButtonName.setEnabled(false);
try {
Thread.sleep(3000);
}
catch (Exception e) {
e.printstacktrace();
}
ButtonName.setBackgroundResource(getresources().getDrawable(R.drawable.btn1));
}
});
ButtonName.setOnClickListener (new OnClickListener (
#Override
public void onClick(View v) {
t.start();
}
));
I think it is what you want
in this app the Content of the TextView should change/update every second with a sleep thread.
The whole process starts when the button is clicked.
Firstable here is the normal code without the threads:
public class MainActivity extends ActionBarActivity {
Button btn;
TextView tw;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
tw = (TextView) findViewById(R.id.tw);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tw.setText("1"); //This is the TextView Content, it should update every second with a sleep thread
tw.setText("2");
tw.setText("3");
}
});
}
}
This is the code added ( not working ) sleep threads:
public class MainActivity extends ActionBarActivity {
Button btn;
TextView tw;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
tw = (TextView) findViewById(R.id.tw);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tw.setText("1");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tw.setText("2");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tw.setText("3");
}
});
}
}
Thank´s
The problem is that you are block the main UI(sleep) thread thus giving you unexpected result.
You need to use handler for this if you want to update this each second
sample:
public class MainActivity extends ActionBarActivity {
Button btn;
TextView tw;
int incre = 1;
Handler handler;
Runnable run;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btn = (Button) findViewById(R.id.btn);
tw = (TextView) findViewById(R.id.tw);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
tw.setText(incre++ + "");
handler = new Handler();
run = new Runnable() {
#Override
public void run() {
tw.setText(incre++ + ""); //set the textview text HERE every 1 second
if(incre != 3) //checks if it is not already 3 second
handler.postDelayed(run, 1000); //run the method again
else
incre -= 2;
}
};
handler.postDelayed(run, 1000); //will call the runnable every 1 second
}
});
}
}
My goal is when the user tap start button, letters "o" "n" "o" "m" and so forth will appear at the center of the screen. "o" will appear first then after a few seconds will be replaced by "n" then "o" and so forth.
note: for brevity, i just make the guessword = onomatopoeia, first. In reality, guessword will changes every time i tap the start bottom.
this is the code:
private String guessword = "onomatopoeia";
private TextView showchar;
private int n = guessword.length();
private char letArray[]= guessword.toCharArray();;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
addStartListener();
}
public void addStartListener(){
Button start = (Button) findViewById(R.id.start);
showchar = (TextView) findViewById (R.id.charView);
start.setOnClickListener(new OnClickListener(){
#Override
public void onClick(View arg0) {
// TODO Auto-generated method stub
Thread thread = new Thread()
{
#Override
public void run() {
try {
for(int i = 0 ; i < n ; i++) {
sleep(1000);
showchar.setText(letArray[i]);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
thread.start();
}
});
}
thanks for the help
I decided to implement runonuithread but still it crashes:
this is the updated version:
private String guessword = "onomatopoeia";
private TextView showchar;
private int n = guessword.length();
private char letArray[]= guessword.toCharArray();
private Handler handler;
private int i = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);
handler = new Handler();
showchar = (TextView) findViewById (R.id.charView);
}
public void startGame(View view){
new Thread() {
public void run() {
while(i++ < n) {
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
showchar.setText(letArray[i]);
}
});
Thread.sleep(300);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}.start();
}
use this code for setting the text in your textview
runOnUiThread(new Runnable() {
#Override
public void run() {
showchar.setText(letArray[i]);
}
});
You are updating ui from a thread which is not possible.
showchar.setText(letArray[i]);
UI must be updated ui thread.
All you are doing is repeatedly setting value to TextView you can use Handler with a delay for this purpose.
You could use runOnUiThread also but i don't see the need for a thread for what you are doing.
Use a Handler. You can find an example #
Android Thread for a timer
I have three layouts:
Layout1
-->onClick()-->show
Layout2
-->wait three seconds-->show
Layout3
The problem is that Layout2 is not shown. To set the layouts I use
setContentView(int);
The relevant code might be:
public class TrainingActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout1);
final Button inputButton = (Button)findViewById(R.id.inputButton);
inputButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
changeLayouts();
}
});
}
public void changeLayouts() {
setContentView(R.layout.layout2);
try {
TimeUnit.MILLISECONDS.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
setContentView(R.layout.layout3);
}
}
My idea was that Android might use something like an "Event-Loop" (like Qt) and my method would block the control to get back to the "Event-Loop" which would make the layout displayed.
But I couldn't find my error.
The problem why your layout2 is not shown is because of TimeUnit.MILLISECONDS.sleep(3000); - what you are doing here is you put your UI thread into sleep, so UI thread cannot process your request to change layout. And when it wakes up - it immediately sets layout3 that's why layout2 is not shown.
You might consider using Handler.postDelayed(Runnable, long) to postpone execution
So this should work as you expected:
public class TrainingActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout1);
final Button inputButton = (Button)findViewById(R.id.inputButton);
inputButton.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
changeLayouts();
}
});
}
public void changeLayouts() {
setContentView(R.layout.layout2);
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setContentView(R.layout.layout3);
}
}, 3000);
}
}
Try this, it will surely work
public void changeLayouts() {
setContentView(R.layout.layout2);
Thread Timer = new Thread(){
public void run(){
try{
sleep(3000);
} catch(InterruptedException e){
e.printStackTrace();
} finally {
setContentView(R.layout.layout3);
}
}
}; Timer.start();
}
I'm having a problem to change the button color after a certain amount of time. I know how to change using handle after a fixed time, but I need to change the color after a specific time that is chosen by the user.
public class MainActivity extends Activity {
EditText tempo;
Button bt;
int estado = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tempo = (EditText) findViewById(R.id.tempo);
long delay = Long.parseLong(tempo.getText().toString());
bt = (Button) findViewById(R.id.btvibrar);
bt.setOnClickListener(new View.OnClickListener() {
public void onClick(View arg0) {
if(!tempo.getText().toString().equals("")){
if(estado==1){
Vibrar();
estado*=-1;
bt.setText("Parar !");
bt.setBackgroundColor(Color.RED);
//Handler handler = new Handler();
//handler.postDelayed(new Runnable() {
//#Override
//public void run() {
//estado*=-1;
//bt.setText("Vibrar !");
//bt.setBackgroundColor(Color.GREEN);
//}
// }, );
} else {
Parar();
estado*=-1;
bt.setText("Vibrar !");
bt.setBackgroundColor(Color.GREEN);
}
} else {
AlertDialog.Builder dialogo = new AlertDialog.Builder(MainActivity.this);
dialogo.setTitle("Erro !");
dialogo.setMessage("Escolha um tempo.");
dialogo.setNeutralButton("OK", null);
dialogo.show();
}
}
private void Vibrar(){ // É necessario lançar excessao no ANDROIDMANIFEST.XML
Vibrator rr = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
long treal = Long.parseLong(tempo.getText().toString());
long milliseconds = treal*1000;
rr.vibrate(milliseconds);
}
private void Parar(){
Vibrator rr = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
rr.cancel();
}
});
}
}
try this in a button listener for example:
try {
Thread.sleep(_time_);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Button but = (Button)theMainActiv.findViewById(R.id.bSend);
but.setBackgroundColor(Color.BLUE);
the _time_ you can get it from an Edittext for example
be careful how much sleep time you put in - anything over 5 seconds and the system will give you a pop-up that tells the user your app is hung and offer to close it.
Sorry for being late, here is a full example:
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/etTime"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_marginLeft="34dp"
android:layout_marginTop="28dp"
android:text="Start" />
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#+id/button1"
android:layout_marginLeft="53dp"
android:layout_toRightOf="#+id/button1"
android:ems="10"
android:inputType="number|none"
android:digits="1234567890" >
<requestFocus />
</EditText>
MainActivity.java
package com.example.testevent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.Activity;
import android.graphics.Color;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class MainActivity extends Activity {
EditText etTime;
Button bStart;
myHandler mh;
int time;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bStart = (Button) this.findViewById(R.id.button1);
etTime = (EditText) this.findViewById(R.id.editText1);
bStart.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mh = new myHandler(bStart);
try {
time = Integer.parseInt(etTime.getText().toString());
} catch (Exception e) {
time = 1000;
}
tester a = new tester(mh, time);
a.start();
}
});
}
}
class myHandler extends Handler {
Button bStart;
public myHandler(Button bStart) {
this.bStart = bStart;
}
public void DisplayResult(String Result) {
// error management,creates an error message
Message msg = obtainMessage(1);
// sends the message to our handler
sendMessage(msg);
}
public void handleMessage(Message msg) {
// switch (msg.what)
bStart.setBackgroundColor(Color.RED);
}
}
class tester extends Thread {
myHandler mh;
int time;
public tester(myHandler mh, int time) {
this.mh = mh;
this.time = time;
}
#Override
public void run() {
try {
Thread.sleep(time);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// error management,creates an error message
Message msg = mh.obtainMessage(1);
// sends the message to our handler
mh.sendMessage(msg);
}
}