Basically, I am trying to run a seconds counter and a levels counter. For every 10 seconds I want to ++level.
But that's not implemented as yet, so far I am just trying to get the seconds to display but I am getting runtime exceptions and a crash.
Googling I see that its because I am trying to update the UI from my thread and thats not allowed.
So I guess I am going to need asyncTask, but I have no idea how to do that with my simple little program. Please help or give me some alternatives...
package com.ryan1;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class main extends Activity {
int level = 1;
int seconds_running=0;
TextView the_seconds;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
the_seconds = (TextView) findViewById(R.id.textview_seconds);
Thread thread1 = new Thread(){
public void run(){
try {
sleep(1000); Log.d("RYAN", " RYAN ");
updated_secs();
} catch (Exception e) {
e.printStackTrace();
Log.d("RYAN", " "+e);
}
}
};
thread1.start();
}
public void updated_secs(){
seconds_running++;
the_seconds.setText(" "+seconds_running);
}
}
Create a Handler in your UI thread, then in the worker thread send a message to the handler (Handler.sendMessage(...)).
The message will be processed on your UI thread, so you can update the text widget correctly. Like this:
private Handler myUIHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
if (msg.what == some_id_you_created)
{
//Update UI here...
}
}
};
Then in your thread, to send a message to the handler you do this:
Message theMessage = myHandler.obtainMessage(some_id_you_created);
myUIHandler.sendMessage(theMessage);//Sends the message to the UI handler.
For this kind of thing, it is a waste to use another thread; it is just a waste and makes it so you have to dael with multithreading issues. Instead, just use Handler.sendDelayedMessage():
static final int MSG_DO_IT = 1;
static final long TIME_BETWEEN_MESSAGES = 10 * 1000; // 10 seconds
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_DO_IT: {
// Update your UI here...
Message newMsg = obtainMessage(MSG_DO_IT);
sendMessageDelayed(newMsg, TIME_BETWEEN_MESSAGES);
} break;
}
}
}
#Override
void onResume() {
super.onResume();
// Start the timer, executing first event immediately.
Message newMsg = mHandler.obtainMessage(MSG_DO_IT);
mHandler.sendMessage(newMsg);
}
#Override
void onPause() {
super.onPause();
// Stop the timer.
mHandler.removeMessages(MSG_DO_IT);
}
Note that this implementation will have some drift -- the actual time between messages is TIME_BETWEEN_MESSAGES + (time to dispatch message). If you need something that won't drift, you can do the timing yourself by using Hander.sendMessageAtTime() and incrementing the new time with a constant value each time, starting with an initial time you get with SystemClock.uptimeMillis() in onResume().
There is a great example of a Timer built using AsyncTask and a Handler with the postDelayed method.
You are correct that updating the UI from a background is a no-no.
Related
I have a simple Activity with two buttons "On" and "Off". I want start changing color of background in cycle with button "On" and stop this with button "Off". Also I need to have red color by click on "Off" button. I have wrote simple programm and everything is fine, but I can't understand one thing. Why the last color not always red? If I use code in main threads cycle
Thread.sleep(100);
or
Thread.sleep(1000);
I always have red color, but if I set
Thread.sleep(10);
I have random last color. Why??
Thank you !!
I have this code:
public class MyActivity extends Activity {
final Handler myHandler = new Handler();
private int randColor;
final Runnable updateColor = new Runnable() {
public void run() {
final Random random = new Random();
randColor = Color.rgb(random.nextInt (255), random.nextInt (255), random.nextInt (255));
mRelativeLayout.setBackgroundColor(randColor);
}
};
private ColorChanger myThread;
class ColorChanger extends Thread {
private volatile boolean mIsStopped = false;
#Override
public void run() {
super.run();
do
{
if (!Thread.interrupted()) {
myHandler.post(updateColor);
}
else
{
return;
}
try{
Thread.sleep(100);
}catch(InterruptedException e){
return;
}
}
while(true);
}
public void stopThis() {
this.interrupt();
}
}
private RelativeLayout mRelativeLayout;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
mRelativeLayout = (RelativeLayout)findViewById(R.id.relativeLayout);
}
public void onflagClick(View view) {
myThread = new ColorChanger();
myThread.start();
}
public void onflagoffClick(View view) throws InterruptedException {
myThread.interrupt();
if(myThread.isAlive())
{
try {
myThread.join();
} catch(InterruptedException e){
}
}
else
{
mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.redColor));
}
mRelativeLayout.setBackgroundColor(getResources().getColor(R.color.redColor));
}
}
I agree with the previous answer-ers, but propose a different solution.
First let me say that I recommend you stop using Runnables. In general posting a Runnable to a Handler is less efficient then sending a Message, although there are very rare exceptions to this rule.
Now, if we send Messages, what should we do? What we basically want to do is keep doing whatever we're doing until a condition is hit. A great way to do this is to write a Message Handler that receives a Message, does our work (setting the color), checks if we should keep going, and if so schedules a new Message in the future to do more work. Let's see how we might do this.
Assume the code below is inside an Activity.
private static final int MSG_UPDATE_COLOR = 1;
private static final int DELAY = 10; //10 millis
private final Object mLock = new Object();
private boolean mContinue = true;
Handler mHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_COLOR:
synchronized (mLock) {
if (mContinue) {
setColor(Color.rgb(random.nextInt (255), random.nextInt (255), random.nextInt (255)));
mHandler.sendEmptyMessageDelayed(MSG_UPDATE_COLOR, DELAY);
} else {
setColor(Color.RED);
}
}
break;
}
}
}
}
public void onflagClick(View view) {
mHandler.sendEmptyMessage(MSG_UPDATE_COLOR);
}
public void onflagoffClick(View view) throws InterruptedException {
synchronized (mLock) {
mContinue = false;
}
// cancel any pending update
mHandler.removeMessages(MSG_UPDATE_COLOR);
// schedule an immediate update
mHandler.sendEmptyMessage(MSG_UPDATE_COLOR);
}
Okay, so, what is happening here. We've created a Handler that will do all the color updates. We kick that off when our start event happens. Then the Message schedules a new message (and therefore color update) in ten milliseconds. When the stop event happens we reset a flag that the message handler reads to determine if a new update should be scheduled. We then unschedule all update messages because it might be scheduled for several milliseconds in the future and instead send an immediate message that does the final color update.
For bonus points we eliminate the use of a second thread which saves resources. Looking carefully I've used synchronized blocks, but these are actually unnecessary because everything is happening on the main thread. I included these just in case someone was changing mContinue from a background thread. Another great point of this strategy is that all color updates happen in one place in the code so it is easier to understand.
When you post to Handler, it will run your Runnable at some given time in the future. It is not immediate. It also works in a queue so the more times you post to Handler you are going to stack up the commands that will all get executed in order eventually.
You're facing a race condition because with Thread.sleep(10), the program is most likely stacking up a lot of Runnables to execute. They will run regardless of whether or not your Thread is running because they've been queued up to run on the main thread. Thread.sleep(100) or Thread.sleep(1000) doesn't have this issue simply because you're giving the system enough time to execute all color commands. However, it is still possible to have this issue if you pressed the off button at just the right time.
As DeeV told you, Handler sends Runnables to a Looper that is basically a Thread looping inside processing messages or runnables in each loop. You are queuing messaged to the main Looper and then you are sleeping your worker Thread. Its possible that you are sending for example 2 runnables in a row between each loop of your worker thread, but the main looper has only executed the last one so you cannot see each color as you want.
If you want a simple solution to make it work, you can use an Object or a CountDownLatch to synchronize your main Looperwith your worker Thread.
For example: Just before you will sleep your worker Thread you can do the next thing myLockObject.wait()
Then, you should change post(Runnable) to sendMessage(Message). In handleMessage from your Handler you can do myLockObject.notify() (Keep in mind that handleMessage will be executed inside the Looper that you have created your Handler or you can specify any Looper you want explicity). To obtain a new Message you should use myHandler.obtainMessage().
This will make your worker Thread wait your main Looperto process your runnable just before you wait X time until you post next color. Obviously you should create your new Object as a field of your Activity for example:
private myLockObject = new Object()
I found this code on the net. I am a newbie so i don't know much about java and android handler. I know how to use Runnables in handler to post on ui thread. But In this code use of handler.sendMessage(handler.obtainMessage)I didn't get it. I also confused about difference between atomic boolean and boolean. So please exaplain this. help is appreciated.
package com.example.watch;
import java.util.Calendar;
import java.util.concurrent.atomic.AtomicBoolean;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.TextView;
import android.app.Activity;
public class MainActivity extends Activity {
TextView watch;
AtomicBoolean ContinueThread = new AtomicBoolean(false);
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
watch = (TextView) findViewById(R.id.txtWatch);
displayCurrentTime();
}
public void displayCurrentTime() {
Calendar c = Calendar.getInstance();
// String curTime = String.valueOf(c.getTime());
int hours = c.get(Calendar.HOUR);
int minutes = c.get(Calendar.MINUTE);
int seconds = c.get(Calendar.SECOND);
String curTime = hours + ":" + minutes + ":" + seconds;
watch.setText(curTime);
}
public void onStart() {
super.onStart();
Thread background = new Thread(new Runnable() {
#Override
public void run() {
try {
while(ContinueThread.get()) {
Thread.sleep(1000);
handler.sendMessage(handler.obtainMessage());
}
} catch (Throwable t) {
}
}
});
ContinueThread.set(true);
background.start();
}
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
displayCurrentTime();
}
};
public void onStop() {
super.onStop();
ContinueThread.set(false);
}
}
if you want your code to run in UI thread you might want Handler.
A Handler allows you to send and process Message and Runnable objects
associated with a thread's MessageQueue. Each Handler instance is
associated with a single thread and that thread's message queue.
When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it -- from that point on, it will deliver messages and runnables to that message queue and execute them as they come out of the message queue.
There are two main uses for a Handler:
(1) to schedule messages and runnables to be executed as some point in
the future;
and
(2) to enqueue an action to be performed on a different thread than
your own.
You can read more here about handler and its usage.
For boolean and atomic boolean Read this and this
Not sure whether you have read Handler and AtomicBoolean document. Handler is associated with thread's message queue, which is thread-safe. so you can transfer data between threads by Handler, and not need to worry about synchronization. AtomicBoolean is a class for boolean value synchronization, not a primitive data type.
I have to run a bit of code in the background every one second, the code will call a webservice which searches a database and returns a value to the application. My question is which method would be the most effective to do this? I have read up on Timers, Threads, AsyncTask and Services and each seem to have their pros and cons. Please can someone tell me which would be the best to use considering execution time and battery life.
Thanks
Update:
I decided to use Aysnc task to run my code in the background while using a TimeTask to trigger the AsyncTask at regular intervals. This way the operation is destroyed when I leave that particular activity
You should use the service to do the background operation but in your case you want to run code in 1 sec here is the example of service using handler it call in every 1 sec.
public class YourService extends Service {
private static final String TAG = "Your Service";
private final Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
}
};
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// Toast.makeText(this, "My Service Created", Toast.LENGTH_LONG).show();
Log.d(TAG, "onCreate");
}
#Override
public void onDestroy() {
super.onDestroy();
// Toast.makeText(this, "My Service Stopped", Toast.LENGTH_LONG).show();
handler.removeCallbacks(sendUpdatesToUI);
}
private Runnable sendUpdatesToUI = new Runnable() {
public void run() {
/// Any thing you want to do put the code here like web service procees it will run in ever 1 second
handler.postDelayed(this, 1000); // 1 seconds
}
};
#Override
public void onStart(Intent intent, int startid) {
handler.removeCallbacks(sendUpdatesToUI);
handler.postDelayed(sendUpdatesToUI, 1000);//1 second
Log.d(TAG, "onStart");
}
}
and service can't run every time android idle the service within 3 or 4 hr i suggested you to use the foreground service to use your process long running.
For operations like this I tend to use a Service component. for the task itself i use an AsyncTask which will wait a set time before it repeats itself (using a while loop).
You will have to create a new Thread so that the call don't lock up the device if the call takes longer than expected. The AsyncTask is an easy way to use multithreading, but it lacks the functionality of repeating tasks. I would say that you are best of either using a Timer or the newer ScheduledExecutorService.
If you chose to use the Timer you create a TimerTask that you can hand it. The ScheduledExecutorService takes a Runnable instead.
You might want to wrap the thread in a Service (The Service does not provide a new Thread), but this is not always necessary depending on your needs.
As suggested in comment, you can also use the Handler.postDelayed(). Although you still need to create a new thread and then call Looper.prepare() on it:
class LooperThread extends Thread {
public Handler mHandler;
public void run() {
Looper.prepare();
mHandler = new Handler() {
public void handleMessage(Message msg) {
// process incoming messages here
}
};
Looper.loop();
}
}
(Code from Looper docs)
Also; calls to a webservice every second seems way too frequent, especially if the user is on a slow connection or there are data that needs to be transferred, try to reduce the calls as much as possible.
I think it's not only one solution, so it's up to you. You can try start thread with this run method:
private final int spleeptime = 1000;
public boolean running;
#Override
public void run() {
while (running) {
try {
int waited = 0;
while ((waited < spleeptime)) {
sleep(100);
waited += 100;
}
} catch (InterruptedException e) {
} finally {
// your code here
}
}
}
I have this code. I don't know why postDelay make UI frozen in this case. I want the Runnable will run after 100 miliseconds deley and run in 4000 miliseconds.
package com.delaythread;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class MyNeedActivity extends Activity implements OnClickListener {
private ProgressBar progressBar;
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
progressBar.setVisibility(ProgressBar.INVISIBLE);
}
};
#Override
public void onClick(final View v) {
if(v.getId() == R.id.button1) {
/* This call doesn't make ProgressBar frozen.
final Thread t = new Thread(new MyRunnable());
t.start();
progressBar.setVisibility(ProgressBar.VISIBLE);
*/
// This makes ProgressBar frozen in 4000 miliseconds.
final boolean b = handler.postDelayed(new MyRunnable(), 100);
if(b) {
progressBar.setVisibility(ProgressBar.VISIBLE);
}
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
((Button)findViewById(R.id.button1)).setOnClickListener(this);
progressBar = (ProgressBar)findViewById(R.id.progressBar1);
}
private class MyRunnable implements Runnable {
#Override
public void run() {
sleep();
}
private void sleep() {
try {
Thread.sleep(4000);
handler.sendEmptyMessage(0);
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
}
}
Update: Actually what I want is AsyncTask executes after a delay time, so I do as this answer Java/android how to start an AsyncTask after 3 seconds of delay?. He said I should use Handler and Runnable.
The following should suit your need according to the post
private final Handler handler = new Handler() {
#Override
public void handleMessage(final Message msg) {
super.handleMessage(msg);
//start Asyntask here. progress show/hide should be done in asynctaswk itself.
}
};
#Override
public void onClick(final View v) {
if(v.getId() == R.id.button1) {
final boolean b = handler.postDelayed(new MyRunnable() , 1000);
}
}
private class MyRunnable implements Runnable {
#Override
public void run() {
handler.sendmessage(0);
}
}
}
You probably want to run your MyRunnable on other thread than main UI one, so you need to start a regular thread for this, like
new Thread(new MyRunnable()).start();
instead of using Handler for this, which queues your runnable to be executed on main UI thread.
BTW, for this purpose Timer with TimerTask would suit better.
The Android Reference for the class Handler points out:
"[...] When you create a new Handler, it is bound to the thread / message queue of the thread that is creating it [...]"
So your Handler, created on instantiation of the Activity, should be running on the UI thread causing it to block when your Runnable is executed.
Try creating a new Thread class in which your Handler is instantiated. Then pass the Runnable to it from your onClick() method. To pass messages back (such as updating the progress bar) you can use another Handler that is running on the UI thread.
You could also save yourself a lot of pain by taking a look at the AsyncTask class.
PS:
Delaying the execution could be done in the AsyncTaskdoInBackground() via a Thread.sleep(100) call. To delay execution on UI thread level you could do the same in AsyncTask.onPreExecute().
As far as I understand it you ask your MyRunnable to run on the GUI thread (of which there is only one); but the only this it does is sleep, effectively causing the GUI thread to freeze waiting for it.
You shouldn't do complicated calcultaions (or, sleep) in the GUI thread.
You may want to read the documentation on threads and the UI thread for a more elaborate description.
Your progress bar isn't updating because you aren't updating it! Try using an AsyncTask, (it runs on a different thread but allows you to update UI elements) and setting the state of the progress bar from within the onProgress method in the Async task.
OR
Just follow this example on the Android Progress Bar page
Try this:
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
//Code to be executed after desired seconds
}
}, seconds*1000);
This would freeze the UI for given number of seconds and the execute the code inside the run()
I have a main menu with an action bar. On create, I run a thread that hits my server for a current status. When Complete, the thread calls a handler which kicks off a constantly running thread that cycles through the items and uses another handler call to change the test in the actionbar. The problem is that when I change views, I either get android.view.WindowLeaked or View not attached to window manager
Here is some sample code
public class MainMenuActivity extends ProtectedWithActionBarActivity{
private int STATUS_COUNTER;
private final int RESULT_STATUS_LOADED = 2000;
private final int RESULT_SHOW_STATUS = 2001;
private CurrentStatusModel currentStatus;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mainmenu);
ActionBar footerbar = (ActionBar)findViewById(R.id.footerbar);
footerbar.setTitle("Currently connected to " + PreferencesHelper.getCurrentEnvironment().name());
STATUS_COUNTER = 0;
statusLoadThread.start();
}
Thread statusLoadThread = new Thread()
{
#Override
public void run()
{
//set currentStatus with data from server
}
};
Thread statusDisplayThread = new Thread()
{
int sleep = 5000;
boolean threadDone = false;
public void done()
{
threadDone = true;
}
#Override
public void run()
{
while(true)
{
//pick message to send to handler
//increment STATUS_COUNTER or reset to 0 when out of bounds
try
{
sleep(sleep);
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
switch(msg.what)
{
case RESULT_STATUS_LOADED:
statusDisplayThread.start();
break;
case RESULT_SHOW_STATUS:
ActionBar footerbar = (ActionBar)findViewById(R.id.footerbar);
String message = ((Object[])msg.obj)[0].toString();
OnClickListener listener = (OnClickListener)((Object[])msg.obj)[1];
footerbar.setTitle(message);
footerbar.setOnTitleClickListener(listener);
break;
case ActivityBase.RESULT_ERROR:
break;
}
}
};
}
I'm not sure if what I'm doing is just wrong or if there is something blatantly obvious that I am missing. What needs to happen is the threads need to stop any time I change screens. Should I use Thread.interrupt(); before starting the next activity?
AsyncTasc allows you to implement doInBackground(), where your thread can crank away at its task. This is similar to the functionality you'd get from Thread.
The real magic happens when you override onPreExecute() and onPostExecute(), which are both executed on the UI thread. This should keep you from getting messages about your Activity not being attached.
Edit - this answer contains a small code example for AsyncTask that could get you started.
You are trying to update UI elements after the owning Activity has been detached from the windowing system.
You will make your life a lot simpler if you use AsyncTask instead of vanilla threads (no handler needed, for one thing) and cancel() the background tasks from your Activity.onPause().
Can't you set a flag in onPause that each of your Threads checks for? If the flag is set then the thread drops out of its loop. Thus whenever the Activity is moved to the background each of your Threads will stop. You would need to handle restarting the threads in onResume. You could alternatively use the AsyncTask approach, but this is not guaranteed to actually cancel when you call its cancel() method, it only attempts to cancel the task.