final Handler handler = new Handler();
LOG.d("delay");
handler.postDelayed(new Runnable() {
#Override public void run() {
LOG.d("notify!");
//calling some methods here
}
}, 2000);
The "delay" does shows in the log, but not others at all. And the method called in the run() is not called at all also. Can anyone help explain why this happens, am I doing anything wrong?
The class that has this code extends IntentService, will this be a problem?
============================
UPDATE:
I put this code in the class that extends IntentService. The only place I found it worked was in the constructor. But I need to put it in the onHandleIntent method. So I checked the documentation for onHandleIntent and it said:
This method is invoked on the worker thread with a request to process.Only one Intent is processed at a time, but the processing happens on a worker thread that runs independently from other application logic. So, if this code takes a long time, it will hold up other requests to the same IntentService, but it will not hold up anything else. When all requests have been handled, the IntentService stops itself, so you should not call stopSelf.
So based on the result I get, I feel like I cannot use postDelayed in "worker thread". But can anyone explain this a bit more, like why this is not working in worker thread? Thanks in advance.
Convert
final Handler handler = new Handler();
to
final Handler handler = new Handler(Looper.getMainLooper());
This worked for me.
You are using looper of the main thread. You must create a new looper and then give it to your handler.
HandlerThread handlerThread = new HandlerThread("background-thread");
handlerThread.start();
final Handler handler = new Handler(handlerThread.getLooper());
handler.postDelayed(new Runnable() {
#Override public void run() {
LOG.d("notify!");
// call some methods here
// make sure to finish the thread to avoid leaking memory
handlerThread.quitSafely();
}
}, 2000);
Or you can use Thread.sleep(long millis).
try {
Thread.sleep(2000);
// call some methods here
} catch (InterruptedException e) {
e.printStackTrace();
}
If you want to stop a sleeping thread, use yourThread.interrupt();
this is how i use handler:
import android.os.Handler;
Handler handler;
//initialize handler
handler = new Handler();
//to start handler
handler.post(runnableName);
private Runnable runnableName= new Runnable() {
#Override
public void run() {
//call function, do something
handler.postDelayed(runnableName, delay);//this is the line that makes a runnable repeat itself
}
};
Handlers and Services will be predictable when the device screen is on.
If the devices goes to sleep for example the Handler will not be a viable solution.
A much more better and reliable solution will be to use:
AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
IntentService is not designed for such scenario. You can use a regular Service instead. You can put the handler inside the onStartCommand(). Don't forget to
call stopSelf() on the Service instance to shut it down after the handler.postDelayed(){}
The most simple is to wait before ending onHandleIntent():
SystemClock.sleep(2000);
Related
I am writing an Android application where I need to periodically (every 30 seconds) fetch data from the server. I was thinking about using AlarmManager to schedule those tasks, however I need to be able to pass a callback function that updates the view. Since the Intent cannot encapsulate a callback, I decided to find another solution, which was a "worker thread". The problem here is that the request to the server is performed in AsyncTask where onPreExecute and onPostExecute have to be running from the Ui thread, so I really cannot do it this way either.
I would appreciate any suggestions what would be the best approach in this case.
Use a Handler.
Handler mHandler;
public void useHandler() {
mHandler = new Handler();
mHandler.postDelayed(mRunnable, 30000);
}
private Runnable mRunnable = new Runnable() {
#Override
public void run() {
Log.e("Handlers", "Call asynctask");
/** Call your AsyncTask here **/
mHandler.postDelayed(mRunnable, 30000);
}
};
I would like my code runs all the one minut..
Can anyone explain me how to do it?
private Handler myHandler;
private Runnable myRunnable = new Runnable() {
#Override
public void run() {
//DO WORK
Toast.makeText(getApplicationContext(), " Hello",Toast.LENGTH_SHORT).show();
myHandler.postDelayed(this,60000);
}
};
#Override
public void onCreate() {
super.onCreate();
//call function
myHandler = new Handler();
//
myHandler.postDelayed(myRunnable,60000);
Log.d(this.getClass().getName(), "onCreate");
}
watch this http://goo.gl/DRdaUi
BTW 60 second is a very long time for thread to run! If you have something that runs this long consider using android service instead of thread.
Also do you need to use handler? think again, most of the time there is no need for that. AsyncTask is android first option for multithreading and its a lot simpler. unless AsyncTask can not handle what you have in your mind don't use any other method.
A Timer is a valid solution but it will not execute on the UI thread. And your code tells me this is what you want.
The simplest way to do that would be via a handler and a repeating task:
final Handler handler = new Handler(); // ui thread handler
handler.postDelayed(new MyRunnable(handler), INETRVAL);
Where:
class MyRunnable implements Runnable {
#Override
public void run() {
// do periodical action here
// and.. repeat your task <------------
handler.postDelayed(new MyRunnable(handler), INETRVAL);
}
}
I have written a handler that calls the method every time interval. I want to remove that handler in on destroy(). The code i use as follows, In Oncreate()
private final Handler _handler = new Handler();
public int DATA_INTERVAL = 30 * 1000;
Runnable getData;
getData = new Runnable()
{
#Override
public void run()
{
recieveData();
}
};
_handler.postDelayed(getData, DATA_INTERVAL);
and in ondestroy(), i use,
_handler.removeCallbacks(getData);
But removecallbacks not work. It calls after exiting the activity.
removeCallbacks(Runnable r):
Remove any pending posts of Runnable r that are in the message queue.
so removeCallbacks(..) only stops pending messages (Runnables) not currently running runnable so if you want to stop currently running Runable then use a Boolean varaible for Stoping Thread when user Exit from your app.
see this post for removeCallbacks not stopping runnable
You are not showing the most important part of the code which is the receiveData method. As you said you are running the task periodically, you must be calling again postDelayed from inside that method to reschedule the task. Probably background threads involved as you cannot do networking on the main thread.
You most likely have a race condition when exiting the Activity. onDestroy runs first and then the task is posted again.
You should use
handler.removeCallbacksAndMessages(null);
Then all handler callbacks will removed.
I have one function which queries a network server with a few "ping pongs" back and forth, and have written a custom handler to handle the message communication between my main UI thread and the communication thread (I was using AsyncTask for this, but as the program got more complex, I have decided to remove the communication code to its own class outside of the main activity).
Triggering a single instance of this thread communication from onCreate works perfectly, no problem.
I want this query to run on a regular timed basis -- in the background -- for the entire time the app is in use, so I've set up another thread called pollTimer, which I'm trying to use to call the OTHER thread at a regularly scheduled basis.
Obviously, it's crashing, or I wouldn't be posting this.
Is there a way to get a thread within a thread? Or put differently, trigger a thread from another thread?
Timer pollTimer = new Timer();
private void startPollTimer(){
pollTimer.scheduleAtFixedRate(new TimerTask(){
public void run(){
Log.d(TAG,"timer dinged");
//if the following is commented out, this "dings" every 6 seconds.
//if its not commented out, it crashes
threadedPoll();
}
}, 3120, 6000);
}
private void threadedPoll() {
testThread(asciiQueries,WorkerThreadRunnable.typeLogin);
}
edit: it would probably help to include the "testThread" function, which works by itself when called from onCreate, but does not make it when called from the Timer.
"WorkerThreadRunnable" is the massive chunk of code in its own class that has replaced the mess of having AsyncTask handle it inside the main activity.
private Handler runStatHandler = null;
Thread workerThread = null;
private void testThread(String[] threadCommands, int commandType){
if(runStatHandler == null){
runStatHandler = new ReportStatusHandler(this);
if(commandType == WorkerThreadRunnable.typeLogin){
workerThread = new Thread(new WorkerThreadRunnable(runStatHandler,threadCommands, WorkerThreadRunnable.typeLogin));
}
workerThread.start();
return;
}
//thread is already there
if(workerThread.getState() != Thread.State.TERMINATED){
Log.d(TAG,"thread is new or alive, but not terminated");
}else{
Log.d(TAG, "thread is likely deaad, starting now");
//there's no way to resurrect a dead thread
workerThread = new Thread(new WorkerThreadRunnable(runStatHandler));
workerThread.start();
}
}
You seem to be well on the way already - the nice thing about handlers, though, is that they aren't limited to the UI thread - so if you have a Handler declared by one thread, you can set it up to take asynchronous instructions from another thread
mWorkerThread = new WorkerThread()
private class WorkerThread extends Thread {
private Handler mHandler;
#Override
public void run() {
mHandler = new Handler(); // we do this here to ensure that
// the handler runs on this thread
}
public void doStuff() {
mHandler.post(new Runnable() {
#Override
public void run() {
// do stuff asynchronously
}
}
}
}
Hopefully that helps... if I'm totally off base on your problem let me know
Wots wrong with a sleep() loop? Why do you have pagefuls of complex, dodgy code when you could just loop in one thread?
I have an app with a two threads - main and data loader. When data loader finishes it posts a Runnable object to the main thread (as described in the DevGuide), but it never gets delivered and run.
Here's the basic code:
class MyApp extends Application
{
public void onCreate()
{
LoaderThread t = new LoaderThread();
t.start();
}
private class LoaderThread extends Thread
{
public void run()
{
SystemClock.sleep(2000);
boolean res = m_handler.post(m_runnable);
if(res)
Log.d(TAG, "Posted Runnable");
}
}
private final Handler m_handler = new Handler();
private final Runnable m_runnable = new Runnable() {
public void run()
{
Log.d(TAG, "Hey, i'm runnable!");
}
}
}
Also it maybe important to note that I ran this code as a unit-test derived from an ApplicationTestCase:
class MyAppTest : public ApplicationTestCase
{
public MyAppTest()
{
super(MyApp.class);
}
public void testLoading()
{
createApplication();
// few asserts follow here...
}
}
So this fails. Runnable never gets run() called, although the log indicates that it has been posted successfully.
I also tried to send simple messages instead of posting runnable (m_handler.sendEmptyMessage(1) for example) - they never get delivered to handler's callback in the main thread.
What do I miss here?
Thanks in advance :)
A Handler requires a Looper in order to work. The Looper provides a message queue required by the Handler.
All instances of Activity have a Looper as one is used to process UI Events, but you can create your instance of Looper elsewhere.
Have a look in your Log output to see if Android is complaining about the absence of a Looper.
If it is, you might be able to fix by add the following to the top of your onCreate() method:
Looper.prepare();
m_handler = new Handler();
Looper.run();
And remove the initialisation of m_handler from later in your code.
Handler only works in an Activity AFAIK. You are attempting to use it in an Application.
An alternative to calling Looper.prepare() is to call new Handler(Looper.getMainLooper()). The problem with calling Looper.prepare() is that it will throw an exception when there is already a looper on your thread. Chances are you are writing code that has to run under different environments and this solution will handle more cases.
See:
AsyncTask and Looper.prepare() error