I am very confused whether to acquire this wakelock. E.g. I have this type of code that is called from onReceive() of a BroadcastReceiever (CONNECTIVITY_CHANGE, BOOT_COMPLETED etc) asynchronously i.e. I am launching an IntentService from onReceive() which performs heavy lifting.
private static void insertInDatabase(Context context /*, some data to be inserted in database*/) {
Database helper = Database.getInstance(context);
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakelockName);
wakeLock.acquire();
try {
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues cv = new ContentValues();
// insert data in database here
} finally {
wakeLock.release();
}
}
Is this scenario the right candidate to acquire PowerManager.PARTIAL_WAKE_LOCK?
The answer by #paha misses an important point : IntentService is not enough. Between onReceive() ends and the IntentService is started the phone might fall asleep again. You need a (static) lock to bridge this gap - this is implemented in Mark Murpphy's WakefulIntentService
So keep the AlarmManager and receiver but launch a WakefulIntentService from your onReceive().
See:
Android deep sleep and wake locks
PowerManager wakelock not waking device up from service
Method onReceive() is running on the main application thread and you do not know how long insertInDatabase() will take.
Use an IntentService for doing the database insert and scheduling your alarms. The IntentService will call your onHandleIntent() on a background thread, so you can take the time you need, and the service automatically goes away when onHandleIntent() completes.
public class MyIntentService extends IntentService {
#Override
protected void onHandleIntent(Intent intent) {
PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
final WakeLock wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakelockName);
wakeLock.acquire();
wl.acquire();
try {
SQLiteDatabase db = helper.getWritableDatabase();
ContentValues cv = new ContentValues();
// insert data in database here
} finally {
wakeLock.release();
}
}
}
To start IntentService from BroadcastReceiver use AlarmManager.
IntentService work as queue pattern and you don't need to worry about synchronicity of operations.
Added after discussion in comments:
Your code example does not say from what place you call PARTIAL_WAKE_LOCK. The short answer is PARTIAL_WAKE_LOCK is not needed in the BroadcastReciever and PARTIAL_WAKE_LOCK is needed in the IntentService. Maybe this will help BroadcastReceiver, Service and Wakelock
Related
I am a newbie in Android.
I wanna create a programing related to Wakelock.
When wakelock is acquired(it's as same as Alarm), an popup Activity is created and it enters HomeScreen directly.
How can I do it?
In manifest
<uses-permission android:name="android.permission.WAKE_LOCK" />
If your app includes a broadcast receiver that uses a service to do some work, you can manage your wake lock through a WakefulBroadcastReceiver, as described in Using a WakefulBroadcastReceiver. This is the preferred approach. If your app doesn't follow that pattern, here is how you set a wake lock directly:
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakelockTag");
wakeLock.acquire();
Using WakefulBroadcastReceiver
In manifest:
<receiver android:name=".MyWakefulReceiver"></receiver>
The following code starts MyIntentService with the method startWakefulService()
public class MyWakefulReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Start the service, keeping the device awake while the service is
// launching. This is the Intent to deliver to the service.
Intent service = new Intent(context, MyIntentService.class);
startWakefulService(context, service);
}
}
Referance :
https://developer.android.com/training/scheduling/wakelock.html
I am calling a service from an AlarmManager onReceive, below is the implementation. I want to know if this implementation of a wake lock is fine and will it suffice my needs?
This is the onStart function in my Service Class:
#Override
public void onStart(Intent intent, int startId) {
WakeLock wakeLock = null;
try{
PowerManager mgr = (PowerManager)getApplicationContext()
.getSystemService(Context.POWER_SERVICE);
wakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
wakeLock.acquire();
//For time consuming an long tasks you can launch a new thread here
Toast.makeText(this, " Service Started", Toast.LENGTH_LONG).show();
}catch(Exception e){
}finally{
wakeLock.release();
}
}
Yep, that should work fine. Although it won't work if you spin up a new Thread, in that case wakelock.release() will be called before the Thread finishes.
You might want to check CommonsWare's Wakeful service though. That services handles the wakelock for you, ensuring that you have a Wakelock during the service, and it'll release it as soon as you stop the service.
My application sends gps updates to a API. I need my application to run in background all the time. But unfortunately, my application always end at some point while on background. I have read that when the cpu usage of the application is low, the application is will be killed automatically. I don't want this to happen. I already included a partial wake lock on my onCreate method in my application using this code:
powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock");
Then on pause:
protected void onPause()
{
super.onPause();
onBackground = true;
wakeLock.acquire();
Log.w("OnPause", "OnPause");
}
I really don't know how to prevent my application being killed. I also tried using full wake lock but it is deprecated. Any ideas on how will I keep my application alive on background? I never want my application to be killed while on background. Thanks!
You can not.
Just make sure, you persist anything that should survive after being killed.
For anything that should run in background, even if the app is not shown to the user:
Use a Service and set it into foreground mode.
public class BGService extends Service {
private PowerManager powerManager;
private WakeLock wakeLock;
#Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"MyWakeLock");
wakeLock.acquire();
}
call and start service in your main activity
public class SendSMSActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.demo);
startService(new Intent(this, BGService.class));
}
}
I have the following code in my BroadcastReceiver's onReceive function.
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action == null) return;
if (action.equals(ACTION_ALARM)) {
Intent alarmPopup = new Intent(context, AlarmPopup.class);
int vibrateDuration = context.getSharedPreferences(PREF, 0)
.getInt(VIBRATE_DURATION, DEFAULT_VIBRATE_DURATION)
alarmPopup.putExtra(VIBRATE_DURATION, vibrateDuration);
alarmPopup.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(alarmPopup);
}
}
This code starts activity AlarmPopup as it receives alarm manager's broadcast.
Once the AlarmPopup activity is started, it shows a typical alarm message and vibrates during vibrateDuration passed through Intent#putExtra.
In AlarmPopup's onCreate method, the activity holds WakeLock to make the device keep turning on.
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
wl = getLock(this);
if (!wl.isHeld()) {
Log.d(PREF, "Alarm popup acquires wake lock");
wl.acquire();
thread.run();
}
.
.
.
}
getLock is a synchronized method that manages WakeLock as WakefulIntentService does.
private static volatile PowerManager.WakeLock wlStatic = null;
synchronized private static PowerManager.WakeLock getLock(Context context) {
if (wlStatic == null) {
PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
wlStatic = mgr.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK
| PowerManager.ACQUIRE_CAUSES_WAKEUP
| PowerManager.ON_AFTER_RELEASE, PREF);
wlStatic.setReferenceCounted(true);
}
return wlStatic;
}
Now here is the problem: even though context.startActivity(alarmPopup) is called, startActivity rarely does not start the activitiy or starts not on time, usually 1-2 minutes later.
It seems that OS kills my AlarmPopup activitiy in the middle of its creation or let the activity be created a little bit later than the time when startActivity was actually called.
What is really interesting is, when the above problem happens, sometimes the log message "Alarm popup acquires wake lock" is recorded and sometimes it is not even recorded. I think, in this case, OS kills the activity while it executes the first or second line of onCreate method.
How can I solve this problem?
Should I put some dummy code that holds the CPU at the end of onReceive while the AlarmPopup activity is being created by another thread?
It seems that OS kills my AlarmPopup activitiy in the middle of its creation or let the activity be created a little bit later than the time when startActivity was actually called.
No. The device simply fell asleep. startActivity() is an asynchronous operation. The WakeLock held by the OS for the AlarmManager work (assuming that you are, indeed, using AlarmManager) will be released when onReceive() returns. onCreate() of your activity will not have run by the time onReceive() returns. Hence, the device might fall asleep in the window of time between the end of onReceive() and when you acquire your WakeLock in onCreate().
How can I solve this problem?
Acquire the WakeLock in onReceive().
im receiving an intent in broadcast receiver and then i start service to do more work. now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
does my service will stop running if the device goes to sleep without getting a wakelock.
now what if the device is sleep and this happen, do i have to get Wakelock (AlarmManger?), and why do i need it?
If the device is asleep to begin with, you will not be "receiving an intent in broadcast receiver", because the device is asleep.
do i have to get Wakelock (AlarmManger?), and why do i need it?
You don't "need it", unless you want to ensure the device stays running while you complete some work.
does my service will stop running if the device goes to sleep without getting a wakelock.
Yes.
Looks like the Android's native WakefulBroadcastReceiver would be a perfect solution for you. Need to extend this rather than the regular BroadcastReceiver and start the service in the onReceive() in the "wakeful" manner:
startWakefulService(context, service);
and signal your work is done in the service's onHandleIntent(), calling
MyWakefulReceiver.completeWakefulIntent(intent);
public class WakeLockManager extends BroadcastReceiver {
private static WakeLock mWakeLock;
private String LCLT;
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Consts.WAKELOCK_INTENT)) {
Log.v("wakelock", "GOT THE wakelock INTENT");
boolean on = intent.getExtras().getBoolean("on");
if (mWakeLock == null) {
PowerManager pm = (PowerManager) context
.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
"Breeze WakeLock");
}
if (on) {
if (!mWakeLock.isHeld()) {
mWakeLock.acquire();
Log.v("wakelock", "acquiring wakelock");
}
} else {
if (mWakeLock.isHeld()) {
Log.v("wakelock", "releasing wakelock");
mWakeLock.release();
}
mWakeLock = null;
}
}
}
}
look at the above code ..put it in a separate class file and and in your manifest define it for some custom intent .... now that this class will respond to a custom intent ...just broadcast that intent and you can turn the wakelock on or off in your entire app since the wakelock is static..like this :
public void setWakeup(boolean status) {
Intent wakelock_Intent = new Intent(CUSTOM_INTENT);
wakelock_Intent.putExtra("on", status);
this.sendBroadcast(wakelock_Intent);
}
the above would be defined in your alarmmanager code so it schedules a call