俺言語。

自分にしか理解できない言語で書かれた備忘録

【Android】BindServiceの使い方

ServiceにはIntent ServiceとBindServiceがあり、それぞれの特徴は下記、

IntentService

  • UIスレッドとは別のスレッドで作動する
  • 実装が比較的楽そう
  • 呼び出し元のActivityが破棄されても実行し続ける

BindService

  • UIスレッドで動く..(2)
  • 実装が少しめんどくさい
  • 呼び出し元のActivityが破棄されると一緒に終了する...(1)


ここで呼び出し元のActivityが破棄されると一緒に終了するという特徴(1)が
アプリが終了しても変にサービスが残らなくていいかと思い、BindServiceを採用。

しかしのちに(2)の結局はUIスレッドで動作するという結果を知る.
よってBindServiceではUIの描画を妨げる程の思い動作には向いていないと思われるので注意.

使い方

呼び出し元

1. ServiceConnectionクラスのインターフェイスを実装したサブクラスを作成.

その中に onServiceConnected と onServiceDisconnected をOverrideする.
onServiceConnected内に呼び出し先で定義したBinderクラスを継承した独自クラスのインスタンスを受け取る


2. bindService()でServiceを起動する. bindServiceメソッドはContextクラスのため何もせずそのまま呼び出せる.


呼び出し先
1. Serviceを継承する.

2. onBindメソッドを継承する。これは最初にbindServiceされたときに呼ばれる。
ここでBinderクラスを継承した独自クラスのオブジェクトを返す.

3. Binderクラスを継承した独自クラスを定義する
ここにデータや処理を記述することで呼び出し元がbinderオブジェクトを通して操作できる

4. onCreate, onRunError, onUnbind, OnDestroyメソッドをOverrideする。

参考例はこちら
MainActivity.java (呼び出し元)

public class MainActivity extends AppCompatActivity {

    // ServiceConnection object class
    private ServiceConnection conn = new ServiceConnection() {
        // callback for connection successful
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            System.out.println("Service connected");
            // onBindされたときにbinderが返される。このbinderにサービス側で処理やデータを格納しておいて使う側が呼び出す
            binder = (BindServiceSensorHandling.MyBinder) iBinder;
        }
        // callback for connection unsuccessful
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            System.out.println("Service disconnected");
        }
    };

        findViewById(R.id.button4).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //サービスがすでに動いているかをチェック
                ActivityManager manage = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
                for(ActivityManager.RunningServiceInfo serviceInfo : manage.getRunningServices(Integer.MAX_VALUE))
                    if(BindServiceSensorHandling.class.getName().equals(serviceInfo.service.getClassName())){
                        // 動いている場合は一回unBindする
                        unbindService(conn);
                    }
                // Bind BindService
                // Intent for MainActivity with Bind service
                final Intent intent = new Intent(MainActivity.this, BindServiceSensorHandling.class);
                bindService(intent, conn, Service.BIND_AUTO_CREATE);
            }
        }
}

BindServiceSensorHandling.java (呼び出し先)

public class BindServiceSensorHandling extends Service{

    // onBind()で返されるBinder
    private MyBinder binder;

    /*
    最初のbindService呼び出しのみ、システムにIBinderインターフェースを渡すために呼ばれる。
     */
    @Override
    public IBinder onBind(Intent intent) {
        System.out.println("Service is binded");
        binder = new MyBinder();
        return binder;
    }

     /*
     Serviceのインスタンスがない状態で、クライアントがstartServiceまたはbindServiceを呼んだ時に
     *Serviceのインスタンス生成で呼ばれる。すでにインスタンスが存在している場合は呼ばれない。
     */
    @Override
    public void onCreate() {}

    /*
     onBind()で返されるbindeオブジェクト. ここに処理やデータを記述する。
     */
    public class MyBinder extends Binder {

        boolean sendRequest(int req){
            String buf = String.valueOf(req);
            try {
                usbSerialPort.write(buf.getBytes(), WRITE_WAIT_MILLIS);
                return true;
            }catch (IOException e){
                Log.e(TAG, "Mode request error");
                return false;
            }
        }
    }
    @Override
    public void onRunError(Exception e) {
        Log.d(TAG, "Runner stopped");
    }

    /*バインドしているクライアントが「全て」いなくなったときに呼ばれる。そのためunbindServiceが呼ばれても、
     *ほかにバインドしているクライアントが存在した場合、onUnbindは呼ばれない。
     */
    @Override
    public boolean onUnbind(Intent intent) {
        disconnect();
        System.out.println("System is unbined");
        return true;
    }

    //バインドされたクライアントがなくなって、onUnbindが呼ばれたあとに呼ばれる
    @Override
    public void onDestroy() {
        System.out.println("Service is destroyed");
        this.quit = true;
    }
}