android in practice_Using Cloud to Device Messaging(portfolio project)

It’s important to think about the effect that the preceding code will have on battery life. The CPU is going to be woken up to make a network call, update a local database,

and possibly create Notifications. Without the power management code we added,this wouldn’t happen when the device is asleep.

there will always be some window of time where an event has happened that you’d like to give your user a Notification.Android’s Cloud to Device Messaging service
provides an elegant alternative to this.The less time,the more valuable.we can use C2DM to allow a server to tell our background Service to refresh its cache.

Update manifest with C2DM permissions

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="example.stockportfolio"
    android:versionCode="1"
    android:versionName="1.0" >
    <application
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".ViewStocks"
            android:label="@string/title_activity_main" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <service android:name="PortfolioManagerService"
            android:process=":stocks_background"
            android:icon="@drawable/icon"
            android:label="@string/service_name"
            />
        <service android:name=".SendC2dmRegistrationService"
            android:process=":stocks_background" />
        <receiver android:name="PortfolioStartupReceiver"
            android:process=":stocks_background" >
            <intent-filter >
                <action android:name="android.intent.action.BOOT_COMPLETED"/>
            </intent-filter>
        </receiver>
        <receiver android:name=".AlarmReceiver" android:process=":stocks_background" />
        <receiver android:name=".PushReceiver" 
			      android:permission="com.google.android.c2dm.permission.SEND">
		    <intent-filter>
		        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
		        <category android:name="example.stockportfolio" />
		    </intent-filter>
		    <intent-filter>
		        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
		        <category android:name="example.stockportfolio" />
		    </intent-filter>
		</receiver>	
    </application>
    <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" />
    <uses-permission android:name="android.permission.INTERNET"/>
    <permission android:name="example.stockportfolio.permission.C2D_MESSAGE" android:protectionLevel="signature" />
	<uses-permission android:name="cexample.stockportfolio.permission.C2D_MESSAGE"/>
	<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
	<uses-permission android:name="android.permission.VIBRATE"/>
</manifest>
initiating the C2DM registration process.
public class PortfolioStartupReceiver extends BroadcastReceiver {
private static final String DEVELOPER_EMAIL_ADDRESS = "...";
@Override
public void onReceive(Context context, Intent intent) {
Intent registrationIntent =
new Intent("com.google.android.c2dm.intent.REGISTER");
registrationIntent.putExtra("app",
PendingIntent.getBroadcast(context, 0,
new Intent(), 0));
registrationIntent.putExtra("sender", DEVELOPER_EMAIL_ADDRESS);
context.startService(registrationIntent);
}
}
Now instead of using the AlarmManager here to schedule the execution of our Service, we’re going to rely on C2DM.

Once the device boots up, the receiver will send out this registration request. We need another BroadcastReceiver to handle the response from the C2DM servers.

Registration and messaging receiver

/**
 * <code>BroadcastReceiver</code> used to receive events from the
 * Cloud to Device Messaging (C2DM) service. 
 */
public class PushReceiver extends BroadcastReceiver {
	@Override
	public void onReceive(Context context, Intent intent) {
		AlarmReceiver.acquireLock(context);
		if(intent.getAction().equals("com.google.android.c2dm.intent.REGISTRATION")){
			onRegistration(context,intent);
		}else if(intent.getAction().equals("com.google.android.c2dm.intent.RECEIVE")){
			onMessage(context,intent);
		}
	}
	
	/**
	 * This method is used to handle the registration event being sent from C2DM.
	 */
	private void onRegistration(Context context, Intent intent){
		String regId=intent.getStringExtra("registration_id");
		if(regId!=null){
			Intent i=new Intent(context,SendC2dmRegistrationService.class);
			i.putExtra("regId", regId);
			context.startService(i);
		}
	}
	/**
	 * This method is used to handle events sent from your servers, via the C2DM service.
	 */
	private void onMessage(Context context, Intent intent){
		Intent stockService=new Intent(context,PortfolioManagerService.class);
		// copy any data sent from your server
		stockService.putExtras(intent);
		context.startService(stockService);
	}

}
Note that when we receive a message, we acquire the static WakeLock in a manner similar to the previous technique. There are two types of messages that it’ll
receive: one for registration events and one for events from your application server.To distinguish them, we look at the Intent that was sent from the C2DM server, and in
particular at its action property.

We need this ID in order for our app servers to be able to send events to the C2DM servers. The C2DM servers will use the registration ID provided by our servers to route the message to the correct device, and then to the correct BroadcastReceiver on that device. We could send the registration ID to our servers from this BroadcastReceiver, but a BroadcastReceiver is designed to execute quickly, so we’ll offload this to an IntentService.
IntentService for sending registration info to servers

public class SendC2dmRegistrationService extends IntentService {
	private static final String WORKER_NAME = "SendC2DMReg";
	public SendC2dmRegistrationService() {
		super(WORKER_NAME);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onHandleIntent(Intent intent) {
		// TODO Auto-generated method stub
		try{
			String regId = intent.getStringExtra("regId");
			// TODO: Send the regId to the server
		} finally {
			AlarmReceiver.releaseLock();
		}
	}

}

This Service gets the registration ID B that was passed in listing 5.24. Then, it sends this information to your server and releases the WakeLock C when it’s done. Your server will use this information whenever it wants to send a message to your app.

In addition to the registration ID from the device, it’ll also need a ClientLogin auth token. This is a generic Google authentication and authorization mechanism.

onMesage()

This is the code to start the PortfolioManagerService. In this case, we’ve still acquired the static WakeLock. But as we saw in the previous technique, the PortfolioManager-
Service will release this WakeLock once it finishes its work.

In this example, we use a message pushed from the server to tell our background Service to update its cache and generate Notifications as needed. But the data that we
push from the server can be much richer. When your application sends data to the C2DM servers, it can send arbitrary name-value pairs. Those name-value pairs can then be accessed from your receiver using the Intent.getXXXExtra methods. For our application, we could have our server track the high/low price events, and it could pass this information as part of the Intent. That could save our background Service from having to wait for data from the network, so that it can issue Notifications quicker.

你可能感兴趣的:(android in practice_Using Cloud to Device Messaging(portfolio project))