Service description:
A service is an application component that can perform long-running operations in the background and does not provide a user interface. Another application component 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 inter-process communication (IPC).
A service can essentially take two forms:
Started
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
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 inter-process communication (IPC).
Life of Cycle
context.startService() ->onCreate()->onStart()->Service running--->context.stopService() ->onDestroy()
context.bindService()->onCreate()->onBind()->Service running--->onUnbind() -> onDestroy()
To create a service, you must create a subclass of Service(or one of its existing subclass).
onStartCommand():
The system calls this method when another component, such as an activity, requests that the service be started, by calling startService().
onBind():
The system calls this method when another component wants to bind with the service (such as to perform RPC), by calling bindService().
onCreate()
The system calls this method when the service is first created, to perform one-time setup procedures
onDestroy()
The system calls this method when the service is no longer used and is being destroyed.
The difference between them:
If a component starts the service by calling startService() (which results in a call to onStartCommand()), then the service remains running until it stops itself with stopSelf() or another component stops it by calling stopService().
If a component calls bindService() to create the service (and onStartCommand is not called), then the service runs only as long as the component is bound to it. Once the service is unbound from all clients, the system destroys it.
We will present a bind service to show how it works. In our example, the main activity will ask the service to send message to the main activity until you click unbind button. The message is “Hello world!”.
Demo website: http://www.youtube.com/watch?v=5Cct5kYbH4w&feature=youtu.be
Step one: make a new project:
Android version 2.2
Step two: AndroidManifest.xml
<?xml
version="1.0"
encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
package="com.szy.service"
android:versionCode="1"
android:versionName="1.0"
>
<uses-sdk
android:minSdkVersion="8"
/>
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
>
<intent-filter>
<action
android:name="android.intent.action.MAIN"
/>
<category
android:name="android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
<service
android:name=".MyService"></service>
</application>
</manifest>
Step three: res/values/Strings.xml
<resources>
<string
name="hello">Hello World, MainActivity!</string>
<string
name="app_name">ExampleService</string>
<string
name="service_started">Example Service started</string>
<string
name="service_label">Example Service Label</string>
</resources>
Step four: Code in MainActivity.java
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
public class MainActivity extends Activity {
Button btnBind, btnUnbind;
TextView textStatus, textStrValue;
Messenger mService = null;
boolean mIsBound;
final Messenger mMessenger = new Messenger(new IncomingHandler());
String s = "";
class IncomingHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MyService.MSG_SET_STRING_VALUE:
String str1 = msg.getData().getString("str1");
s += str1;
textStrValue.setText("Coming Message: " + s);
break;
default:
super.handleMessage(msg);
}
}
}
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
mService = new Messenger(service);
textStatus.setText("Attached.");
try {
Message msg = Message.obtain(null, MyService.MSG_REGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been unexpectedly disconnected - process crashed.
mService = null;
textStatus.setText("Disconnected.");
}
};
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnBind = (Button)findViewById(R.id.btnBind);
btnUnbind = (Button)findViewById(R.id.btnUnbind);
textStatus = (TextView)findViewById(R.id.textStatus);
textStrValue = (TextView)findViewById(R.id.textStrValue);
btnBind.setOnClickListener(btnBindListener);
btnUnbind.setOnClickListener(btnUnbindListener);
CheckIfServiceIsRunning();
}
private void CheckIfServiceIsRunning() {
//If the service is running when the activity starts, we want to automatically bind to it.
if (MyService.isRunning()) {
doBindService();
}
}
private OnClickListener btnBindListener = new OnClickListener() {
public void onClick(View v){
doBindService();
}
};
private OnClickListener btnUnbindListener = new OnClickListener() {
public void onClick(View v){
doUnbindService();
}
};
void doBindService() {
bindService(new Intent(this, MyService.class), mConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
textStatus.setText("Binding.");
}
void doUnbindService() {
if (mIsBound) {
// If we have received the service, and hence registered with it, then now is the time to unregister.
if (mService != null) {
try {
Message msg = Message.obtain(null, MyService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mMessenger;
mService.send(msg);
} catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
mIsBound = false;
textStatus.setText("Unbinding.");
}
}
@Override
protected void onDestroy() {
super.onDestroy();
try {
doUnbindService();
} catch (Throwable t) {
Log.e("MainActivity", "Failed to unbind from the service", t);
}
}
}
Step five: Create a MyService.java class.
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
public class MyService extends Service {
private NotificationManager nm;
private Timer timer = new Timer();
private int counter = 0;
private static boolean isRunning = false;
int mValue = 0; // Holds last value set by a client.
static final int MSG_REGISTER_CLIENT = 1;
static final int MSG_UNREGISTER_CLIENT = 2;
static final int MSG_SET_STRING_VALUE = 4;
final Messenger mMessenger = new Messenger(new IncomingHandler()); // Target we publish for clients to send messages to IncomingHandler.
String sendText = "Hello World!";
Messenger client = null;
@Override
public IBinder onBind(Intent intent) {
return mMessenger.getBinder();
}
class IncomingHandler extends Handler { // Handler of incoming messages from clients.
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
client = msg.replyTo;
break;
case MSG_UNREGISTER_CLIENT:
client = null;
break;
default:
super.handleMessage(msg);
}
}
}
private void sendMessageToUI(char intvaluetosend) {
try {
Bundle b = new Bundle();
b.putString("str1", "" + intvaluetosend);
Message msg = Message.obtain(null, MSG_SET_STRING_VALUE);
msg.setData(b);
client.send(msg);
} catch (RemoteException e) {
client = null;
}
}
@Override
public void onCreate() {
super.onCreate();
Log.i("MyService", "Service Started.");
showNotification();
timer.scheduleAtFixedRate(new TimerTask(){ public void run() {onTimerTick();}}, 0, 1000L);
isRunning = true;
}
private void showNotification() {
nm = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
// In this sample, we'll use the same text for the ticker and the expanded notification
CharSequence text = getText(R.string.service_started);
String text2 = "send Hello World!";
// Set the icon, scrolling text and timestamp
Notification notification = new Notification(R.drawable.ic_launcher, text2, System.currentTimeMillis());
// The PendingIntent to launch our activity if the user selects this notification
PendingIntent contentIntent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
// Set the info for the views that show in the notification panel.
//notification.setLatestEventInfo(this, getText(R.string.service_label), text, contentIntent);
notification.setLatestEventInfo(this, "Send Hello World", text2, contentIntent);
// Send the notification.
// We use a layout id because it is a unique number. We use it later to cancel.
nm.notify(R.string.service_started, notification);
}
public static boolean isRunning()
{
return isRunning;
}
private void onTimerTick() {
Log.i("TimerTick", "Timer doing work." + counter);
try {
if(counter == (sendText.length()))
{
counter = 0;
}
sendMessageToUI(sendText.charAt(counter));
counter ++;
} catch (Throwable t) { //you should always ultimately catch all exceptions in timer tasks.
Log.e("TimerTick", "Timer Tick Failed.", t);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (timer != null) {
timer.cancel();
}
counter = 0;
nm.cancel(R.string.service_started); // Cancel the persistent notification.
Log.i("MyService", "Service Stopped.");
isRunning = false;
}
}