I´m trying to have a service that executes some code in a Handler at every second. While the phone is connected to the PC everythings running fine. However as soon as I start the service while not connected to the PC and I lock the phone, the periodic task just stops executing and executes all posted events when the app is opened again.
I´ve tried adding a PARTIAL_WAKE_LOCK in the onCreate of the Service but it doesn´t help at all.
Service.java
private PowerManager.Wakelock mWakeLock;
private Handler mHandler;
private Timer mTimer;
#Override
public void onCreate() {
super.onCreate();
Notification notification = createNotification();
startForeground(1, notification);
// create and acquire the WakeLock
PowerManager pm = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "APP:LockName");
mWakeLock.acquire();
// create Handler for periodic code execution
HandlerThread thread = new HandlerThread("PeriodicThread", THREAD_PRIORITY_BACKGROUND);
thread.start();
Looper looper = thread.getLooper();
mHandler = new Handler(looper);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mTimer = new Timer();
mTimer.scheduleAtFixedRate(new PeriodicTask(), 0, 1000);
return START_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mTimer.cancel();
mWakeLock.release();
}
private class PeriodicTask extends TimerTask {
#Override
public void run() {
mHandler.post(() -> { // periodic task here});
}
}
I would expect the service to execute normally when the screen is locked, since the whole execution is protected by the PARTIAL_WAKE_LOCK.
Or are WakeLocks Thread-specific and I need to acquire a lock for the newly created Thread?
Many Thanks for your help
Edit 1:
I´ve tried adding the permission REQUEST_IGNORE_BATTERY_OPTIMIZATIONS to the app and even then the behavior is phone dependent. On a Samsung phone it works now as intended and the task is executed each second. on Huawei phone there´s no change and the periodic task is only executed when the app is opened again.
Is there a way to at least secure the same behaviour on different phones?
Related
I want to close a background thread in my service in the onDestroy method, because if I stop my service the background thread is still running. Because thread.stop() is deprecated, I don't really know how to do it.
#Override
public int onStartCommand(Intent intent, int flags, int startId)
{
runAsForeground();
Runnable service = new Runnable() {
#Override
public void run() {
connect(client,options);
}
};
backgroundThread = new Thread(service);
backgroundThread.start();
Log.i(TAG, "onStartCommand methode called");
return Service.START_NOT_STICKY;
}
Thread life cycle is not the same as Android Context Component life cycle. Stopping the service is not enough to stop the thread which service created. Thread.interrupt() is a option. - You should catch InterruptedException though. If it is not enough, you can check if service is not stopped inside your connect() method.
I suppose you're using a Service. Then you can Context.stopService(intent) just the same way you Context.startService(intent).
You can use
stopService(new Intent(this, YourService.class));
It will stop this service and all its Threads.
I'm writing an app which should collect some sensor data every 10 seconds or so and write them to disk.
So far, I have an Activity which starts a service. The service has a runnable, which uses a handler to run my task periodically via handler.postDelayed(). See below for the (shortened) code.
So far, this works fine as long as the device is active. As soon as the device goes into idle, it doesn't run my task until it wakes up again.
So, my question is how to run my task ALWAYS.
With setExactAndAllowWhileIdle(), the AlarmManager seems to offer exactly what I need, but...
To reduce abuse, there are restrictions on how frequently these alarms will go off for a particular application. Under normal system operation, it will not dispatch these alarms more than about every minute (at which point every such pending alarm is dispatched); when in low-power idle modes this duration may be significantly longer, such as 15 minutes.
Battery life has just a minor priority, though not being awake the entire time would be fine. (Not sure if android can be awake for just a second or so)
MyActivity
...
public void onStartService(View view) {
Intent i= new Intent(getBaseContext(), MyAppService.class);
getBaseContext().startService(i);
}
public void onStopService(View view) {
stopService(new Intent(getBaseContext(), MyAppService.class));
}
....
MyService
public class MyAppService extends Service {
MyRunnable mr;
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
mr= new MyRunnable(getApplicationContext() );
mr.Start();
return Service.START_NOT_STICKY;
}
#Override
public void onDestroy() {
super.onDestroy();
mr.Stop();
}
#Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
}
MyRunnable
public class MyRunnable implements Runnable{
// context is needed for sensorListener (?)
private Context myContext;
private Handler handler;
public MyRunnable(Context c){
myContext=c;
handler= new Handler();
}
public void Start(){
run();
}
public void Stop(){
handler.removeCallbacks(this);
// some clean-up
}
#Override
public void run() {
//acquire and write to file some sensor data
handler.postDelayed(this, 10000);
}
}
i think what you are looking for is STICKY SERVICE.
Officail Docs: If the system kills the service after onStartCommand() returns, recreate the service and call onStartCommand(), but do not redeliver the last intent. Instead, the system calls onStartCommand() with a null intent, unless there were pending intents to start the service, in which case, those intents are delivered. This is suitable for media players (or similar services) that are not executing commands, but running indefinitely and waiting for a job.
you just need to pass a flag at the time of calling the service.
When Android Wear goes to sleep mode (screen dimmed), some parts of my code are not executed. I use Timer in background service to trigger some actions, such as sending data from wear to mobile, but the data is not sent. It is sent when I tap the screen to wake it up.
I also try to use Timer trigger a notification with vibration when the screen is off, but it doesn't appear until I tap the screen.
In debug mode (either Bluetooth or USB), data sending and notification work fine.
I suspect this is because when Android Wear is in sleep mode, its CPU works at minimum level because the Timer is still running, but not for GoogleApiClient, IntentService, or Notification.
I have tried many ways to wake CPU up such as AlarmManager, PowerManager, Wakelock, but it did not work for Android Wear.
Anyone has encountered this problem? What is the solution?
I'm using PowerManger to wakeup my wearable device each time i receive message from handled device.
Do not forget to release PowerManager.WakeLock
public abstract class WatchFaceActivity extends Activity {
private PowerManager.WakeLock mWakeLock;
private Handler mWakeLockHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_clock_watch_face);
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
mWakeLock = powerManager.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "MyWakelockTag");
mWakeLockHandler = new Handler();
IntentFilter messageFilter = new IntentFilter("message-forwarded-from-data-layer");
MessageReceiver messageReceiver = new MessageReceiver();
LocalBroadcastManager.getInstance(this).registerReceiver(messageReceiver, messageFilter);
}
public class MessageReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
}
mWakeLockHandler.removeCallbacksAndMessages(null);
mWakeLockHandler.postDelayed(mReleaseRunnable, 5000);
}
}
private Runnable mReleaseRunnable = new Runnable() {
#Override
public void run() {
mWakeLock.release();
}
};
#Override
protected void onDestroy() {
super.onDestroy();
mWakeLockHandler.removeCallbacksAndMessages(null);
mWakeLock.release();
}
}
And allow WAKE_UP permission in your Manifest.
<uses-permission android:name="android.permission.WAKE_LOCK" />
You should use AlarmManager along with WakefulBroadcastReceiver and startWakefulService(). See this working solution.
You may find answers for your further questions in chat history on that post here.This is the only solution worked for our app.
#SeaDog is successful in making http calls when device in deep sleep mode with this solution. Try it.
I have this application that needs to run a service (background) that beeps periodically.
The phone needs to beep the entire day for 5 seconds every one minute (used a handler in the service). I have implemented this service which does this perfectly, but when the phone goes into deep sleep mode, the execution stops of this handler stops. Using this answer from the question in SO, I managed to use wake locks and it works fine. But when I explicitly put the phone in deep sleep mode, the handler stops executing. Where do I place the wakelock in the service. Code snippet below.
public class PlaySound extends Service{
PowerManager.WakeLock wl ;
PowerManager pm;
private SoundManager mSoundManager;
boolean wakeUpFlag = false;
#Override
public void onCreate(){
super.onCreate();
mSoundManager = new SoundManager();
mSoundManager.initSounds(getBaseContext());
mSoundManager.addSound(1, R.raw.sound);
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
startservice();
return START_STICKY;
}
private void startservice() {
System.out.println("Started the service");
timer.scheduleAtFixedRate( new TimerTask() {
public void run() {
toastHandler.sendEmptyMessage(0);
}
}, 0, 60000);
}
private final Handler toastHandler = new Handler()
{
#Override
public void handleMessage(Message msg)
{
result =start();
System.out.println("result"+result);
close();
}
};
protected void close() {
try {
if(wakeUpFlag){
wl.release();
System.out.println("Released the wakelock");
}
if(!pm.isScreenOn()){
System.out.println("Screen is off - back to sleep");
pm.goToSleep(1000);
}
else{
System.out.println("Screen is on - no need to sleep");
}
bs.close();
writer.close();
System.out.println("Closed socket and writer");
System.out.println("Size of file:"+f.length()/1024);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
public void start(){
try{
wakeUpFlag = false;
pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
if(!pm.isScreenOn()) {
wakeUpFlag = true;
wl = pm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK | PowerManager.ON_AFTER_RELEASE,"CollectData");
System.out.println("Screen off - wake lock acquired");
wl.acquire();
}
else{
System.out.println("Screen on - no need of wake lock");
}
}
catch(Exception e){
e.printStackTrace();
}
mSoundManager.playSound(1);
}
I dont think you are using the correct flag accorinding to the android documentation fior PowerManager:
*If you hold a partial wakelock, the CPU will continue to run, irrespective of any timers and even after the user presses the power button. In all other wakelocks, the CPU will run, but the user can still put the device to sleep using the power button.
In other words, try using PARTIAL_WAKE_LOCK as this is the only one that gurantees the cpu to run
Follow the pattern Mark Murphy provides with the WakefulIntentService. I would suggest picking up his books, not only for the detailed explanation of this class and example he includes in one of them, but for the other wealth of information you'll find in them.
I just recently implemented this pattern for my main app and this class works like a charm.
I think you'd be better off using android.app.AlarmManager to schedule a wakeup alarm. Be careful though - you don't want to do any long-running work in your onReceive() method as that's normally called on the main thread, and will hang your activity. You'll still need to acquire the wakelock for the duration of your task to prevent the phone sleeping part-way through.
I have a service that spawns a thread which runs a task every 3 seconds.
class MyService extends Service {
private Timer timer = new Timer();
public int onStartCommand(Intent intent, int flags, int startId) {
TimerTask task = new TimerTask() {
public void run() {
// something important
}
};
timer.scheduleAtFixedRate(task, 0, 3000);
return Service.START_STICKY;
}
...
}
My service runs fine when my phone is on, but when my phone is on standby, the service is often not responding.
Any clues as to how I can ensure my service is running while on standby?
Maybe use alarms via AlarmManager class.