android in practice_Keeping Services awake(portfolio project)

AlarmManager help us to resurrect our killed Service. But that resurrection could be short-lived.the Service needs to do—retrieve fresh stock data from the Internet and send out Notifications if needed.We want it to keep the device awake long enough to create Notifications for the user.

Android’s PowerManager API,Acquiring a WakeLock allows your application to prevent the OS from putting the device to sleep (turning off the CPU).you must list it as a <uses-permission> in your AndroidManifest.xml file.

the PARTIAL_WAKE_LOCK. This turns on the CPU, but keeps the screen turned off.

We can add code to our Service to acquire a WakeLock during its onStartCommand method, and then release it after we finish checking for Notifications. But there’s a big problem with that approach. If the device is asleep, then the WakeLock acquired by the AlarmManager will be released once the onReceive method of our AlarmReceiver class finishes. This can (and will) happen before the onStartCommand of our Service is invoked. The device could go back to sleep before we even get a chance to acquire a WakeLock. Therefore, we must acquire a WakeLock in the onReceive method of AlarmReceiver, since that’s the only place we’re guaranteed that execution won’t be suspended.

Modified AlarmReceiver, now with power management:

/**
 * A {BraodcastReceiver} is notified when a system alarm fires. It then starts the 
 * {PortfolioManagerService} passing it a {WakeLock}.
 */
public class AlarmReceiver extends BroadcastReceiver {
	private static PowerManager.WakeLock wakeLock=null;
	private static final String LOCK_TAG = "com.manning.aip.portfolio";
	public static synchronized void acquireLock(Context ctx){
		if(wakeLock==null){
			PowerManager mgr=(PowerManager)ctx.getSystemService(Context.POWER_SERVICE);
			wakeLock=mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOCK_TAG);
			wakeLock.setReferenceCounted(true);
		}
		wakeLock.acquire();
	}
   public static synchronized void releaseLock(){
	   if(wakeLock!=null){
		   wakeLock.release();
	   }
   }
	@Override
	public void onReceive(Context context, Intent intent) {
		acquireLock(context);
		// TODO Auto-generated method stub
		Intent stockService=new Intent(context,PortfolioStartupReceiver.class);
		context.startService(stockService);
	}
}

Normally, to share with a Service that you’re starting, you’d pass it as part of the Intent (typically as an extra), but anything passed as part of the Intent must be a
Parcelable. A WakeLock is a representation of a system setting, it’s definitely not a Parcelable. So we use static variables and static methods to work around this.

We used a static WakeLock with static acquire/release methods so that this can be shared between the AlarmReceiver instance and our background Service.

Keep in mind that for this technique to work, AlarmReceiver and our Service must be running in the same process, or you’ll face a tricky bug.

Here’s the declaration of AlarmReceiver from our AndroidManifest.xml file:

 <receiver android:name=".AlarmReceiver" android:process=":stocks_background" />
 <uses-permission android:name="android.permission.WAKE_LOCK"/>
Now we need to add code to PortfolioManagerService to release the WakeLock so that the device can go back to sleep.

Releasing the WakeLock after checking for alerts:

private void checkForAlerts(Iterable<Stock> stocks){
		try{
			for(Stock stock:stocks){
				double current=stock.getCurrentPrice();
				if(current>stock.getMaxPrice()){
					createHighPriceNotification(stock);
					continue;
				}
				if(current<stock.getMinPrice()){
					createLowPriceNotification(stock);
				}
			}
		}finally{
			AlarmReceiver.releaseLock();
			this.stopSelf();
		}
	}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值