User Tools

Site Tools


android-labs-s14:class-07

Class 07

In this class, we'll be learning about:

  • Service
  • Notifications
  • Audio Playback

Week-2 Homework Review

Source code available on Github.


Service

  • A Service is an application component that runs in the background without needing to interact with the user.
  • For example, a service might handle network transactions, play music or perform file I/O, all from the background.
  • Another application component (for e.g., an Activity) can start a service and it will continue to run in the background even if the user switches to another application.
  • Additionally, a component can bind to a service to interact with it and even perform interprocess communication (IPC).

A service can have two forms-

State Service callback Description
Started onStartCommand() A service is “started” when an application component (such as an activity) starts it by calling startService(). Once started, a service can run in the background indefinitely, even if the component that started it is destroyed.
Bound onBind() A service is “bound” when an application component binds to it by calling bindService(). A bound service offers a client-server interface that allows components to interact with the service, send requests, get results, and even do so across processes with interprocess communication (IPC).

Lifecycle Callback Methods

To create a service, you must create a subclass of Service (or one of its existing subclasses). The most important callback methods you should override are:

Lifecycle Callback Description
onCreate() The system calls this method when the service is first created, to perform one-time setup procedures (before it calls either onStartCommand() or onBind()). If the service is already running, this method is not called.
onStartCommand() The system calls this method when another component, such as an activity, requests that the service be started, by calling startService(). If you implement this, it is your responsibility to stop the service when its work is done, by calling stopSelf() or stopService().
onBind() The system calls this method when another component wants to bind with the service (such as to perform RPC), by calling bindService().
onDestroy() The system calls this method when the service is no longer used and is being destroyed.

Demo

Quick look into what we're going to build next.

App: PlayMusic

We'll build an application similar to other Music Players which we can use to play music even when our application is in background or we have exited from our app. We'll use Service and Notification for this purpose.

Let's begin with creating an Android Application Project (with Minimum API Level = 16). I've named it PlayMusic.

Step 01: Create the Main Screen

Create the main screen which should look similar to the screenshot below.

Step 02: Create PlayMusic Service

Now, we have to create a service which will play this audio file even if our application goes into background. So, as mentioned before, we'll need implement lifecycle methods - (1) onCreate(), (2) onStartCommand(), (3) onDestroy(). And, yes, we'll be binding the service in our app, so we'll implement onBind() as well.

  • Let's begin with creating a class extending Service. I named it PlayMusicService.
PlayMusicService.java
public class PlayMusicService extends Service
{
	// An interface object used by clients to communicate with the service.
	private final IBinder mBinder = new MyBinder();
 
	@Override
	public void onCreate()
	{
		Toast.makeText(this, "Service Created", Toast.LENGTH_SHORT).show();
	}
 
	@Override
	public int onStartCommand(Intent intent, int flags, int startId)
	{
		Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
		return Service.START_STICKY;	// Service will be explicitly started and stopped as needed.
	}
 
	@Override
	public IBinder onBind(Intent i)
	{
		Toast.makeText(this, "Binding Service", Toast.LENGTH_SHORT).show();
		return mBinder;
	}
 
	public class MyBinder extends Binder
	{
		PlayMusicService getService()
		{
			return PlayMusicService.this;
		}
	}
 
	public void onDestroy()
	{
		Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
	}
 
}
  • Like Activity, we also have to register any Service used in the app in AndroidManifest.xml of the project. Add <service> as the sibling of <activity> tag (i.e. as a child of <application> tag).
	<application>
 
		<!-- Existing activities -->
		<activity>....</activity>
 
		<!-- Add your service as in the line below -->
		<service android:name="com.example.playmusic.PlayMusicService" />
 
	</application>

Step 03: Implement click callbacks for the Buttons on Main Screen

  • For binding to a service, we need to have a ServiceConnection object in the MainActivity class. ServiceConnection is an interface for monitoring the state of an application service. The methods of this class are called from the main thread of application's process.
MainActivity.java
	private ServiceConnection mConnection = new ServiceConnection()
	{
		public void onServiceConnected(ComponentName className, IBinder binder)
		{
			Toast.makeText(MainActivity.this, "Connected to the service", Toast.LENGTH_SHORT)
					.show();
		}
 
		public void onServiceDisconnected(ComponentName className)
		{
			Toast.makeText(MainActivity.this, "Disconnected from the service", Toast.LENGTH_SHORT)
					.show();
		}
	};
  • Now, on the click of Start button, we have to first bind the service and then start it. Whereas, on the click of Stop button, we have to unbind and stop the service.
