In the onHandleIntent of my my IntentService class, I created handle containing a runnable which should be done after 20 seconds. Unfortunatly my service sleeps or is destroyed before this period.
I tried also with the CountDownTimer, but i had the same problem.
Do someone have any idea can I make the onHnadleIntent waiting? Thank you!
This is the code:
public class MyService extends IntentService {
//...
#Override
protected void onHandleIntent(Intent workIntent) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
#Override
public void run() {
Log.i("20 seconds later","I am here");
}
}, 20000);
//...
}
//...
}
Don't use an IntentService. It is not designed for your scenario. Use a regular Service. Put your code in onStartCommand(). At the bottom of your run() method, call stopSelf() on the Service instance to shut it down.
You need to stop onHandleIntent from returning until the Runnable has completed. This can be achieved by using a CountdownLatch, which awaits at the end of your onHandleIntent method, and gets released at the end of the run method.
NOTE: this will cause the intent service to not process other Intents you sent it until the previous one has completed (after 20 seconds).
You may also want to obtain a partial wakelock at the start of onHandleIntent and release it at the end.
Related
What is the best way to implement an android Service (not IntentService) which polls a device using SNMP at regular intervals? I've tried implementing it with a Handler.postDelayed(Runnable) within onHandleIntent of IntentService. But later found it cannot be used in onHandleIntent() from this answer. My code just would not execute the runnable part.
make an IntentService not sleep until it executes a handler.postDelayed runnable
My code goes like:
public class MyPoller extends IntentService {
//Variable declarations
protected Handler handler;
public MyPoller() {
super("My service");
}
#Override
protected void onHandleIntent(Intent intent) {
.......
.......
runable = new Runnable() {
public void run() {
//My code here
handler.postDelayed(this, poll_interval);
}
};
handler.postDelayed(runable,poll_interval);
}
}
So I thought I could implement the same in a service, but I don't know how to implement this recurring task in a service also running it in a new thread. I found few answers demonstrating different ways of running recurring tasks in a new thread in a Service, but I'm confused.
Can someone suggest some way of implementing the same in a Service? It would be of great help. Thanks in advance.
i have an IntentService that should act like a manager and create Tasks in a queue (Runnable) that are submitted to a ThreadPool.
Im a little bit confused of the lifecycle of an IntentService:
The method protected abstract void onHandleIntent (Intent intent) runs already on a separated Thread. In the onHandleIntent I would create a new Runnable instance and submit it to the ThreadPool. My Service looks like this:
public class SyncService extends IntentService {
private final ThreadPoolExecutor threadPool;
public SyncService() {
super("SyncService");
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
threadPool = new ThreadPoolExecutor(1, 1, 20, TimeUnit.SECONDS, queue);
}
#Override
public void onCreate() {
super.onCreate();
EventBus.getInstance().register(this);
}
#Override
public void onDestroy() {
super.onDestroy();
EventBus.getInstance().unregister(this);
}
#Override
protected void onHandleIntent(Intent intent) {
if (intent.getAction().equals("sync")){
threadPool.submit(new SyncRunnable());
}else
if(intent.getAction().equals("delete")){
threadPool.submit(new DeleteRunnable());
} else
if(intent.getAction().equals("register")){
threadPool.submit(new RegisterRunnable())
}
}
}
My questions:
Is it a good idea to use a ThreadPool in a IntentService?
If I use a ThreadPool, than the IntentService will be destroyed if the Threadpool has no more Runnables to execute or queued, right?
Is IntentService already something that I want to achieve and should I simply execute my (long running) Runnable code in the
onHandleIntent() because this method alread runs on the
IntentService worker Thread? If yes, is there a queue limit for
intent, since onHandleIntent() could run up to 30 seconds before
finishing and handling the next Intent.
Is it a good idea to use a ThreadPool in a IntentService?
Not really. IntentService is already a single threaded (serial) variant of what you try to achieve. I would derive directly from Service.
If I use a ThreadPool, than the IntentService will be destroyed if the Threadpool has no more Runnables to execute or queued, right?
No. IntentService can go into the destroyed state once you return from onHandleIntent - i.e. immediately because threadPool.submit is non-blocking. Within the source it calls stopSelf(int) with the startId it got when the service was started.
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
#Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
A Service will go into destroyed state if you call stopSelf with the latest (highest) startId. It will keep running if a newer start is in the queue.
If the service goes into destroyed state it will not kill your thread pool because it has no knowledge about it. The problem is that Android now thinks that your service is dead and it will no longer count as a reason to keep your app process. The service running vs destroyed state is essentially just a way to tell Android that there is something going on and you don't want to get destroyed.
If you want to do it the right way you have to keep the service state in sync with what is actually going on.
Is IntentService already something that I want to achieve and should I simply execute my (long running) Runnable code in the onHandleIntent() because this method alread runs on the IntentService worker Thread?
If you are happy with single threaded serial execution yes. That's what onHandleIntent does for you.
If yes, is there a queue limit for intent, since onHandleIntent() could run up to 30 seconds before finishing and handling the next Intent.
There is no limit (it's a linked list as far as I can tell). But there is also nothing that stops you from producing more tasks than it can handle which will ultimately lead to some kind of overflow.
My APP has to start some time consuming job when receiving ACTION_SCREEN_OFF, and interrupt the job when receiving ACTION_SCREEN_ON if job is still going on.
public class TimeConsumingWorkIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
TimeConsumingWork();
}
}
public class ScreenStatusReceiver extends BroadcastReceiver {
Intent intent = new Intent(mContext, TimeConsumingWorkIntentService.class);
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
mContext.startService(intent );
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
mContext.stopService(intent );
}
}
}
By print log of time, I find time consuming work is still going on stop the TimeConsumingWorkIntentService (when receiving ACTION_SCREEN_ON).
why ?
Use
// Cancel the runnable
myHandler.removeCallbacks(yourRunnable);
Ok , then you can do something like this
Runnable r = new Runnable{
public void run(){
if(booleanCancelMember != false){
// within this you make the call to handler and work
// Since you block the call the handler wont get repeated
}
}
}
You can't do this like that. When you start your IntentService, it will call onHandleIntent() on a separate worker thread. That mehod then calls TimeConsumingWork(). Stopping the service will not interrupt the execution of the worker thread. It just tells the worker thread that when it has finished processing the current Intent, it should stop.
What you will need to do is to have your TimeConsumingWork() method periodically look to see if it should stop. You can do this by setting a static boolean variable and have TimeConsumingWork() periodically check this variable and quit if it is set.
You don't need to call stopService() on an IntentService as it will stop itself when it has nothing to do.
i have created one intent service. Now I want to stop that service from activity how to stop that service? My code is:
MyActivity.java
#Override
public void onCreate(Bundle savedInstanceState) {
Intent intent = new Intent(this, myService.class);
intent.putExtra("myHand", new Messenger(this.myHand));
startService(intent);
}
myService.java
public class myService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
String signal = intent.getAction();
if (signal != null && signal.equals("stop")) {
stopSelf();
} else {
t.schedule(new TimerTask() {System.out.println("print")}, 0, 10000);
}
}
}
to stop service on click of button
Intent in = new Intent(this, myService.class);
in.setAction("stop");
stopService(in);
can anybody help me to stop service?
From the docs for IntentService
IntentService is a base class for Services that handle asynchronous requests (expressed as Intents) on demand. Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
In other words, you don't have to stop an IntentService - it will terminate itself when it has no more work to do.
EDIT:
Looking back at your code, it seems you don't wan't to stop the IntentService you want to stop the TimerTask???
t.schedule(new TimerTask() {System.out.println("print")}, 0, 10000);
I don't know what t is but I'm guessing it's a Timer. If that's the case it will be running with its own Thread and attempting to terminate the IntentService is pointless - kill the Timer instead.
Also, why are you using an IntentService to create any type of object which maintains its own thread of execution?
Now I want to stop that service from activity how to stop that
service?
IntentService stops itself, you shouldn't, you can't call stopSelf().
When all requests have been handled, the IntentService stops itself.
From what I know, IntentHandler creates a separate new thread, does its work, and kills itself.
So I don't think you need to explicitly stop it from an activity.
Ok this got me really mad. Is there a restriction for services with countdowns?
I tried so many methods to make a countdown timer work in a service,but it always fails. It just never gets to the finish() part!
So is there a restriction with services and countdowns or what? Please help me...
Here is the service:
public class ss extends IntentService {
public ss() {
super("ss");
}
#Override
protected void onHandleIntent(Intent intent) {
new CountdownTimer(30000, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
executemymethod(); //it never gets here!
}
}.start();
}
}
As you can see the code is simple and correct,but still the executemymethod(); never really executes! There are no errors... Please give me a solution!
If you want to do this kind of thing you should be using a regular Service and not an IntentService. Here's what the docs say about IntentService:
Clients send requests through startService(Intent) calls; the service is started as needed, handles each Intent in turn using a worker thread, and stops itself when it runs out of work.
Since the countdown is asynchronous, the work is complete after you start the countdown timer. The IntentService then finishes immediately, and probably shuts down the thread.