BindService ---擴展Binder類

1,BindServcie -- 擴展Binder類開啓服務
  • 前面描述過,如果我們的服務僅供本地應用使用,不需要跨進程工作,則可以實現自有 Binder 類,讓客戶端通過該類直接訪問服務中的公共方法。其使用開發步驟如下
【1】創建BindService服務端,繼承自Service並在類中,創建一個實現IBinder 接口的實例對象並提供公共方法給客戶端調用
 
【2】從 onBind() 回調方法返回此 Binder 實例。
 
【3】在客戶端中,從 onServiceConnected() 回調方法接收 Binder,並使用提供的方法調用綁定服務。
 
【4】注意事項:
  • 此方式只有在客戶端和服務位於同一應用和進程內纔有效,
  • 如對於需要將 Activity 綁定到在後臺播放音樂的自有服務的音樂應用,此方式非常有效。
  • 另一點之所以要求服務和客戶端必須在同一應用內,是爲了便於客戶端轉換返回的對象和正確調用其 API。服務和客戶端還必須在同一進程內,因爲此方式不執行任何跨進程編組。
 
2, 擴展 Binder 類的實例
【1】 Service端的實現BindService.java
  • BindService類繼承自Service
  • 在該類中創建了一個LocalBinder繼承自Binder類,LocalBinder中聲明瞭一個getService方法,客戶端可訪問該方法獲取LocalService對象的實例
  • 只要客戶端獲取到LocalService對象的實例就可調用LocalService服務端的公共方法,如getCount方法,
  • 值得注意的是,我們在onBind方法中返回了binder對象,該對象便是LocalBinder的具體實例,而binder對象最終會返回給客戶端,客戶端通過返回的binder對象便可以與服務端實現交互。
package com.ipctest.service;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
/**
* Description:綁定服務簡單實例--服務端
*/
public class LocalService extends Service{
    private final static String TAG = "wzj";
    private int count;
    private boolean quit;
    private Thread thread;
    private LocalBinder binder = new LocalBinder();
    /**
     * 創建Binder對象,返回給客戶端即Activity使用,提供數據交換的接口
     */
    public class LocalBinder extends Binder {
        // 聲明一個方法,getService。(提供給客戶端調用)
        LocalService getService() {
            // 返回當前對象LocalService,這樣我們就可在客戶端端調用Service的公共方法了
            return LocalService.this;
        }
    }

    /**
     * 把Binder類返回給客戶端
     */
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return binder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "Service is invoke Created");
        thread = new Thread(new Runnable() {
            @Override
            public void run() {
                // 每間隔一秒count加1 ,直到quit爲true。
                while (!quit) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    count++;
                }
            }
        });
        thread.start();
    }

    /**
     * 公共方法
     * @return
     */
    public int getCount(){
        return count;
    }
    /**
     * 解除綁定時調用
     * @return
     */
     @Override
    public boolean onUnbind(Intent intent) {
        Log.i(TAG, "Service is invoke onUnbind");
        return super.onUnbind(intent);
    }

    @Override
    public void onDestroy() {
        Log.i(TAG, "Service is invoke Destroyed");
        this.quit = true;
        super.onDestroy();
    }
}

 

 
【2】客戶端BindActivity的實現:
 
package com.ipctest.service;


import android.app.Activity;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import android.view.View;
import android.widget.Button;

import com.zejian.ipctest.R;

/**
* Description:綁定服務實例--客戶端
*/
public class BindActivity extends Activity {
    protected static final String TAG = "wzj";
    Button btnBind;
    Button btnUnBind;
    Button btnGetDatas;
    /**
     * ServiceConnection代表與服務的連接,它只有兩個方法,
     * onServiceConnected和onServiceDisconnected,
     * 前者是在操作者在連接一個服務成功時被調用,而後者是在服務崩潰或被殺死導致的連接中斷時被調用
     */
    private ServiceConnection conn;
    private LocalService mService;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bind);
        btnBind = (Button) findViewById(R.id.BindService);
        btnUnBind = (Button) findViewById(R.id.unBindService);
        btnGetDatas = (Button) findViewById(R.id.getServiceDatas);
        //創建綁定對象
        final Intent intent = new Intent(this, LocalService.class);


        // 開啓綁定
        btnBind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "綁定調用:bindService");
                //調用綁定方法
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            }
        });
        // 解除綁定
        btnUnBind.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Log.d(TAG, "解除綁定調用:unbindService");
                // 解除綁定
                if(mService!=null) {
                    mService = null;
                    unbindService(conn);
                }
            }
        });


        // 獲取數據
        btnGetDatas.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mService != null) {
                    // 通過綁定服務傳遞的Binder對象,獲取Service暴露出來的數據


                    Log.d(TAG, "從服務端獲取數據:" + mService.getCount());
                } else {


                    Log.d(TAG, "還沒綁定呢,先綁定,無法從服務端獲取數據");
                }
            }
        });

        conn = new ServiceConnection() {
            /**
             * 與服務器端交互的接口方法 綁定服務的時候被回調,在這個方法獲取綁定Service傳遞過來的IBinder對象,
             * 通過這個IBinder對象,實現宿主和Service的交互。
             */
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TAG, "綁定成功調用:onServiceConnected");
                // 獲取Binder
                LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
                mService = binder.getService();
            }
            /**
             * 當取消綁定的時候被回調。但正常情況下是不被調用的,它的調用時機是當Service服務被意外銷燬時,
             * 例如內存的資源不足時這個方法才被自動調用。
             */
            @Override
            public void onServiceDisconnected(ComponentName name) {
                mService=null;
            }
        };
    }
}

 

  • 在客戶端中我們創建了一個ServiceConnection對象,該代表與服務的連接,它只有兩個方法, onServiceConnected和onServiceDisconnected
