How I can Notify on Multiple variables update?
Is there any method to detect and separatenotifyObservers?
public class AnimalWeightObservable extends Observable {
public long animalId;
public long weigh;
public long getAnimalId() {
return animalId;
}
public AnimalWeightObservable setAnimalId(long animalId) {
this.animalId = animalId;
this.setChanged();
this.notifyObservers(animalId);
return this;
}
public long getWeigh() {
return weigh;
}
public AnimalWeightObservable setWeigh(long weigh) {
this.weigh = weigh;
this.setChanged();
this.notifyObservers(weigh);
return this;
}
}
How can detect witch variable has changed?
How about wrapping animalId and weight inside another type: for example AnimalProperty
class AnimalProperty<T> {
String propertyName;
T property;
AnimalProperty(String name, T property) {
this.propertyName = name;
this.property = property;
}
}
so your code would look like this:
public class AnimalWeightObservable extends Observable {
public AnimalProperty animalId;
public AnimalProperty weigh;
//...
//...
public AnimalWeightObservable setWeigh(AnimalProperty weigh) {
this.weigh = weigh;
this.setChanged();
this.notifyObservers(weigh);
return this;
}
}
then in the Observer's update(...) method switch on the propertyName to know which property is updated
Related
I recently got following example where we are passing the action name to the method as string and then the method decides the function that needs to be called.
is this a good way of solving problem or is there some better way as well
public static final String ACTION_CHARGING_REMINDER = "charging-reminder";
public static void executeTask(Context context, String action) {
if (ACTION_INCREMENT_WATER_COUNT.equals(action)) {
incrementWaterCount(context);
} else if (ACTION_DISMISS_NOTIFICATION.equals(action)) {
NotificationUtils.clearAllNotifications(context);
} else if(ACTION_CHARGING_REMINDER.equals(action)){
issueChargeReminder(context);
}
}
I'd do something like this. This can be extended as much as you want, and obviously just an example:
static abstract class ActionHandler {
private String action;
public ActionHandler(String action) {
this.action = action;
}
public boolean canHandleAction(String input) {
return this.action.equals(input);
}
public abstract void handleAction();
}
static class OneActionHandler extends ActionHandler {
public OneActionHandler(String action) {
super(action);
}
#Override
public void handleAction() {
//...
}
}
static class TwoActionHandler extends ActionHandler {
public TwoActionHandler(String action) {
super(action);
}
#Override
public void handleAction() {
//...
}
}
static class Test {
private ActionHandler[] handlers;
public Test() {
handlers = new ActionHandler[]{new OneActionHandler("action1"), new TwoActionHandler("action2")};
}
public void handleAction(String action) {
for(ActionHandler i : handlers) {
if(i.canHandleAction(action)) {
i.handleAction();
break;
}
}
}
}
This sounds a lot like the react/redux, action/reduction pattern.
Reducers specify how the application's state changes in response to
actions sent to the store. Remember that actions only describe what
happened, but don't describe how the application's state changes.
I would like to observe a #Bindable via Java, is it possible?
I read that I can observe a ObservableField on this answer:
https://stackoverflow.com/a/31885802/858257
But sometimes you need the primitive field and the best approach is using a #Bindable.
Sure you can. If you have a field marked with #Bindable and implement Observable, you can listen for changes to that field. Any bindable field must notify when changed. For example:
public class Item extends BaseObservable {
private String name;
private int stockCount;
#Bindable
public String getName() { return name; }
public void setName(String name) {
this.name = name;
notifyPropertyChanged(BR.name);
}
#Bindable
public int getStockCount() { return stockCount; }
public void setStockCount(int stockCount) {
this.stockCount = stockCount;
notifyPropertyChanged(BR.stockCount);
}
}
You can then listen for changes on this object. I used BaseObservable as the base class for this data class because it implements the observability for me.
public void listenForStockChange(Item item) {
item.addOnPropertyChangedCallback(new OnPropertyChangedCallback() {
#Override
public void onPropertyChanged(Observable sender, int propertyId) {
if (propertyId == BR.stockCount) {
Item item = (Item) sender;
// Do whatever you want when the stock changes
}
}
});
}
I have the following code:
/**
* Request wrapped around flowable.
*/
public abstract class RequestFlowable<T> {
private final PublishProcessor<String> mPublish;
private String mName;
public RequestFlowable(String name) {
mName = name;
mPublish = PublishProcessor.create();
}
public Flowable<T> getFlowable() {
//return createAction();
return mPublish.compose(new FlowableTransformer<String, T>() {
#Override
public Publisher<T> apply(#NonNull Flowable<String> upstream) {
return createAction();
}
});
/*
return mPublish.flatMap(new Function<String, Publisher<? extends T>>() {
#Override
public Publisher<? extends T> apply(#NonNull String s) throws Exception {
return createAction();
}
});
*/
}
protected abstract Flowable<T> createAction();
public String getName() {
return mName;
}
public void start() {
mPublish.onNext("processCommand");
}
#Override
public String toString() {
return "Request: " + mName;
}
}
Now for Single
#EDIT 2
public abstract class Request<T> {
private final SingleSubject<Object> mPublish;
private String mName;
public Request(String name) {
mName = name;
mPublish = SingleSubject.create();
}
public Single<T> getSingle() {
return mPublish.flatMap(o -> createAction());
}
protected abstract Single<? extends T> createAction();
public String getName() {
return mName;
}
public void start() {
mPublish.onSuccess("Start");
}
#Override
public String toString() {
return "Request: " + mName;
}
}
The code from the above works when used with compose, like in code from above but, if instead I put the commented code - aka flatMap for some reason createAction is not executed.
EDIT 2
The code from the above is called from another class. The corresponding code is attached below(important parts of class added):
public class RequestQueue implements RequestController {
private static final String TAG = RequestQueue.class.getSimpleName();
private PublishSubject<Request> mRequest;
private PublishSubject<RequestFlowable> mRequestFlowable;
#Override
public <T> Single<T> registerRequest(Request<T> request) {
mRequest.onNext(request);
return request.getSingle();
}
#Override
public <T> Flowable<T> registerRequestFlowable(RequestFlowable<T> request) {
mRequestFlowable.onNext(request);
return request.getFlowable();
}
public RequestQueue() {
mRequest = PublishSubject.create();
mRequestFlowable = PublishSubject.create();
mRequest.subscribe(this::actionOnRequest);
mRequestFlowable.subscribe(this::actionOnRequest);
}
private void actionOnRequest(Request request) {
Log.d(TAG, "actionOnRequest() called with: request = [" + request + "]");
request.start();
}
private void actionOnRequest(RequestFlowable request) {
Log.d(TAG, "actionOnRequest() called with: request = [" + request + "]");
request.start();
}
}
(From my comments:)
Why does Single work?
SingleSubject retains the single terminal event it received. Since it can only receive onSuccess and onError, it will "replay" that to late subscribers (also this is why there is no separater ReplaySingleSubject). When you call onSuccess on the SingleSubject, that value is remembered and promplty reemitted when the later subscription happens, calling your createAction. PublishProcessor also remembers its terminal events but onNext is not a terminal event, hence dropped without consumer.
How can the desired behavior be achieved via Processor?
You could reorganize your logic, use BehaviorProcessor or ReplayProcessor.createWithSize(1). Calling onComplete won't execute the flatMap function either.
I have a listener:
public interface OnCompleteListener<T> {
void onComplete(T data);
}
I store it in list:
private List<OnCompleteListener<?>> mListeners = new ArrayList<>();
// ...
public void addType1Listener() {
addListener(new OnCompleteListener<Type1>() {
//...
});
}
public void addType2Listener() {
addListener(new OnCompleteListener() {
//...
});
}
private <T> void addListener(OnCompleteListener<T> listener) {
mListeners.add(listener);
}
I am trying to get it by this way:
public <T> OnRequestsCompleteListener<T> get(int i) {
return (OnRequestsCompleteListener<T>) mListeners.get(i);
}
Type1 and Type2 have no parent class and cannot have.
But I get 'unchecked cast' warning. How to get it correctly?
Instead of specifying genetic T in a method, you need a class with generic T
public class ListenerCollection <T> {
private List<OnCompleteListener<T>> mListeners = new ArrayList<OnCompleteListener<T>>();
public void addListener(OnCompleteListener<T> listener) {
mListeners.add(listener);
}
public OnCompleteListener<T> get(int i) {
return mListeners.get(i);
}
}
Suppose you have a class OnRequestCompleteListener, implemening OnCompleteListener<String>. Then you do:
ListenerCollection<String> lcollection;
...........
OnRequestCompleteListener newListener = (OnRequestCompleteListener) lcollection.get(i);
That doesn't give any warning.
I have my Class Adapter , and I need to have the access of two class ! Then I can put public class JSONAdapter extends ArrayAdapter<Voiture> { for have access in my class " Voiture " but I need to have the acceesss in my class "Moniteur" too , and I can"t put that :
public class JSONAdapter extends ArrayAdapter<Voiture>,ArrayAdapter<Moniteur> {
I need to view attributes of my class " Voiture " and " Moniteur " ...
Do you have the solution for me please ? Thanks
EDIT : Ok thanks you , this is the code of my class VOITURE :
public class Voiture {
private int idV = -1; // permet de voir si le parent est enregistré dans la BDD
private String marqueV;
private String dateAchatV;
private String PlaqueImmatriculationV;
public Voiture(String marqueV, String plaqueImmatriculationV) {
this.marqueV = marqueV;
PlaqueImmatriculationV = plaqueImmatriculationV;
}
public Voiture(JSONAdapter jsonAdapter) {
this.marqueV = marqueV;
this.PlaqueImmatriculationV = PlaqueImmatriculationV;
}
public int getIdV() {
return idV;
}
public void setIdV(int idV) {
this.idV = idV;
}
public String getMarqueV() {
return marqueV;
}
public void setMarqueV(String marqueV) {
this.marqueV = marqueV;
}
public String getDateAchatV() {
return dateAchatV;
}
public void setDateAchatV(String dateAchatV) {
this.dateAchatV = dateAchatV;
}
public String getPlaqueImmatriculationV() {
return PlaqueImmatriculationV;
}
public void setPlaqueImmatriculationV(String plaqueImmatriculationV) {
PlaqueImmatriculationV = plaqueImmatriculationV;
}
}
This is the code of my class Moniteur :
public class Moniteur {
private int idM;
private String nomM;
private String prenomM;
private String adresseM;
private String telephoneM;
public Moniteur(String nomM, String prenomM,String adresseM,String telephoneM) {
this.nomM = nomM;
this.prenomM = prenomM;
this.adresseM = adresseM;
this.telephoneM = telephoneM;
}
public int getIdM() { return idM; }
public void setIdM(int idM) { this.idM = idM; }
public String getNomM() {
return nomM;
}
public void setNomM(String nomM) {
this.nomM = nomM;
}
public String getPrenomM() {
return prenomM;
}
public void setPrenomM(String prenomM) {
this.prenomM = prenomM;
}
public String getAdresseM() {
return adresseM;
}
public void setAdresseM(String adresseM) {
this.adresseM = adresseM;
}
public String getTelephoneM() {
return telephoneM;
}
public void setTelephoneM(String telephoneM) {
this.telephoneM = telephoneM;
}
}
The purpose of these two classes and how they relate is not clear, but if you want to store both of them in a single container (which is what you are trying to do) you will need to define a common interface between them (or an abstract class). I don't speak French so you will have a easier time creating a good name.
I suggest creating an interface:
public interface AbstractItem
{
//TODO define common functions in this class
}
then implement this interface in your classes:
public class Voiture implements AbstractItem
{ ... }
public class Moniteur implements AbstractItem
{ ... }
Then, you can create an array adapter that will hold both of these items:
public class JSONAdapter extends ArrayAdapter<AbstractItem>
{ ... }
If I understand correctly, "Voiture" means "car" and "Moniteur" means "instructor" or "teacher".
So, it sounds like you are implementing a type of "driving school" where there are teachers with cars that they use/drive.
If that is the case, you really only need an ArrayAdapter<Monituer> and you could implement your Moniteur class like so.
public class Moniteur {
private List<Voiture> voitures;
public Monituer() {
voitures = new ArrayList<Voiture>();
}
public void ajouterVoiture(Voiture v) {
voitures.add(v);
}
public List<Voiture> obtientVoitures() {
return voitures;
}
}
Or maybe I don't understand what is trying to be displayed in the adapters. In that case, feel free to comment below.