I have a simple program with one button. Once I clicked on the button loop started and should display the current value in TextView dynamically. But this display the value when loop is completed.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv=(TextView) findViewById(R.id.textView2);
}
public void btnClick(View v) throws Exception {
for (int i=0;i<10;i++){
tv.setText("Value of I "+i);
Thread.sleep(500);
}
}
My expected output is displaying values from 0, 1,.... dynamically but displayed 9 at last. if I use append I have to wait until loop terminated. Please help me.
Try this:
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);
}
Make sure you declare int i = 0 globally
tv.append("text here") is your answer.
don't use Thread.sleep() in your main UI thread this should give an exception instead use a new Thread like this
Thread myThread = new Thread(new Runnable() {
#Override
public void run() {
for (int i=0;i<10;i++){
tv.setText("Value of I "+i);
Thread.sleep(500);
}
}
});
myThread.start();
or if there is more complex operations you make you will have to use AsyncTask calss
Related
I'm currently working on a weather project in Android Studio where I want to schedule image changes in my design background every 5 seconds, I have all the image resources in my #drawable directory. I watched a basic tutorial where they explained some things in the demo but it only helped a little and didn't quite suit me, I'm still confused because I'm getting a lot of errors but I've currently tried these few codes:
HomeActivity.java:
public class HomeActivity extends AppCompatActivity {
public static int count=0;
int[] drawablearray=new int[]{R.drawable.burj_khalifa,R.drawable.central_bank_of_nigeria,R.drawable.eiffel_tower,R.drawable.hong_kong,R.drawable.statue_of_liberty};
Timer _t;
ImageView imageView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
imageView = findViewById(R.id.imageView);
ImageView = (ConstraintLayout) findViewById(R.id.lnMain);
_t = new Timer();
_t.scheduleAtFixedRate(new TimerTask); {
public void run(); {
runOnUiThread(new Runnable() { // run on ui thread
#Override
public void run() {
if (count < drawablearray.length) {
lnMain.setBackgroundDrawable(drawablearray[count]);
count = (count + 1) % drawablearray.length;
}
}
});
}
}, 5000, 5000);
}
}
Any Idea on how to Organize it to suit the design?
final Handler h = new Handler();
Runnable r = new Runnable() {
public void run() {
Home.this.getWindow.setBackgroundDrawableResource(drawableArray[count]);
cout += (count + 1) % drawableArray.length;
h.postDelayed(this, 5000);
}
};
final Runnable r = new Runnable() {
public void run() {
imageView.setBackgroundDrawableResource(drawablearray[count]);
count += (count+1)%(drawablearray.length);
handler.postDelayed(this, 5000);
}
};
And the call is like this:
handler.postDelayed(r,0);
This will call the runnable to execute and handle.postDelayed will run the method every 5000 millsec.
I already fixed the error by using constraintlayout in place of imageview and inmain. I also got id for the layout:
constraintLayout = findViewById(R.id.layout);
constraintLayout.setBackgroundResource(R.drawable.burj_khalifa);
_t = new Timer();
_t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() { // run on ui thread
#Override
public void run() {
if (count < drawable.length) {
constraintLayout.setBackgroundResource(drawable[count]);
count = (count + 1) % drawable.length;
}
}
});
}
}, 5000, 5000);
}
}
This question already has answers here:
Update TextView Every Second
(11 answers)
Closed 4 years ago.
i want to update my textview every second.
on button click i am calling one method,
loopMethod(milli); //suppose milli= 50000 i.e 50 sec.
so my loopMethod(int m) is as follows:
public void loopMethod(int m){
timer=(TextView) findViewById(R.id.timerText);
if(m>=1000){
try {
timer.setText(""+m);//timer is a textview
System.out.println(m);
m=m-1000;
Thread.sleep(1000);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
loopMethod(m);
}
}
so what i am expecting is, my timer textview should print the value of m every second.
but i am getting only console output i.e system.out.println(m)...
printing value on console working fine...
but its not updating my textview at all
You can use following code:
Runnable updater;
void updateTime(final String timeString) {
timer=(TextView) findViewById(R.id.timerText);
final Handler timerHandler = new Handler();
updater = new Runnable() {
#Override
public void run() {
timer.setText(timeString);
timerHandler.postDelayed(updater,1000);
}
};
timerHandler.post(updater);
}
In this line:
timerHandler.post(updater);
time will set for the first time. i.e, updater will execute. After first execution it will be posted after every 1 second time interval. It will update your TextView every one second.
You need to remove it when the activity destroys, else it will leak memory.
#Override
protected void onDestroy() {
super.onDestroy();
timerHandler.removeCallbacks(updater);
}
Hope it will help you.
You should use RxJava library to do so:
Subscription s =
Observable.interval(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(v -> {
// update your ui here
}, e -> {
});
// call when you no longer need an update:
if (s != null && !s.isUnsubscribed()){
s.unsubscribe();
s = null;
}
That's it. Do NOT use .postDelay(), Timer because it is error prone.
You might want to consider using the Chronometer class: https://developer.android.com/reference/android/widget/Chronometer.html
just use timer.start(); on the button click
Using handler can be used like this
TextView timer;
int m =0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
timer=(TextView) findViewById(R.id.timerText);
Handler handler = new UpdateHandler();
m = 10;
handler.sendEmptyMessageDelayed(1, 1000);//start after 1000
}
class UpdateHandler extends Handler{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
switch (msg.what) {
case 1:
timer=(TextView) findViewById(R.id.timerText);
timer.setText("Text :" +m);
m = m-1000;
sendEmptyMessageDelayed(1, 1000); //seng again after 1000
//add some stop logic
break;
default:
break;
}
}
}
Try this code Initialize textview in
onCreate
timer=(TextView) findViewById(R.id.timerText);
public void loopMethod(int m){
if(m>=1000){
try {
System.out.println(m);
m=m-1000;
final ScheduledThreadPoolExecutor c = new ScheduledThreadPoolExecutor(1);
c.schedule(new Runnable() {
#Override
public void run() {
timer.setText(""+m);//timer is a textview
c.shutdownNow();
}
}, 1, TimeUnit.SECONDS);
} catch(InterruptedException ex) {
ex.printStackTrace();
}
loopMethod(m);
}
}
I've added some logics to stop the Timer. If you have any qyestion, ask freely
private int m = 0;
private int milliseconds = 1000;
public void loopMethod(int m){
timer=(TextView) findViewById(R.id.timerText);
Timer t = new Timer();
//schedule a timer
t.scheduleAtFixedRate(new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
timer.setText(String.valueOf(m));//avoid using composite string in the setText
System.out.println(String.valueOf(m));
//remove from the total the amount of millisecond passed
m=m-milliseconds;
if(m <= milliseconds) { //or <= what you want
//stop the timer repeatitions
t.cancel();
}
}
});
}
//"0" is the amount of time to wait for the timer to start
//"milliseconds" is the duration
},0,milliseconds);
}
Add
For a correct analysis you should add more infos in your question. the problem of not-updating textview might be caused by the setText("" + int) because it's always better to avoid the setText with an int. I edited it with String.valueOf, but if it's not working you should add the xml and the onCreate
Hope this helped
I have created timer for seconds.
public class TimerForSeconds extends AppCompatActivity {
private int seconds = 60;
private TextView tvTimer;
private Handler mHandler;
private Runnable runnable = new Runnable() {
#Override
public void run() {
if(seconds == 0){
mHandler.removeCallbacks(runnable);
}
else{
tvTimer.setText(seconds + "");
seconds--;
mHandler.postDelayed(runnable,1000);
}
}
};
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.test_activity);
tvTimer = (TextView) findViewById(R.id.tv_timer);
mHandler = new Handler();
mHandler.postDelayed(runnable,1000);
}
}
//and also removCallback onDestroy too.
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 want to print a single word at a time in textView and then using sleep and then next word.
but it int'n working.. need help.
String s = MainActivity.check;// String check defined in mainactivity this is second
String[] words = s.split(" ");
EditText et = (EditText) findViewById(R.id.editText2);
for(int i=0;i<words.length; i++ ){
et.setText(words[i]);
Thread.sleep(1000);
}
above output only last word in textView
You are setting th text new on each iteration. Try et.setText(et.getText() + words[i]);
This takes the text that is already in the TextView then appends the new word.
Any updates to the UI in an Android application must happen in the UI thread. If you spawn a thread to do work in the background you must marshal the results back to the UI thread before you touch a View.
You must use Handler class to do so...
public EditText et;
Handler handler;
oncreate(..) {
setContentView(R.layout.main);
et = new EditText(context);
Thread t =new Thread(){
public void run() {
handler.post(new Runnable() {
public void run() {
et.setText("test");
}
});
}
}};
t.start();
}
Try using handler instead:
for(int i=0;i<words.length; i++ ){
final int j = i;
String text = words[j];
new Handler().postDelayed(new Runnable() {
public void run() {
et.setText(text);
}
}, 1000);
}
ok , Here is your answer :
int i = 0;
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
textView.setText(""+i);
i++;
handler.postDelayed(this, 1000);
}
}, 1000);
the UI is very simple, only having a button login and a scrollable TextView on it, when i press the button login, 100 lines of messages will add to the TextView, but they are added at the same time, and because i need do with the messages that will add to the TextView, which will cost a few time, sometimes the app looks like no response. i hope that the message could add to the TextView line by line. IOW i want the TextView displays the added line of message in each loop. how can i realize that? Here is the main code which has been simplified:
login.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
for(int i = 0; i < 100; i++) {
mTextView.append("test\n");
}
}
}
login.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mTextView.setText("");
for(int i = 0; i < 100; i++) {
mTextView.setText(mTextView.getText()+"test\n");
}
}
}
Try this code it should work
Use this:
login.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
mTextView.setText("");
if (!isStopped) {
Acitivut.this.runOnUiThread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 100; i++) {
mTextView.append("test\n");
}
isStopped=true;
}
});
}
}
}
Anything that changes UI element, must run on UI thread. Since you are running long running loop, your app freezes. You should either change the design and avoid updating UI in loop or you can use run a background thread and append the text to StringBuilder and when loop is over, append the StringBuilder text to the mtextView.
Again, if your StringBuilder contains very large text, updating that to UI may freeze it again.
login.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
i=0;
Thread thread=new Thread(new SleepThread());
thread.start();
}
}
private class SleepThread implements Runnable
{
public void run()
{
sleep(10);
handler.sendEmptyMessage();
}
}
Handler handler=new Handler()
{
public void handleMessage(Message msg)
{
mTextView.append("test\n");
i++;
if(i<100)
{
Thread thread=new Thread(new SleepThread());
thread.start();
}
}
}