How to stop a service after it has finished its job? - android

I have a service which I start from my Activity.
Now the serivce performs some task by starting a new thread from onStartCommand()
I want to stop the service after the thread has finished its job.
I tried using a Handler like this
public class MainService extends Service{
private Timer myTimer;
private MyHandler mHandler;
#Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mHandler = new MyHandler();
myTimer = new Timer();
myTimer.schedule(new MyTask(), 120000);
return 0;
}
private class MyTask extends TimerTask{
#Override
public void run() {
Intent intent = new Intent(MainService.this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
mHandler.sendEmptyMessage(0);
}
}
private static class MyHandler extends Handler{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("", "INSIDE handleMEssage");
//stopSelf();
}
}
First it was giving me a warning that if handler class is not static it will cause leaks
After I made it static, stopSelf() can not be called, because its non static.
Is my approach correct or is there a simpler way around ?

you should use IntentService rather service. It starts automatically in separate thread and stop itself as task completes.
public class MyService extends IntentService {
public MyService(String name) {
super("");
}
#Override
protected void onHandleIntent(Intent arg0) {
// write your task here no need to create separate thread. And no need to stop.
}
}

Use IntentService its 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.

try this,
private static class MyHandler extends Handler{
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Log.e("", "INSIDE handleMEssage");
MainService.this.stopSelf();;
}
}

Related

Run a service in background continuously

Run a service in background continuously. For example, a service has to be kicked off which will display a toast message 20 seconds once even if the app is closed.
public class AppService extends IntentService {
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;
}
public AppService() {
super("AppService");
}
#Override
protected void onHandleIntent(Intent workIntent) {
Toast.makeText(getApplicationContext(), "hai", Toast.LENGTH_SHORT).show();
SystemClock.sleep(20000);
}
}
Below code works for me...
public class AppService extends Service {
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
Toast.makeText(this, " MyService Created ", Toast.LENGTH_LONG).show();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, " MyService Started", Toast.LENGTH_LONG).show();
return START_STICKY;
}
}
Accepted answer will not work on from Android 8.0 (API level 26), see the android's background limitations here
Modification in Accepted Answer:
1: You have to invoke the service's startForeground() method within 5 seconds after starting the service. To do this, you can call startForeground() in onCreate() method of service.
public class AppService extends Service {
....
#Override
public void onCreate() {
startForeground(9999, Notification())
}
....
}
2: You must call startForegroundService() instead of startService() by checking API level from where you want to start the service.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
context.startService(intent);
}
This code work for me..
public class ServiceClass extends Service {
public static final int notify = 300000; //interval between two services(Here Service run every 5 Minute)
private Handler mHandler = new Handler(); //run on another Thread to avoid crash
private Timer mTimer = null; //timer handling
#Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
#Override
public void onCreate() {
if (mTimer != null) // Cancel if already existed
mTimer.cancel();
else
mTimer = new Timer(); //recreate new
mTimer.scheduleAtFixedRate(new TimeDisplay(), 0, notify); //Schedule task
}
#Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel(); //For Cancel Timer
Log.d("service is ","Destroyed");
}
//class TimeDisplay for handling task
class TimeDisplay extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
Log.d("service is ","running");
}
});
}
}
}
In your manifest, where you declare your service, add:
android:process=":processname"
This lets the service run on a separate process and thus it will not be killed with the app.
You can then chose if you want to use foreground. It will show a persistent notification, but reduces the likelihood if the service being killed.
Further, if you want to create a continuously running service, use Service, NOT IntentService. IntentService stops when it is finished doing its action.

IntentService does not start

My IntentService looks like this:
public class MusicService extends IntentService{
final static String NAME = "MusicService";
//------------------------------------------------------------------------------
public MusicService(String name) {
super(NAME);
}
//------------------------------------------------------------------------------
public MusicService() {
super(NAME);
}
//------------------------------------------------------------------------------
#Override
protected void onHandleIntent(Intent intent) {
// Toast never comes up
Toast.makeText(getApplicationContext(), NAME, Toast.LENGTH_SHORT).show();
PodcastrApplication.newInstance().getMediaPlayer().start();
}
//------------------------------------------------------------------------------
}
I have a MediaPlayer that I keep in my Application to reduce object instantiations. The idea is that once the app goes out of focus, the media player will play. However, the service is never fired.
Here is how I am calling the service from the onStop() of my Fragment
showMediaPlayerNotification();
Intent music = new Intent(getActivity(), MusicService.class);
getActivity().startService(music);
I have it declared in the manifest also. There is no error in logcat, either.
What is going on?
Update 1:
Once you call startService(), the IntentService does the work defined
in its onHandleIntent() method, and then stops itself.
Is it that the service is stopping itself because it is just one line of execution?
Should I move the media player to a thread?
Update 2:
<service
android:name=".service.MusicService"
android:enabled="true"
android:exported="false" />
You've called Toast.makeText() in a background thread!, Any UI stuff must be done in UI thread.
Note that: IntentService uses a background thread but Service uses UI thread
You can try:
public class MusicService extends IntentService{
Handler mHandler;
final static String NAME = "MusicService";
//------------------------------------------------------------------------------
public MusicService(String name) {
super(NAME);
mHandler = new Handler();
}
//------------------------------------------------------------------------------
public MusicService() {
super(NAME);
mHandler = new Handler();
}
//------------------------------------------------------------------------------
#Override
protected void onHandleIntent(Intent intent) {
mHandler.post(new Runnable{
#Override
public void run(){
Toast.makeText(getApplicationContext(), NAME, Toast.LENGTH_SHORT).show();
}
});
// Toast never comes up
PodcastrApplication.newInstance().getMediaPlayer().start();
}
//------------------------------------------------------------------------------
}