MainActivity::onButtonClick()
	private boolean mIsBound = false;
 
	public void onButtonClick(View v)
	{
		switch (v.getId())
		{
		case R.id.button_start:
 
			doBindService();
			startService(new Intent(MainActivity.this, PlayMusicService.class));
 
			break;
 
		case R.id.button_stop:
 
			doUnbindService();
			stopService(new Intent(MainActivity.this, PlayMusicService.class));
 
			break;
 
		default:
		}
	}
 
	void doUnbindService()
	{
		if (mIsBound)
		{
			unbindService(mConnection);
			mIsBound = false;
 
			Toast.makeText(this, "Unbinding Service", Toast.LENGTH_SHORT).show();
		}
	}
 
	void doBindService()
	{
		mIsBound = true;
		bindService(new Intent(this, PlayMusicService.class), mConnection, Context.BIND_AUTO_CREATE);
	}

Step 04: Play Audio while PlayMusicService is running

Our intention is to play a music file on press of 'Start' button, and stop it on press of 'Stop' button.

Supported Audio Formats

  • You can find here the audio formats supported by Android, which includes .mp3, .mp4, .3gp, and .wav.
  • First of all, you need to download an audio file (in any of the above formats). You can get one from last.fm website. (I downloaded one and renamed it to 'song.mp3')
  • We generally want audio files to be saved in their raw form. So, create a folder named raw inside res folder. And, copy the downloaded audio file to res/raw folder.
  • To play an audio file, we first have to create MediaPlayer object.
	/* Create a MediaPlayer object as the member variable of PlayMusicService class */
	MediaPlayer mPlayer;
 
	/* ----------- Add this in onCreate() method -----------------------*/
	mPlayer = MediaPlayer.create(this, R.raw.song);	// Set the Player to play the downloaded audio file
	mPlayer.setLooping(false);	// Disable auto-repeat
 
	/* ----------- Add this in onStartCommand() method -----------------------*/
	mPlayer.start(); // Start playing music
 
	/* ----------- Add this in onDestroy() method -----------------------*/
	mPlayer.stop();	// Stop playing music

Step 05: Add Notifications

Notifications are persistent messages at the top of the device, commonly known as the 'Status bar' (sometimes also referred to as the 'Notification bar').

Notifications collapsed appear something like below:

And, when expanded, they look something like:

  • To create a Notification, we can use Notification.Builder. And, we have to use NotificationManager to display a notification. The code snippet below shows how to create a notification. You can add this method to PlayMusicService class.
PlayMusicService.java
	private NotificationManager mNotificationMgr;
	private void createNotification()
	{
		// Prepare intent which is triggered if the notification is clicked.
		Intent intent = new Intent(this, MainActivity.class);
		PendingIntent contentIntent = PendingIntent.getActivity(this, 0 /* requestCode */, intent,
				Notification.FLAG_ONGOING_EVENT);
 
		// Build notification
		Notification notification = new Notification.Builder(this)
				.setContentTitle("PlayMusicService")
				.setContentText("Tap to go to application & stop the service.")
				.setSmallIcon(R.drawable.ic_launcher)
				.setContentIntent(contentIntent)
				.setAutoCancel(true)
				.build();
 
		notification.flags = notification.flags | Notification.FLAG_ONGOING_EVENT;
 
		// Display the notification
		mNotificationMgr = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
		mNotificationMgr.notify(R.string.hello_world, notification);
	}
  • Now, we can call this method when we start playing the audio file. So, onStartCommand() should look something like below in the end:
PlayMusicService::onStartCommand()
@Override
	public int onStartCommand(Intent intent, int flags, int startId)
	{
		// Display notification in the notification bar
		createNotification();
 
		// Start playing music
		mPlayer.start();
 
		Toast.makeText(this, "Service Started", Toast.LENGTH_SHORT).show();
		return Service.START_STICKY;	// Service will be explicitly started and stopped as needed.
	}
  • Also, we want to hide this notification, when the song stops playing, i.e. when service gets destroyed. We can remove notifications again using NotificationManager. Hence, onDestroy() of PlayMusicService should end up with something similar like below:
PlayMusicService::onDestroy()
	public void onDestroy()
	{
		// Remove notification from the Notification bar.
		mNotificationMgr.cancel(R.string.hello_world);
 
		// Stop playing music
		mPlayer.stop();
 
		Toast.makeText(this, "Service Destroyed", Toast.LENGTH_SHORT).show();
	}
android-labs-s14/class-07.txt · Last modified: 2014/02/24 14:11 by prakhar