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);
Related
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);
I am trying to simulate an sending msg progress .
The main idea is to colour the members who message sent to them, promote the status bar etc.. (gui changes ) all this with delay for each loop iteration.
The main problem is that everything is going inside the onClick listener and runing thread inside it wont help ): cause gui is changing only after delay is completed.
Any one may advice me how to do this simulation ?
send.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
for(int i=0; i<phoneNumbers.size(); i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
members.get(i).setBackgroundColor(Color.GREEN);
members.get(i).invalidate();
mProgressDialog.setProgress(i+1);
sentCount.setText(getString(R.string.msgSentCount) + (i+1));
if(i==12){
scroolView.animate().translationYBy(-50);}
}
}
});
Thanks you very much !
If I unserstood you right - fake progress + waiting time. First of all handlers a perferct to delay an output:
//Fake Progress
progress = new ProgressDialog(this);
open(this);
// Delay output
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
setData();
}
}, 6000);
in the function setData(), do the task you wanna run after
and progress bar for fake:
public void open(Activity activity) {
progress.setMessage("Fakeprogress, Data Mining...");
progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progress.setIndeterminate(false);
progress.setCancelable(false);
progress.setMax(100);
progress.setProgress(10);
progress.show();
final int totalProgressTime = 100;
final Thread t = new Thread() {
#Override
public void run() {
int jumpTime = 0;
while (jumpTime < totalProgressTime) {
try {
sleep(60);
//System.out.println("********" + jumpTime);
jumpTime += 1;
progress.setProgress(0);
progress.setProgress(jumpTime);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
progress.dismiss();
}
};
t.start();
}
Finaly got it works with recursion !!!!
public static int counter=0;
public void runMother(final Handler handler)
{
if(counter==3)return;
handler.postDelayed(new Runnable() {
#Override
public void run() {
members.get(counter).setBackgroundColor(Color.GREEN);
counter++;
runMother(handler);
}
}, 1000*counter);
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();
}
}
}
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);
I need to stop a Runnable from running when an image is clicked in my Android app. I'm running this Runnable repeatedly using ImageView.postDelayed():
r = new Runnable() {
public void run() {
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
// imgview.setOnClickListener(this);
}
};
imgview.postDelayed(r, 20); // set first time for 3 seconds
But under certain conditions I want to stop it from running, after it's already started. Here's the full code for my activity:
public class MainActivity extends Activity {
int i = 0;
ImageView imgview, imgview2;
Handler handler = new Handler();
Runnable r;
MediaPlayer mMediaPlayer;
int[] imageArray = { R.drawable.f1, R.drawable.f2, R.drawable.f3,
R.drawable.f4, R.drawable.f5, R.drawable.f6, R.drawable.f7,
R.drawable.f8, R.drawable.f9, R.drawable.f10, R.drawable.f11,
R.drawable.f12, R.drawable.f13, R.drawable.f14, R.drawable.f15,
R.drawable.f16, R.drawable.f17, R.drawable.f18, R.drawable.f19,
R.drawable.f20, R.drawable.f21, R.drawable.f22, R.drawable.f23,
R.drawable.f24, R.drawable.f25, R.drawable.f26, R.drawable.f27,
R.drawable.f28 };
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.tapp_activity);
imgview = (ImageView) findViewById(R.id.imageView1);
mMediaPlayer = new MediaPlayer();
mMediaPlayer = MediaPlayer.create(MainActivity.this, R.raw.water);
mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC);
imgview2 = (ImageView) findViewById(R.id.imageView2);
imgview2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(i==0)
{
mMediaPlayer.setLooping(true);
mMediaPlayer.start();
i=1;
r = new Runnable() {
public void run() {
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20); // set to go off again in 3 seconds.
// imgview.setOnClickListener(this);
}
};
imgview.postDelayed(r, 20); // set first time for 3 seconds
}
else
{
i=0;
mMediaPlayer.stop();
imgview.setBackgroundResource(R.drawable.tapstill);
}
}
});
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mMediaPlayer.stop();
}
}
What can I change in my code so that my Runnable stops running in the else condition of my onClick() method?
You might try removing the callback.
imgview.removeCallbacks(r);
In order for this to work, though. you'd have to ensure that r is the same Runnable as the one you posted. You could do this by creating it once, possibly in onCreate. Since the Runnable doesn't have any dependency on the ClickListener anyway, this shouldn't be a problem.
You might also need to do some synchronization in order to prevent the case where you're removing a currently running callback, though, now that i think about it. The volatile boolean running idea is probably less complex overall.
You can control your run() method with a boolean flag:
boolean running = true;
...
r = new Runnable()
{
public void run()
{
if(running)
{
imgview.setImageResource(imageArray[i]);
i++;
if (i >= imageArray.length) {
i = 0;
}
imgview.postDelayed(r, 20);
}
};
}
If you set running = false later on, your thread will be idle and that's what you want.
You can do it by
Thread.stop();