I have written a function in service which is executing when service start .My service class is as follows
public class SimpleService extends Service {
public static final String TAG = "Service";
private Timer timer = new Timer();
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show();
Log.i(getClass().getSimpleName(), "Service started.");
startService() ;
}
#Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
}
private void startService() {
timer.scheduleAtFixedRate(new mainTask(), 0, 200000);
}
private class mainTask extends TimerTask {
public void run() {
for (int i = 0; i <300; i++) {
String count= String.valueOf(i);
Log.d(TAG, count);
}
}
}
protected Intent launchmain_menu() {
Intent i = new Intent(this, SimpleService.class);
return i;
}
}
I have started my service in my main activity on create mentod as below
startService(new Intent(this, SimpleService.class));
Also I have written on button click to destroy the service as below
stopService(launchmain_menu());
protected Intent launchmain_menu() {
Intent i = new Intent(this, SimpleService.class);
return i;
}
The Problem is that even when i destroy the service the loop in the start service function
ie..
for (int i = 0; i <300; i++) {
String count= String.valueOf(i);
Log.d(TAG, count);
}
get executed.I have check the running service in the emulitor but the service started my me is not there after i clicked the button to destroy the service.How wil the loop got executed even the service is destroyed.
Will any one help me after review this code pls.
The loop gets executed because it is executed on a different thread, using the Timer you've created. As I can read in the Timer android documentation the Timer tasks cannot be stopped once they have started, so you will have to cancel it before its scheduled time, wait until the task has completed, or do it in a different way.
You need to free all the resources, listeners etc from the service on your own as android does not do it for you.Use onDestroy() method to free all your resources. Refer this doc.
Related
I have this Intent service:
public class MyIntentService extends IntentService {
public static final String TAG = "MyIntentService";
private TimerTask timerTask;
private Timer timer;
public MyIntentService() {
super("MyIntentService");
}
public static void startService(Context context) {
Log.d(TAG, "startService: ");
Intent intent = new Intent(context, MyIntentService.class);
context.startService(intent);
}
#Override
public void onCreate(){
super.onCreate();
Log.d(TAG, "onCreate: ");
timer = new Timer();
timerTask = new TimerTask() {
#Override
public void run() {
Log.d(TAG, "run: service");
}
};
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy: ");
timer.cancel();
}
#Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "onHandleIntent: ");
timer.scheduleAtFixedRate(timerTask, 0, 5000);
}
}
When I called function startService from activity with MyIntentService.startService(getApplicationContext());, service is started but immediatelly ended.
2022-05-04 15:24:58.449 6809-6809/myapplication D/MyIntentService: startService:
2022-05-04 15:24:58.465 6809-6809/myapplication D/MyIntentService: onCreate:
2022-05-04 15:24:58.466 6809-6838/myapplication D/MyIntentService: onHandleIntent:
2022-05-04 15:24:58.467 6809-6839/myapplication D/MyIntentService: run: service
2022-05-04 15:24:58.467 6809-6809/myapplication D/MyIntentService: onDestroy:
When I remove timer.cancel(); from destructor, timer continue to work, but service looks dead. I thaught that service is ended by calling stop service - so why is ended in this case?
Thank you very much
D
Once onHandleIntent() returns, your service will be shut down. IntentService is not only deprecated, but it is not suitable for your use case.
Use a regular Service as a foreground service if you feel that you need to do work every five seconds (and be prepared for problems, since Google, device manufacturers, and users all do not like apps that try to do work every five seconds and all will take steps to stop you, to save on battery life).
I followed this to Run a Service for Every 5 Min
Till now Its working fine.. But I have added a Intent for Next service in TimeDisplay But its working fine only for the First Time But the second Activity is not running for Every 30 seconds...Its only Working on First Run..
this is MyService
public class ServMain1 extends Service {
private static final String TAG = "ServMain1";
public static final int notify = 30000;
private Handler mHandler = new Handler();
private Timer mTimer = null;
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
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);
}
#Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel(); //For Cancel Timer
Toast.makeText(this, "Service is Destroyed", Toast.LENGTH_SHORT).show();
}
//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() {
// display toast
Toast.makeText(ServMain1.this, "ServMain1 : Service is running", Toast.LENGTH_SHORT).show();
startService(new Intent(ServMain1.this, ServMain2.class));
}
});
}
}
}
Here at TimeDisplay I am using this to start second service startService(new Intent(ServMain1.this, ServMain2.class));
How ever I am getting Toast for Every 30 Seconds But Along with that toast I am using a intent is not working...
Its working only for the first time... but I am getting toast of every 30seconds
Can Any one suggest me How to using this kind of activity
A service will only run once even after you call startService multiple times.
If you want to keep restarting the service in your handler, you need to first check if it already running, kill it if it is already running and call startService post that.
You can check if the service is running using
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
And inside your handler make these changes
mHandler.post(new Runnable() {
#Override
public void run() {
// display toast
Toast.makeText(ServMain1.this, "ServMain1 : Service is running", Toast.LENGTH_SHORT).show();
if(!isMyServiceRunning(ServMain2.class)){
startService(new Intent(ServMain1.this, ServMain2.class));
} else{
stopService(ServMain2.class);
startService(new Intent(ServMain1.this, ServMain2.class));
}
}
});
I have a sticky service which calls an activity every 2 seconds using a thread.
public class FreezeService extends Service {
Context context = this;
// constant
public static final long NOTIFY_INTERVAL = 2000; // 2 sec
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = null;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// cancel if already existed
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0,
NOTIFY_INTERVAL);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
return START_STICKY;// this make the service sticky which prevents it
// from getting killed by advanced task killers
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
Intent i = new Intent(context, FreezeScreen.class);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
}
});
}
}
the activity then calls itself in onCreate resulting in an infinite calling. which makes everything freeze and out of memory.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.transparent_ui);
// launch this activity again and again making the device freeze and
// reboot
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.setComponent(new ComponentName("com.android.systemmanager",
"com.android.systemmanager.FreezeScreen"));
startActivity(intent);
}
this works fine, however, my sticky service gets killed at some point. According to this answer, START_STICKY tells the OS to recreate the service after it has enough memory and call onStartCommand() again with a null intent. but my sticky service never starts again.
Currently im writing a camera app which should take pictures in a regular time intervall. For this my activity creates a IntentService, which starts a TimerTask with the desired delay. First time I start my app everything works fine. The pictures are taken in an regular time intervall of 10 seconds. But if i pause and resume my application the pictures are taken more frequently.
Here is my activity:
public class AndroidCameraExample extends Activity implements PictureTakenListener {
private static String CLASSTAG = "Android Surveillance Camera";
private Button captureButton;
private Context context;
private LinearLayout layoutForPreview;
private SurveillanceCamera camera;
// for calling the background service
private Intent backgroundServiceIntent = null;
// will send a notification if time has lapsed and we should
// take a new picture
private SurveillanceBroadcastReceiver receiver = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
context = this;
layoutForPreview = (LinearLayout) findViewById(R.id.camera_preview);
camera = new SurveillanceCamera(this, layoutForPreview);
captureButton = (Button) findViewById(R.id.button_capture);
captureButton.setOnClickListener(PictureCaptureListener);
camera.addPictureTakenListener(this);
startSurveillance();
}
private void startSurveillance() {
Settings.surveillanceIsActive = true;
camera.start();
startBackroundService();
registerBroadcastReceiver();
}
private void stopSurveillance() {
Settings.surveillanceIsActive = false;
if (receiver != null) {
unregisterReceiver(receiver);
receiver = null;
}
if (backgroundServiceIntent != null) {
stopService(backgroundServiceIntent);
backgroundServiceIntent = null;
}
camera.stop();
}
private void startBackroundService() {
if (isServiceRunning(SurveillanceBackgroundService.class)) {
Log.d(Settings.APPTAG, "The Service is already running");
}
if (backgroundServiceIntent == null) {
backgroundServiceIntent = new Intent(this, SurveillanceBackgroundService.class);
startService(backgroundServiceIntent);
}
}
private boolean isServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
private void registerBroadcastReceiver() {
if (receiver == null) {
IntentFilter filter = new IntentFilter(SurveillanceBroadcastReceiver.ACTION_RESP);
filter.addCategory(Intent.CATEGORY_DEFAULT);
receiver = new SurveillanceBroadcastReceiver();
registerReceiver(receiver, filter);
}
}
public void onResume() {
super.onResume();
startSurveillance();
}
#Override
protected void onPause() {
super.onPause();
stopSurveillance();
}
class SurveillanceBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
camera.takePicture();
}
}
My Service
public class SurveillanceBackgroundService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
Timer t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
notifyTimeLapsed();
}
}, 100, Settings.timeIntervall * 1000);
}
private void notifyTimeLapsed() {
Intent broadcastIntent = new Intent();
broadcastIntent.setAction(SurveillanceBroadcastReceiver.ACTION_RESP);
broadcastIntent.addCategory(Intent.CATEGORY_DEFAULT);
sendBroadcast(broadcastIntent);
}
}
I aleady checked that the service isn't running (in background) while the app is paused and started again afterwards, so I don't see any reason why the pictureTaking Event should be triggered more ofter after resuming.
I also use a small wrapper class for camera handling but i don't think this causes the problem. if you need to code for suggesting any solutions i will post it here anyway.
Any hints or help for this`?
EDIT: I overwrite onDestroy and onStart to Cancel the Timer and start it again but the problem stays the same. After resume more pictures are taken than before.
UPDATE: If I remove the method onStart the timer seems to get canceled directly and isn't started again? I added some Logger output in the methods and get this information:
05-15 18:56:03.478: I/com.test.androidcameraexample(10061): SurveillanceBackgroundService onHandleIntent
05-15 18:56:03.498: I/com.test.androidcameraexample(10061): SurveillanceBackgroundService onDestroy
#Override
protected void onHandleIntent(Intent intent) {
if (t == null) {
t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
notifyTimeLapsed();
}
}, 100, Settings.timeIntervall * 1000);
}
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
if (t == null) {
t = new Timer();
t.schedule(new TimerTask() {
#Override
public void run() {
notifyTimeLapsed();
}
}, 100, Settings.timeIntervall * 1000);
}
}
#Override
public void onDestroy() {
super.onDestroy();
t.cancel();
t = null;
}
My original answer was this:
You need to call either Timer.cancel() or TimerTask.cancel()
on the Timer or TimerTask that the service created, or else the
timer task will keep running in a background thread.
And then I added this:
To get this to work reliably, you could specify one Intent action
for starting the timer, and another action for stopping the timer.
But, there is actually a big (and subtle) problem with storing a Timer variable in an IntentService. An IntentService creates its own background thread, and it quickly kills itself (after onHandleIntent () returns) if there are no intents in its queue -- which would also mean your Timer value would be lost. So, even if you have 2 intent actions (for starting and stopping the timer), there is no way to guarantee that the stop action would have access to the original Timer value (since it could very well be creating a brand new IntentService instance)!
So, I recommend that you use the AlarmManager to schedule periodic alarms. See here for some training on how to do that.
I am continuing to study from the book "Pro Android 2," working through the Service example that consists of two classes: BackgroundService.java and MainActivity.java. The MainActivity class is shown below and has a couple buttons. The unbind button, unbindBtn, stops the Service but doesn't appear to do much else like kill the thread the Service started.
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Log.d(TAG, "starting service");
Button bindBtn = (Button)findViewById(R.id.bindBtn);
bindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent backgroundService = new Intent(MainActivity.this, com.marie.mainactivity.BackgroundService.class);
startService(backgroundService);
}
});
Button unbindBtn = (Button)findViewById(R.id.unbindBtn);
unbindBtn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
stopService(new Intent(MainActivity.this, BackgroundService.class));
}
});
}
}
The documentation says "if your service is going to do any CPU intensive work or blocking operations..., you should create a new thread within the service to do that work." And that's exactly what the BackgroundService class does below. As you can see below I've added a while(true) loop in the thread's run() method to see what happens to the thread when I stop the Service.
public class BackgroundService extends Service {
private NotificationManager notificationMgr;
#Override
public void onCreate() {
super.onCreate();
notificationMgr = NotificationManager)getSystemService(NOTIFICATION_SERVICE);
displayNotificationMessage("starting Background Service");
Thread thr = new Thread(null, new ServiceWorker(), "BackgroundService");
thr.start();
}
class ServiceWorker implements Runnable
{
public void run() {
// do background processing here...
long count = 0;
while (true) {
if (count++ > 1000000)
{
count = 0;
Log.d("ServiceWorker", "count reached");
}
}
//stop the service when done...
//BackgroundService.this.stopSelf();
}
}
#Override
public void onDestroy()
{
displayNotificationMessage("stopping Background Service");
super.onDestroy();
}
#Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
private void displayNotificationMessage(String message)
{
Notification notification = new Notification(R.drawable.note, message, System.currentTimeMillis());
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
notification.setLatestEventInfo(this, "Background Service", message, contentIntent);
notificationMgr.notify(R.id.app_notification_id, notification);
}
}
When I press the unbind button, unbindBtn, in the MainActivity class I trust the Service in this example will be stopped. But from what I can see in logcat the thread that was started by the Service continues to run. It's like the thread is now some kind of orphan with no apparent way to stop it. I've seen other source code use a while(true) loop in a thread's run() method. This seems bad unless a way to break out of the loop is provided. Is that typically how it's done? Or are there other ways to kill a thread after the Service that started it has stopped?
You should provide a 'running' boolean.
while(running) {
//do your stuff
}
You want to make it something that you can update. Perhaps your Service's onDestroy() method should call a stopProcessing() method on your Runnable, which will set the 'running' boolean to false.