menawi
menawi

Reputation: 399

Migrating from java.lang.Observable to RxJava

I'm working on an Android application that features a shopping cart. The Cart object extends java.lang.Observable so if there are any changes, they are saved to the disk immediately and also so that the badge icon can be updated.

public class Cart extends Observable{

    private Set<Product> products;

    public Cart(){
        products = new HashSet<>();
    }

    public Cart(Collection<Product> products){
        this.products = new HashSet<>(products);
    }

    public int getTotalItems() {
        return products.size();
    }

    public void clear(){
        products.clear();
        setChanged();
        notifyObservers();
    }

    public void addProduct(Product product){
        products.add(product);
        setChanged();
        notifyObservers();
    }

    public void removeProduct(Product product){
        products.remove(product);
        setChanged();
        notifyObservers();
    }

    public void updateProduct(Product product){
        products.remove(product);
        products.add(product);
        setChanged();
        notifyObservers();
    }

    public List<Product> getProducts() {
        return new ArrayList<>(products);
    }
}

Example usage

public class MainActivity extends BaseActivity implements Observer {
    Cart mCart;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);

        getApp().getCart().addObserver(this);
        setCartItemsCount(getApp().getCart().getTotalItems());

        //...
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (getApp().getCart() != null) {
            getApp().getCart().deleteObserver(this);
        }
    }

    @Override
    public void update(Observable observable, Object data) {
        if (observable instanceof Cart) {
            setCartItemsCount(((Cart) observable).getTotalItems());
        }
    }
}

I'd like to migrate this code to RxJava but i don't have a clear idea on how to go about it. From what I read, I'm supposed to use BehavioralSubject but I don't know how to adapt the examples I've read to my scenario.

I would appreciate if some guidance or an example.

Upvotes: 0

Views: 254

Answers (1)

Rzodkiewka
Rzodkiewka

Reputation: 410

I made some small example that can help you catch the idea. I have used this library https://github.com/trello/RxLifecycle, I also recommend you to use this http://google.github.io/dagger/

public class MainActivity extends RxActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    final CartPresenter cartPresenter = new CartPresenter();
    final TextView counterTextView = (TextView) findViewById(R.id.counter);
    final Button button = (Button) findViewById(R.id.button2);

    RxView.clicks(button)
            .subscribe(new Action1<Void>() {
                @Override
                public void call(Void aVoid) {
                    cartPresenter.getCardModel().addProduct(new Random().nextInt(100));
                }
            });

    cartPresenter.getCardObservable()
            .compose(this.<CartPresenter.CardModel>bindToLifecycle())
            .subscribe(new Action1<CartPresenter.CardModel>() {
                @Override
                public void call(CartPresenter.CardModel cardModel) {
                    counterTextView.setText(String.valueOf(cardModel.getProducts().size()));
                }
            });
}
}

One solution simpler to understand for a beginner

public class CartPresenter {

    private final PublishSubject<CardModel> dataChangedSubject = PublishSubject.create();
    private final Observable<CardModel> cardObservable;
    private final CardModel cardModel;

    public CartPresenter() {
        cardModel = new CardModel();

        this.cardObservable = dataChangedSubject.startWith(cardModel)
                .flatMap(new Func1<CardModel, Observable<CardModel>>() {
                    @Override
                    public Observable<CardModel> call(CardModel cardModel) {
                        return Observable.just(cardModel);
                    }
                });
    }

    public CardModel getCardModel() {
        return cardModel;
    }

    @NonNull
    public Observable<CardModel> getCardObservable() {
        return cardObservable;
    }

    class CardModel {
        final private Set<Integer> products;

        public CardModel() {
            this.products = new HashSet<>();
        }

        public void addProduct(Integer integer) {
            products.add(integer);
            dataChangedSubject.onNext(this);
        }

        public Set<Integer> getProducts() {
            return products;
        }
    }
}

And for some more advanced users

public class CartPresenter {

    private final PublishSubject<CardModel> dataChangedSubject = PublishSubject.create();
    private final Observable<CardModel> cardObservable;
    private final CardModel cardModel;

    public CartPresenter() {
        cardModel = new CardModel();

        this.cardObservable = Observable.just(cardModel)
                .compose(new Observable.Transformer<CardModel, CardModel>() {
                    @Override
                    public Observable<CardModel> call(final Observable<CardModel> cardModelObservable) {
                        return dataChangedSubject.switchMap(new Func1<Object, Observable<? extends CardModel>>() {
                            @Override
                            public Observable<? extends CardModel> call(Object o) {
                                return cardModelObservable;
                            }
                        });
                    }
                });

    }

    public CardModel getCardModel() {
        return cardModel;
    }

    @NonNull
    public Observable<CardModel> getCardObservable() {
        return cardObservable;
    }

    class CardModel {
        final private Set<Integer> products;

        public CardModel() {
            this.products = new HashSet<>();
        }

        public void addProduct(Integer integer) {
            products.add(integer);
            dataChangedSubject.onNext(null);
        }

        public Set<Integer> getProducts() {
            return products;
        }
    }
}

Upvotes: 1

Related Questions