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>

 

posted @ 2014-10-27 10:49  Mirrorhanman  阅读(137)  评论(0编辑  收藏  举报