onServiceConnected(ComponentName name, IBinder service) 
系統會調用該方法以傳遞服務的 onBind() 方法返回的 IBinder。其中service便是服務端返回的IBinder實現類對象,通過該對象我們便可以調用獲取LocalService實例對象,進而調用服務端的公共方法。而ComponentName是一個封裝了組件(Activity, Service, BroadcastReceiver, or ContentProvider)信息的類,如包名,組件描述等信息,較少使用該參數。
onServiceDisconnected(ComponentName name) 
Android 系統會在與服務的連接意外中斷時(例如當服務崩潰或被終止時)調用該方法。注意:當客戶端取消綁定時,系統“絕對不會”調用該方法。
conn = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName name, IBinder service) {
                Log.d(TAG, "綁定成功調用:onServiceConnected");
                // 獲取Binder
                LocalService.LocalBinder binder = (LocalService.LocalBinder) service;
                mService = binder.getService();
            }
            @Override
            public void onServiceDisconnected(ComponentName name) {
                mService=null;
            }
        };

 

 
  • 在onServiceConnected()被回調前,我們還需先把當前Activity綁定到服務LocalService上,綁定服務是通過通過bindService()方法,解綁服務則使用unbindService()方法,這兩個方法解析如下:
 
bindService(Intent service, ServiceConnection conn, int flags) 
該方法執行綁定服務操作,其中Intent是我們要綁定的服務(也就是LocalService)的意圖,而ServiceConnection代表與服務的連接,它只有兩個方法,前面已分析過,flags則是指定綁定時是否自動創建Service。0代表不自動創建、BIND_AUTO_CREATE則代表自動創建。
unbindService(ServiceConnection conn) 
該方法執行解除綁定的操作,其中ServiceConnection代表與服務的連接,它只有兩個方法,前面已分析過。
  • Activity通過bindService()綁定到LocalService後,ServiceConnection#onServiceConnected()便會被回調並可以獲取到LocalService實例對象mService,之後我們就可以調用LocalService服務端的公共方法了,最後還需要在清單文件中聲明該Service。而客戶端佈局文件實現如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <Button
        android:id="@+id/BindService"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="綁定服務器"
        />
    <Button
        android:id="@+id/unBindService"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="解除綁定"
        />
    <Button
        android:id="@+id/getServiceDatas"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="獲取服務方數據"
        />
</LinearLayout>

 

 
3,運行結果:
【1】我們運行程序,點擊綁定服務並多次點擊綁定服務接着多次調用LocalService中的getCount()獲取數據,最後調用解除綁定的方法移除服務,其結果如下: 
 
【2】通過Log可知,
  • 當我們第一次點擊綁定服務時,LocalService服務端的onCreate()、onBind方法會依次被調用,
  • 此時客戶端的ServiceConnection#onServiceConnected()被調用並返回LocalBinder對象,
  • 接着調用LocalBinder#getService方法返回LocalService實例對象,
  • 此時客戶端便持有了LocalService的實例對象,也就可以任意調用LocalService類中的聲明公共方法了。
  • 更值得注意的是,我們多次調用bindService方法綁定LocalService服務端,而LocalService得onBind方法只調用了一次,那就是在第一次調用bindService時纔會回調onBind方法。接着我們點擊獲取服務端的數據,
  • 從Log中看出我們點擊了3次通過getCount()獲取了服務端的3個不同數據,
  • 最後點擊解除綁定,此時LocalService的onUnBind、onDestroy方法依次被回調,並且多次綁定只需一次解綁即可。
 
【3】bindService  的生命週期
  • 此情景也就說明了綁定狀態下的Service生命週期方法的調用依次爲onCreate()、onBind、onUnBind、onDestroy。
 
 
 
 
 
 
 
 
 
 
 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章