Android Service のバインド実行を綺麗に

Android Service をバインドして Serviceメソッドを呼び出すのは、、
  ・bindService の実行と実際に Service メソッドを call 可能になるのは非同期であること。
  ・バインドして呼びだすクラスの記述量が大きくなりやすい。

これらを解決したくて、まずはAIDL使用しないケースで考えてみました。

Service実装側の Binder に1つインターフェースを被せる

import android.app.Service;
import android.os.IBinder;
/**
 * ITransitBinder
 */
public interface ITransitBinder extends IBinder{
   public Service getService();
}


このインタフェースは、Serviceをバインド取得する時に使う。
Service 側は、以下のように、Binderから、自身のServiceを取得できるように用意する。

public class SampleService extends Service {
   private final IBinder mBinder = new MyServiceBinder();

   class MyServiceBinder extends Binder implements ITransitBinder{
      @Override
      public SampleService getService(){
         return SampleService.this;
      }

   }

   @Override
   public IBinder onBind(Intent intent){
      return mBinder;
   }
   // 他は省略
}

Serviceをバインドする側のためのインターフェース、これが鍵である。

public interface IServiceProcessor<T extends android.app.Service>{
   public void process(T service);
}


これは、例として、、
呼び出す Activity で以下のようにするだけで呼び出す目的のインターフェースである。

   ServiceClient serviceClient = new ServiceClient(this, SampleService.class);
   serviceClient.execute(new IServiceProcessor<SampleService>(){
      @Override
      public void process(SampleService service){


         // 総称型で指定する Service 継承クラスのメソッドを実行する

      }
   }
);

この ServiceClient の正体は、、、

import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
/**
 * ServiceClient
 */

public final class ServiceClient{
   Context mContext;
   private Class<? extends Service> mServiceClass;
   Service mBoundService;
   IServiceProcessor mProcessor;

   public ServiceClient(Context context, Class<? extends Service> serviceClass){
      mContext = context;
      mServiceClass = serviceClass;
   }

   public void execute(IServiceProcessor processor){
      mProcessor = processor;
      mContext.bindService(new Intent(mContext,mServiceClass), mConnection, Context.BIND_AUTO_CREATE);
   }

   ServiceConnection mConnection = new ServiceConnection(){
      @SuppressWarnings("unchecked")
      @Override
      public void onServiceConnected(ComponentName name,IBinder binder){
         mBoundService = ((ITransitBinder)binder).getService();
         mProcessor.process(mBoundService);
         mContext.unbindService(mConnection);
      }
      @Override
      public void onServiceDisconnected(ComponentName name){
         mBoundService = null;
      }
   };
}