I want to toast (or show a dialog) when progressbar ends. I tried to do this with if in run() method, but it causes the following error:
Can't create handler inside thread that has not called Looper.prepare()
how can I do that?
This is my code:
#Override
public void run() {
int myProgress = 0, Speed = 50;
ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progressbar);
while (myProgress<750){
try{
Thread.sleep(Speed);
myProgress++;
if (myProgressBar != null) {
myProgressBar.setProgress(myProgress);
}
}
catch(Throwable t){ }
}
}
runOnUiThread(new Runnable() {
public void run() {
//your code here
}
});
Change like this.
runOnUiThread(new Runnable() {
public void run() {
int myProgress = 0, Speed = 50;
ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progressbar);
while (myProgress<750){
try{
Thread.sleep(Speed);
myProgress++;
if (myProgressBar != null) {
myProgressBar.setProgress(myProgress);
}
}
catch(Throwable t){ }
}
}
});
Worker threads are meant for doing background tasks and you can't show anything on UI within a worker thread unless you call method like runOnUiThread. If you try to show anything on UI thread without calling runOnUiThread, there will be a java.lang.RuntimeException.
Tell me if you still face any problem.
I tried this and it works now:
public void run() {
int myProgress = 0, Speed = 50;
ProgressBar myProgressBar = (ProgressBar) findViewById(R.id.progressbar);
while (myProgress<750){
try{
Thread.sleep(Speed);
myProgress++;
if (myProgressBar != null) {
myProgressBar.setProgress(myProgress);
}
}
catch(Throwable t){ }
}
final int finalMyProgress = myProgress;
runOnUiThread(new Runnable() {
#Override
public void run() {
if (finalMyProgress == 750)
Toast.makeText(word_guess2.this, "hi", Toast.LENGTH_SHORT).show();
}
});
}
Related
I am trying to play with progress bars. I have this (below) simple activity which runs a progress bar N times one after the other, when I call Progress(N). It is working great but the problem I am facing is, if I press back button. I get into the mainActivity but the progress bars (the threads) are still running in background one after the other. As soon as they finish N loops, the intent is called and whatever I would be doing would be interrupted by this LOOP_OVER activity.
I tried solving this by my own. I tried using variable of Thread class (before I was directly doing it). And tried to interrupt() it at onDestroy() or even just before the intent is called but its not helping. How should I go about it?
public class Loop extends Activity {
private ProgressBar progressBar;
private CircleProgress circleProgress;
private int progressStatus = 0;
private Handler handler = new Handler();
private TextView myView;
private int started = 0, doneLoop=0;
private Thread th;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_loop);
progressBar = (ProgressBar) findViewById(R.id.progressBar1);
circleProgress = (CircleProgress) findViewById(R.id.circle_progress);
myView = (TextView) findViewById(R.id.instruction);
progressBar.setScaleY(3f);
// Start long running operation in a background thread
Progress(3);
}
#Override
public void onDestroy() {
// Below, everything I am just
th.interrupt();
Loop.this.finish();
Thread.currentThread().interrupt();
super.onDestroy();
}
public void Progress(final int numberOfRuns){
// QueView.setText(Que);
if(numberOfRuns == 0){
th.interrupt();
Intent myIntent = new Intent(Loop.this, LOOP_OVER.class);
startActivity(myIntent);
super.onDestroy();
finish();
}
th = new Thread(new Runnable() {
public void run() {
genNextSet();
while (progressStatus < 100) {
progressStatus += 1;
// Update the progress bar and display the
//current value in the text view
handler.post(new Runnable() {
public void run() {
circleProgress.setProgress(progressStatus);
progressBar.setProgress(progressStatus);
textView.setText(progressStatus+"/"+progressBar.getMax());
}
});
try {
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
myView.setText(Que);
}
});
// Sleep for 200 milliseconds.
//Just to display the progress slowly
Thread.sleep(30);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
progressStatus = 0;
Progress(numberOfRuns - 1);
}
});
th.start();
}
private void genNextSet() {
// so some cool here!
}
}
You can think of a class variable that is shared among all threads.
Try to add something like this:
private Boolean LOOP = true;
then
while (progressStatus < 100 && LOOP) {
and
#Override
public void onBackPressed() {
LOOP = false
}
also
if(LOOP == true){
// call intent
}
finish();
Your activity does not get destroyed, if you press the "Back"-key, thus onDestroy() will not be called.I'd override onBackPressed(), if I where you.Alternatively, you could try to put it into the onPause()-method.
You haven't override the back button pressed..try this
#Override
public void onBackPressed() {
th.interrupt();
Loop.this.finish();
Thread.currentThread().interrupt();
super.onBackPressed();
// add finish() if you want to kill current activity
}
And how should i solve it ?
This is my button click method that i call it from inside onCreate:
public void addListenerOnButton()
{
btnClick = (Button) findViewById(R.id.checkipbutton);
btnClick.setOnClickListener(new OnClickListener()
{
byte[] response = null;
#Override
public void onClick(View arg0)
{
text = (TextView) findViewById(R.id.textView2);
Thread t = new Thread(new Runnable()
{
#Override
public void run()
{
for (int i = 0; i < ipaddresses.length; i++)
{
try
{
response = Get(ipaddresses[i]);
if (response == null)
{
text.setText("Connection Failed: " + generateRunnablePrinter(i));
}
}
catch (Exception e)
{
String err = e.toString();
}
if (response != null)
{
try
{
final String a = new String(response, "UTF-8");
text.post(new Runnable()
{
#Override
public void run()
{
text.setText(a);
}
});
iptouse = ipaddresses[i].substring(0, 26);
connectedtoipsuccess = true;
Logger.getLogger("MainActivity(inside thread)").info(a);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
Logger.getLogger("MainActivity(inside thread)").info("encoding exception");
}
Logger.getLogger("MainActivity(inside thread)").info("test1");
break;
}
else
{
}
}
}
});
t.start();
}
});
}
At this place in the method inside the FOR loop the variable 'i' should be final:
text.setText("Connection Failed: " + generateRunnablePrinter(i));
But since 'i' is also the variable of the FOR loop i can't make it final.
So i added the method : generateRunnablePrinter
private Runnable generateRunnablePrinter(final int value)
{
return new Runnable() {
public void run()
{
text.setText("Connection Failed: " + ipaddresses[value]);
}
};
}
But now using this method I'm getting the exception:
ViewRootImpl$CalledFromWrongThreadException
You can't change the UI "text of the TextView" from another thread so you can try AsyncTask to do the work in the background in doInBackground() method then change the UI in the method onPostExecute().
Check out the AsyncTask:
http://developer.android.com/reference/android/os/AsyncTask.html
Since you're adjusting your UI, you'll need to run it from the UI thread. I'd recommend this function:
runOnUiThread(new Runnable() {
#Override
public void run() {
// Your code here...
}
});
If you're calling it from anywhere else but an Activity, you'll need to either pass down the activity or get the activity using getActivity() (i.e. from a fragment), and then call the function from the activity, i.e. getActivity().runOnUiThread() { ... }
Trying to get the following ;
ImageView x is shown for y seconds. Then, x is Invisible again and a different ImageView (z) is shown for y seconds. And so on..
I've got :
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.series_onthouden);
hideAllImages();
showImage(3, 2000);
showImage(4, 1000);
}
public void showImage(int color, final int sec) {
Thread thread = new Thread() {
#Override
public void run() {
try {
Thread.sleep(sec);
} catch (InterruptedException e) {
}
runOnUiThread(new Runnable() {
#Override
public void run() {
for (int i = 0; i < myImagebtns.length; i++) {
((ImageView) findViewById(myImagebtns[i]))
.setVisibility(View.INVISIBLE);
}
}
});
}
};
if (!thread.isAlive()){
((ImageView) findViewById(myImagebtns[color])).setVisibility(View.VISIBLE);
thread.start();
}
}
It works for the first color.. But also shows the second simultaniously. The second color should be shown when the first turns invisible (after x seconds).
ty
You could try using a Handler like the example below:
Handler handler = new Handler();
im1.setVisibility(View.VISIBLE);
handler.postDelayed(new Runnable() {
#Override
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
im1.setVisibility(View.INVISIBLE);
im2.setVisibility(View.VISIBLE);
}
});
}
},500);
where 500 is the delay between events.
Repeat postDelayed calls for as many images as necessary.
Hope this helps!
public class MainActivity extends Activity
{
int min, sec;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
min = 5;
sec = 0;
final TextView timer1 = (TextView) findViewById(R.id.timer1);
timer1.setText(min + ":" + sec);
Thread t = new Thread() {
public void run() {
sec-=1;
if (sec<0) {
min-=1;
sec=59;
}
timer1.setText(min + ":" + sec);
try
{
sleep(1000);
}
catch (InterruptedException e)
{}
}
};
t.start();
}
}
This is a code for a Thread in Java but it doesn't work. Can you help me?
Its a Timer that counts down from 5 Minutes to 0:00.
In your case you are using threads. So you cannot update ui from the thread other than the ui thread. SO you use runOnUithread. I would suggest you to use a countdown timer or a Handler.
1.CountDownTimer
http://developer.android.com/reference/android/os/CountDownTimer.html
Here's a link to another example. Suggest you to check the link for the count down timer.
Countdowntimer in minutes and seconds
Example:
public class MainActivity extends Activity {
Button b;
TextView tv;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = (TextView) findViewById(R.id.textView1);
b= (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener()
{
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
startTimer(200000);
}
});
}
private void startTimer(long time){
CountDownTimer counter = new CountDownTimer(30000, 1000){
public void onTick(long millisUntilDone){
Log.d("counter_label", "Counter text should be changed");
tv.setText("You have " + millisUntilDone + "ms");
}
public void onFinish() {
tv.setText("DONE!");
}
}.start();
}
}
2.You can use a Handler
Example :
Handler m_handler;
Runnable m_handlerTask ;
int timeleft=100;
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
if(timeleft>=0)
{
// do stuff
Log.i("timeleft",""+timeleft);
timeleft--;
}
else
{
m_handler.removeCallbacks(m_handlerTask); // cancel run
}
m_handler.postDelayed(m_handlerTask, 1000);
}
};
m_handlerTask.run();
3.Timer
Timer runs on a different thread. You should update ui on the ui thread. use runOnUiThread
Example :
int timeleft=100;
Timer _t = new Timer();
_t.scheduleAtFixedRate( new TimerTask() {
#Override
public void run() {
runOnUiThread(new Runnable() //run on ui thread
{
public void run()
{
Log.i("timeleft",""+timeleft);
//update ui
}
});
if(timeleft>==0)
{
timeleft--;
}
else
{
_t.cancel();
}
}
}, 1000, 1000 );
You are trying to update the UI Thread from a background Thread with
timer1.setText(
which you can't do. You need to use runOnUiThread(), AsyncTask, CountDownTimer, or something similar.
See this answer for an example of runOnUiThread()
But CountDownTimer is nice for things like this.
Also, when posting a question on SO, statements like "it doesn't work." are very vague and often unhelpful. Please indicate the expected results compared to actual results of your code and logcat if the app is crashing.
Handler hnd = new Handler() {
#Override
public void handleMessage(Message msg) {
int id = sequence.get(msg.arg1);
if(msg.arg1 % 2 == 0) {
sq.get(id-1).setBackgroundResource(R.drawable.square_show);
} else {
sq.get(id-1).setBackgroundResource(R.drawable.square);
}
}
};
#Override
public void onResume() {
super.onResume();
Thread background = new Thread(new Runnable() {
public void run() {
try {
for(int i = 0; i < sequence.size()-1; i++) {
record_tv.setText(""+i);
Thread.sleep(200);
Message msg = hnd.obtainMessage();
msg.arg1 = i;
msg.sendToTarget();
}
} catch(Throwable t) {
}
}
});
background.start();
}
[CODE UPDATED] now it goes through the first loop and stops
do you have any idea why the code in the first runOnUiThread gets executed but it doesn't do what i want?
what i want is: change the image to "square", wait 2 seconds, change the image to "square_show", wait 2 secs and repeat the loop
i've been struggling for an hour now...
You can easily set image using following code.
sq.get(id-1).setImageResource(R.drawable.square_show);
sq.get(id-1).setImageResource(R.drawable.square);
public void show(int size) {
// CICLE THROUGH EACH SQUARE
for(int i = 0; i <= size-1; i++) {
Thread thrd = new Thread() {
public void run() {
runOnUiThread(new Runnable() {
#Override
public void run() {
sq.get(id-1).setImageResource(R.drawable.square_show);
// System.out.println("1st..........");
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
sq.get(id-1).setImageResource(R.drawable.square);
// System.out.println("2nd..........");
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
}
};
thrd.start();
}
}
This is a wrong way to achieve it. This may help you.
http://developer.android.com/guide/topics/graphics/2d-graphics.html#tween-animation
I would suggest you to use a handler
int drawablebkg[] ={R.drawable.ic_launcher,R.drawable.icon};
Handler m_handler;
Runnable m_handlerTask ;
ImageView iv;
iv = (ImageView)findViewById(R.id.imageView1);
m_handler = new Handler();
m_handlerTask = new Runnable()
{
#Override
public void run() {
iv.setImageResource(android.R.color.transparent);
if(i<2)
{
ivsetBackgroundResource(drawablebkg[i]);
i++;
}
else
{
i=0;
}
m_handler.postDelayed(m_handlerTask, 2000);
}
};
m_handlerTask.run();
In onPause() of your activity
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
//_t.cancel();
m_handler.removeCallbacks(m_handlerTask);
}
Another way
iv= (ImageView)findViewById(R.id.imageView1);
AnimationDrawable animation = new AnimationDrawable();
animation.addFrame(getResources().getDrawable(R.drawable.ic_launcher), 2000);
iv.setImageResource(android.R.color.transparent);
animation.addFrame(getResources().getDrawable(R.drawable.icon), 2000);
animation.setOneShot(false);
iv.setBackgroundDrawable(animation);
//set setBackgroundDrawable(animation) is decprecreated i guess. not sure in which api
// start the animation!
animation.start();
Another way
Define background.xml in drawable folder
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="#drawable/ic_launcher" android:duration="2000" />
<item android:drawable="#drawable/icon" android:duration="2000" />
</animation-list>
I your activity onCreate();
ImageView iv = (ImageView)findViewById(R.id.imageView1);
iv.setBackgroundResource(R.drawable.background);
AnimationDrawable animation= (AnimationDrawable)loadingRaven.getBackground();
loadingRaven.setImageResource(android.R.color.transparent);
animation.start();
Note to stop the animation you need to call animation.stop()
Because the resource changes in the UI thread and you are sleeping your background thread. The UI thread is running normally.
Use handlers:
public class MainActivity extends Activity {
Button b;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b = (Button) findViewById(R.id.button1);
}
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (msg.arg1 % 2 == 0) {
b.setBackgroundResource(R.drawable.analytic_icon);
} else {
b.setBackgroundResource(R.drawable.ic_launcher);
}
}
};
#Override
public void onResume() {
super.onResume();
Thread background = new Thread(new Runnable() {
public void run() {
try {
for (int i = 0; i < 20; i++) {
Thread.sleep(2000);
Message msg = handler.obtainMessage();
msg.arg1 = i;
msg.sendToTarget();
}
} catch (Throwable t) {
// just end the background thread
}
}
});
background.start();
}
}
Try this,It will work:
public void show(final int size) {
Thread thrd = new Thread(new Runnable() {
#Override
public void run() {
for (int i = 0; i <= size - 1; i++) {
id = (Integer) sequence.get(i);
runOnUiThread(new Runnable() {
#Override
public void run() {
sq.get(id - 1).setBackgroundResource(
R.drawable.square_show);
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
#Override
public void run() {
sq.get(id - 1).setBackgroundResource(
R.drawable.square);
}
});
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thrd.start();
}