Service and activity communication, method update in all activities

In first Activity I've started this service:
public class TaskMsg extends Service
{
private static Timer timer;
private Context ctx;
public IBinder onBind(Intent arg0)
{
return null;
}
public void onCreate()
{
super.onCreate();
timer = new Timer();
ctx = this;
startService();
}
private void startService()
{
timer.scheduleAtFixedRate(new mainTask(), 0, 35000);
}
private class mainTask extends TimerTask
{
public void run()
{
toastHandler.sendEmptyMessage(0);
}
}
public void onDestroy()
{
timer.cancel();
super.onDestroy();
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
// for example, 2*3;
}
}
}
In handleMessage method where I have a few operation. It's working fine.
But I have problem, because I would like to call to activity (from this Service) that in service has new result operation. In all Activity in my project, I have method Update. I need only information that Handler in Service returned new information to all Activity or current Activity.
May be you can use a custom broadcast receiver. From the service you can broadcast the message and can write a receiver in your activity. In onReceive() in your activity, you can call to your update() method.
Hope you understand what I mean
Thank You! Is it good solution for few activities?
Intent intent = new Intent(Activity1.UPDATE);
sendBroadcast(intent);
intent = new Intent(Activity2.UPDATE);
sendBroadcast(intent);
intent = new Intent(Activity3.UPDATE);
sendBroadcast(intent);

Only one instance of Thread in service

I initialize new Thread in service but when i start service the new one is made and it make my app crash beacause I use camera in it.
How to make that it will be ony one instance of that Thread?
When Thread is closing? If I close service where I made it, it will be also closed?
you could use a lock or a static variable:
private static boolean isThreadRunning;
and then in your service:
if(isThreadRunning)
return;
Thread t=new Thread(new Runnable(){
protected void run(){
isThreadRunning=true;
while(yourcondition){
//your thread code...
}
isThreadRunning=false;
//if you want to start another thread after this one is ended, you should post a message to a handler here and it should start another thread like this
}
});
You can also achieve this using Handler class, which is recommended by Google in thread operations. The code bellow shows generic example how to use it in Service.
public class MyService extends Service{
private final Handler handler = new Handler();
private final static int RUNABLE_WHAT=6558057;
private final static int PEROID=6*1000;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if(!handler.hasMessages(RUNABLE_WHAT))
{
handler.sendMessageDelayed(new Worker().extractMessage(), PEROID);
}
return START_STICKY;
}
private class Worker implements Runnable{
#Override
public void run() {
//DO WORK HERE
handler.sendMessageDelayed(new Worker().extractMessage(), PEROID);
}
private Message extractMessage()
{
Message message = Message.obtain(handler, this);
message.what=RUNABLE_WHAT;
return message;
}
}
}

Android - how to run a task via "handler" periodically within a service-intent (worker-thread)

My question is Android related:
How do I run a task every 20 seconds within an intentservice ?
Problem is, I have to init some classes which will be used in the Handler "run" process.
It works one time - but then the service stops & the application crashes when the handler-loop starts again after 20 seconds (probably because of the classes that got eliminated when the service stopped?). So maybe the solution is to get the service to stay running as long as the Handler runs or to throw away the code and do it right ?
Hope, someone can help me.
public class Fadenzieher extends IntentService{
private Handler handler = new Handler();
private Runnable timedTask = new Runnable(){
#Override
public void run() {
// My functions get called here...
// class1member.getDBWorkdone();
handler.postDelayed(timedTask, 20000);
handler.obtainMessage();
}};
public Fadenzieher() {
super("Fadenzieher");
}
#Override
protected void onHandleIntent(Intent intent) {
// SOME INITIALISING
// I have to init some vars & functions here that
// will also be used inside the handler loop
// Class1 class1member = new Class1();
// class1member.startUpDB();
handler.post(timedTask); }
Thank you very much in advance!!!
---- So this is the updated code now (14. nov. 2011)
public class Fadenzieher extends Service{
private static final long UPDATE_INTERVAL = 60000;
Context context = this;
private Timer timer = new Timer();
DbHelper dbHelper;
public void onCreate(){
dbHelper = new DbHelper(context);
runTheLoop();
}
protected void runTheLoop() {
timer.scheduleAtFixedRate(new TimerTask(){
#Override
public void run() {
dbHelper.dosomethings();
Toast.makeText(context, "CALL", Toast.LENGTH_LONG).show();
}}, 0, UPDATE_INTERVAL);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "Starte Service“, Toast.LENGTH_SHORT).show();
return super.onStartCommand(intent,flags,startId);
}
public void onDestroy() {
super.onDestroy();
dbHelper.close();
Toast.makeText(this, "Stoppe Service“, Toast.LENGTH_LONG).show();
}
// We return the binder class upon a call of bindService
#Override
public IBinder onBind(Intent arg0) {
return mBinder;
}
public class MyBinder extends Binder {
Fadenzieher getService() {
return Fadenzieher.this;
}
}
}
The whole application crashes immediately.
How do I run a task every 20 seconds within an intentservice ?
That is not an appropriate use of IntentService. Use a regular Service, please.
It works one time - but then the service stops & the application crashes when the handler-loop starts again after 20 seconds
IntentService shuts down when onHandleIntent() returns, which is why this is breaking for you. Use a regular Service, please.
Also:
Please allow the user to configure the polling period
Make sure that this service will shut down when the user no longer wants it to be running

Categories

Resources