?

Log in

Жизнь прекрасна и удивительна
Android Bound Service 
17-окт-2016 03:58 pm
Робот. Книжку вот чтает...

Я сейчас занят пинанием хуев в рабочее время повышением квалификации и исследовательской работой.

Набрел на ряд решений которые мне кажутся очень удачными.

Вот например интересный вариант реализации boundService на RX для Андроид.

Решение из этого широко известного гайда обладает одним большим и рядом мелких недостатков. Большой в том, что в ходе работы активности мы ничего не можем сказать о подключении сервиса. И нам приходится использовать безумное количество хендлеров, либо ставить проверку перед каждым вызовом. Кроме того это решение весьма тяжеловесно и негибко.

Вот более интересный способ:


public abstract class BoundService extends Service {

  private IBinder binder = new ServiceBinder(this);

  @Override
  public IBinder onBind(Intent intent) {
    return binder;
  }
}



public class ServiceBinder extends Binder {

  private BoundService service;

  public ServiceBinder(BoundService service) {
    this.service = service;
  }

  public BoundService getService() {
    return service;
  }
}



public class ServiceConnector <T extends BoundService> {

  public abstract class LocalBinder extends Binder {
    public abstract Service getService();
  }

  private BehaviorSubject<T> serviceSubject = BehaviorSubject.create();
  private BoundServiceConnection boundServiceConnection = new BoundServiceConnection();

  public ServiceConnector(Context context, Class<T> tClass) {

    Intent orderServiceIntent = new Intent(context, tClass);
    context.bindService(orderServiceIntent,
        boundServiceConnection, Context.BIND_AUTO_CREATE);

    serviceSubject.subscribe(s -> {
    }, t -> {
    }, () -> context.unbindService(boundServiceConnection));
  }



  private class BoundServiceConnection implements ServiceConnection {
    @Override
    public void onServiceConnected(ComponentName name, IBinder binder) {
      Service service = ((ServiceBinder) binder).getService();
      serviceSubject.onNext((T) service); // May produce Class cast Exception
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
      serviceSubject.onCompleted();
    }
  }

  public Observable<T> getService() {
    return serviceSubject.first();
  }

  public BehaviorSubject<T> getBehavior() {
    return serviceSubject;
  }
}


Чтобы все собралось добавляем в Градл скрипт лямбды и саму RX
apply plugin: 'me.tatarka.retrolambda'

buildscript {
    dependencies {
        classpath 'me.tatarka:gradle-retrolambda:3.2.3'
    }
}

android {

dependencies {

    compile 'io.reactivex:rxjava:1.1.6'
    compile group: 'io.reactivex', name: 'rxandroid', version: '1.2.1'
  }
}

В первых 2 классах нет ничего необычного. Они цельнотянуты со стека. Третий класс реализует подключение к сервису на RX. Идея проста: Вместо лисенеров "onServiceConnected" мы используем бехевиор, который выполняет за нас всю нудную работу отслеживания состояний.

Как это использовать?


Создадим новый сервис:


public class SimpleService extends BoundService {

  public static class Connector extends ServiceConnector<SimpleService> {
    public Connector(Context context) {
      super(context, SimpleService.class);
    }
  }

}



В активности подключаем его:


  private Observable<SimpleService> simpleService;
  public void onCreate(Bundle savedInstanceState) {
...
    simpleService = new SimpleService.Connector(this).getService();
 }



И все. Можно работать с сервисом:


 simpleService.subscribe(service -> {
      Log.v(TAG, service.getPackageCodePath()); // например
    });



Все RX фишки здесь прекрасно работают. Например:


simpleService.map(SimpleService::getCloningDataType).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
        .subscribe(data -> Log.v(TAG,data));




Как видно это гораздо проще чем создавать ServiceConnection а потом отслеживать все его состояния.
This page was loaded фев 26 2017, 2:42 pm GMT.