2.App Components-Services/Bound Services
1. Bound Services
A bound service is the server in a client-server interface. A bound service allows components (such as activities) to bind to the service, send
requests, receive responses, and even perform interprocess communication (IPC). A bound service typically lives only while it serves
another application component and does not run in the background indefinitely
2. The Basics
A bound service is an implementation of the Services class that allows other applications to bind to it and interact with it. To provide binding
for a service, you must implement the onBind() callback method. This method returns an IBinder object that defines the programming
interface that clients can use to interact with the service.
3. Creating a Bound Service
When creating a service that provides binding, you must provide an IBinder
that provides the programming interface that clients can use to
interact with the service. There are three ways you can define the interface:
<1>Extending the Binder class
<2>Using a Messenger
<3>Using AIDL
4. Extending the Binder class
If your service is private to your own application and runs in the same process as the client (which is common), you should create your
interface by extending the Binder
class and returning an instance of it from onBind()
. The client receives the Binder
and can use it to
directly access public methods available in either the Binder
implementation or even the Service
.
This is the preferred technique when your service is merely a background worker for your own application. The only reason you would not
create your interface this way is because your service is used by other applications or across separate processes.
//activity_bingding.xml <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="mirror.android.extendingbinder.BindingActivity" > <Button android:id = "@+id/btn_create_service" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Create service" /> </RelativeLayout>
//LocalService.class package mirror.android.extendingbinder; import java.util.Random; import android.app.Service; import android.content.Intent; import android.os.Binder; import android.os.IBinder; public class LocalService extends Service { private final IBinder mBinder = new LocalBinder(); private final Random mGenerator = new Random(); /*1.In your service, create an instance of Binder that either: * <1> contains public methods that the client can call * <2> returns the current Service instance, which has public methods the client can call * <3> or, returns an instance of another class hosted by the service with public methods the client can call */ public class LocalBinder extends Binder{ LocalService getService(){ return LocalService.this; } } /*2.Return this instance of Binder from the onBind() callback method. */ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return mBinder; } /*The LocalBinder provides the getService() method for clients to retrieve the current instance of LocalService. *This allows clients to call public methods in the service. *For example, clients can call getRandomNumber() from the service.*/ public int getRandomNumber(){ return mGenerator.nextInt(); } }
//BindingActivity.class package mirror.android.extendingbinder; import mirror.android.extendingbinder.LocalService.LocalBinder; 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.IBinder; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.Toast; public class BindingActivity extends Activity { private Button button; LocalService mService; Boolean mBound = false; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_binding); button = (Button)findViewById(R.id.btn_create_service); ButtonListener buttonListener = new ButtonListener(); button.setOnClickListener(buttonListener); } @Override protected void onStart() { super.onStart(); //1.bind to LocalService Intent intent = new Intent(this, LocalService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE); } @Override protected void onPause() { super.onPause(); } @Override protected void onStop() { super.onStop(); //2.unbind from service if(mBound){ unbindService(mConnection); mBound = false; } } class ButtonListener implements OnClickListener{ //3.Call a method from the LocalService. //create a separate thread if needed; @Override public void onClick(View v) { if(mBound){ int num = mService.getRandomNumber(); Toast.makeText(getApplicationContext(), "number: " + num, Toast.LENGTH_SHORT).show(); } } } private ServiceConnection mConnection = new ServiceConnection() { //3.In the client, receive the Binder from the onServiceConnected() callback method // and make calls to the bound service using the methods provided. @Override public void onServiceDisconnected(ComponentName name) { mBound = false; } @Override public void onServiceConnected(ComponentName name, IBinder service) { LocalBinder binder = (LocalBinder)service; mService = binder.getService(); mBound = true; } }; }
//manifest.xml <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name=".BindingActivity" 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=".LocalService"></service> </application>
5. Using a Messenger
If you need your service to communicate with remote processes, then you can use a Messenger to provide the interface for your service.
This technique allows you to perform interprocess communication (IPC) without the need to use AIDL.
For example. click the button in the client, we will see Toast ""Nice to meet you, I'm your server MessengerService.""
then "Nice to meet you too, MessengerService.",
the step will be see in the Logcat and we canhave a look at the photo below
MessengerServerTestClient
1 package com.example.messengerservicetestclient; 2 3 import android.os.Bundle; 4 import android.os.Handler; 5 import android.os.IBinder; 6 import android.os.Message; 7 import android.os.Messenger; 8 import android.os.RemoteException; 9 import android.app.Activity; 10 import android.content.ComponentName; 11 import android.content.Intent; 12 import android.content.ServiceConnection; 13 import android.util.Log; 14 import android.view.View; 15 import android.widget.Button; 16 import android.widget.Toast; 17 18 public class MainActivity extends Activity { 19 20 private Button mButton; 21 22 public static final int MSG_SAY_HELLO = 1;// service可以接收的msg.what 23 24 public static final int MSG_ANS_HELLO = 2;// client可以接收的msg.what 25 26 public static final String BIND_ACTION = "com.lefter.MessengerService";// 用于启动MessengerService.java 27 28 private boolean isServiceBound = false; 29 30 // 处理从Service发过来的Message 31 private Handler mClientHandler = new Handler() { 32 @Override 33 public void handleMessage(Message msg) { 34 35 Log.d("Client: ","Step 7: handleMessage"); 36 37 switch (msg.what) { 38 case MSG_ANS_HELLO: 39 Toast.makeText(getApplicationContext(), 40 "Nice to meet you too, MessengerService.", 41 Toast.LENGTH_SHORT).show(); 42 break; 43 default: 44 super.handleMessage(msg); 45 } 46 } 47 48 }; 49 50 private Messenger mClientMessenger = new Messenger(mClientHandler);// client自己的Messenger 51 52 private ServiceConnection conn = new ServiceConnection() { 53 @Override 54 public void onServiceDisconnected(ComponentName name) { 55 /* 56 * 注意onServiceDisconnected函数的执行时机,当我们手动unBindService的时候,该函数是不会被调用的。 57 * 详见该函数的API 58 */ 59 isServiceBound = false; 60 } 61 62 @Override 63 public void onServiceConnected(ComponentName name, IBinder service) { 64 isServiceBound = true; 65 66 Log.d("Client: ","Step 3: onServiceConnection, IBinder service--->messenger"); 67 Messenger mServiceMessenger = new Messenger(service); // 获得Service的Messenger对象 68 try { 69 Message msg = Message.obtain(null, MSG_SAY_HELLO, 0, 0); 70 // 将client的Messenger对象通过msg传递给Service,Service可以通过这个Messenger对象给client发送消息,以实现双向通信 71 msg.replyTo = mClientMessenger; 72 Log.d("Client: ","Step 4: onServiceConnection, mServiceMessenger--->send msg"); 73 mServiceMessenger.send(msg); 74 } catch (RemoteException e) { 75 e.printStackTrace(); 76 } 77 } 78 }; 79 80 @Override 81 protected void onCreate(Bundle savedInstanceState) { 82 super.onCreate(savedInstanceState); 83 setContentView(R.layout.activity_main); 84 mButton = (Button) findViewById(R.id.textview); 85 mButton.setOnClickListener(new View.OnClickListener() { 86 @Override 87 public void onClick(View v) { 88 if (isServiceBound) { 89 unbindService(conn); 90 } 91 bindService(new Intent(BIND_ACTION), conn, BIND_AUTO_CREATE); 92 Log.d("Client: ","Step 1: bindService"); 93 } 94 }); 95 } 96 }
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.messengerservicetestclient" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="14" 9 android:targetSdkVersion="17" /> 10 11 <application 12 android:allowBackup="true" 13 android:icon="@drawable/ic_launcher" 14 android:label="@string/app_name" 15 android:theme="@style/AppTheme" > 16 <activity 17 android:name="com.example.messengerservicetestclient.MainActivity" 18 android:label="@string/app_name" > 19 <intent-filter> 20 <action android:name="android.intent.action.MAIN" /> 21 22 <category android:name="android.intent.category.LAUNCHER" /> 23 </intent-filter> 24 </activity> 25 </application> 26 27 </manifest>
MessengerServerTestServer
1 //MainActivity . cause a service don't have UI 2 3 package com.example.messengerservicetestserver; 4 5 import android.os.Bundle; 6 import android.app.Activity; 7 8 public class MainActivity extends Activity { 9 10 @Override 11 protected void onCreate(Bundle savedInstanceState) { 12 super.onCreate(savedInstanceState); 13 setContentView(R.layout.activity_main); 14 } 15 }
package com.example.messengerservicetestserver; import android.app.Service; import android.content.Intent; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.util.Log; import android.widget.Toast; public class MessengerService extends Service { public static final int MSG_SAY_HELLO = 1;// service可以接收的msg.waht public static final int MSG_ANS_HELLO = 2;// client可以接收的msg.waht private Messenger mClientMessenger; // Service的Handler对象,用于处理client发来的Message private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { Log.d("Service: ","Step 5: handleMessage"); switch (msg.what) { case MSG_SAY_HELLO: mClientMessenger = msg.replyTo; // 获得client的Messenger对象 Toast.makeText(getApplicationContext(),"Nice to meet you, I'm your server MessengerService.",Toast.LENGTH_SHORT).show(); new Thread() { @Override public void run() { try { Thread.currentThread().sleep(3000); // 延时3秒后回复client Message msg = Message.obtain(null, MSG_ANS_HELLO, 0, 0); Log.d("Service: ","Step 6: handleMessage, mClientMessenger--->send msg"); mClientMessenger.send(msg);// 使用client的Messenger对象给client回信息 } catch (Exception e) { e.printStackTrace(); } } }.start(); break; default: super.handleMessage(msg); } } }; // Service自己的Messenger对象 private Messenger mServiceMessenger = new Messenger(mHandler); @Override public IBinder onBind(Intent intent) { Log.d("Service: ","Step 2: onBind, mMessenger--->IBinder"); return mServiceMessenger.getBinder(); } }
1 <?xml version="1.0" encoding="utf-8"?> 2 <manifest xmlns:android="http://schemas.android.com/apk/res/android" 3 package="com.example.messengerservicetestserver" 4 android:versionCode="1" 5 android:versionName="1.0" > 6 7 <uses-sdk 8 android:minSdkVersion="14" 9 android:targetSdkVersion="17" /> 10 11 <application 12 android:allowBackup="true" 13 android:icon="@drawable/ic_launcher" 14 android:label="@string/app_name" 15 android:theme="@style/AppTheme" > 16 <activity 17 android:name="com.example.messengerservicetestserver.MainActivity" 18 android:label="@string/app_name" > 19 <intent-filter> 20 <action android:name="android.intent.action.MAIN" /> 21 22 <category android:name="android.intent.category.LAUNCHER" /> 23 </intent-filter> 24 </activity> 25 <service 26 android:name="MessengerService" 27 android:exported="true" > 28 <intent-filter> 29 <action android:name="com.lefter.MessengerService" /> 30 </intent-filter> 31 </service> 32 </application> 33 34 </manifest>