I have a common problem since the first day I start coding: avoid handling an event (button click,..) multiple times. Most of the time, I come up with a simple solution (which add a boolean flag to check) like this:
private boolean isProcessingClick = false;
#Override
public void onClick(View v) {
onLoginButtonClick();
}
private void onLoginButtonClick() {
if (isProcessingClick)
return;
isProcessingClick = true;
// Do something..
// Update some UIs..
isProcessingClick = false;
}
This worked fine. But as the class go bigger with more features & events everything started going wrong. We need to create too many boolean flags which doesn't mean anything about the business and should not be a field of this class.
Does anyone has better solution for this?
The restriction can be supported with a wrapper (if you need to protect click of each button independently).
class MyOnClickListener implements View.OnClickListener {
private final View.OnClickListener internal;
private final AtomicBoolean isProcessingClick = new AtomicBoolean();
public MyOnClickListener(View.OnClickListener internal) {
this.internal = internal;
}
#Override
public void onClick(View v) {
try {
boolean noProcessing = this.isProcessingClick.compareAndSet(false, true);
if(noProcessing) {
internal.onClick(v);
} else {
// it's good to show some alert for the user here
}
} finally {
isProcessingClick.set(false);
}
}
}
I'm not android developer so AtomicBoolean was used in case that 'onClick' could be invoked by different threads.
Related
So I'm using the Observer pattern in my app in order to get notified of changes in another class without having to look for them.
I have a Singleton class which extends Observable. Inside this class I have two CountDownTimer type variables. Eachs of these contains two methods: onTick() and onFinished().
Let's call those Timers A and B for the sake of simplicity.
Every time A.onTick(), A.onFinished(), B.onTick(), B.onFinished() are called, I must call notifyObservers() to notify my Observer that something has changed.
Until here everything works fine. The problem is that I know something has changed, but I don't know what exactly has changed. Depending on which one notified me, I must execute some code on the Observer side.
How do I know which of these methods notified me?
Use LiveData instead of Observable. LiveData is quite useful because not only it's observable but also it binds to your activity's lifecycle so you don't have to worry about handling it yourself.
Maybe this example will help you:
public class MyTimerWrapper {
public static MyTimerWrapper getInstance() {
// Your singleton logic
createTimers();
return instance;
}
private CountDownTimer timerA;
private CountDownTimer timerB;
private MutableLiveData<TimerEvent> timerALiveData = new MutableLiveData<TimerEvent>();
private MutableLiveData<TimerEvent> timerBLiveData = new MutableLiveData<TimerEvent>();
public LiveData<TimerEvent> startTimerA() {
timerA.start();
return timerALiveData;
}
public LiveData<TimerEvent> startTimerB() {
timerB.start();
return timerBLiveData;
}
private void createTimers() {
createTimerA();
createTimerB();
}
private void createTimerA() {
timerA = new CountDownTimer(30000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
// If you're running on another thread
timerALiveData.postValue(TimerEvent.TICK);
// Otherwise
timerALiveData.setValue(TimerEvent.TICK);
}
#Override
public void onFinish() {
// If you're running on another thread
timerALiveData.postValue(TimerEvent.FINISH);
// Otherwise
timerALiveData.setValue(TimerEvent.FINISH);
}
}
}
private void createTimerB() {
// Same as createTimerA, but with timerB
}
}
public enum TimerEvent {
TICK,
FINISH
}
Now to observe that data in your activity:
MyTimerWrapper timerWrapper = MyTimerWrapper.getInstance();
timerWrapper.startTimerA().observe(this, new Observer {
#Override
public void onChanged(TimerEvent timerEvent) {
// Here you'll be able to see whether timerA is ticking or finished
}
})
You can create a custom EventType class and pass it to Observable.notifyObservers(Object arg):
public class EventType {
String eventType; //"onTick" or "onFinish"
TimerType timerType;
EventType(String eventType, TimerType timerType){
this.eventType = eventType;
this.timerType = timerType;
}
}
TimerType is an enum type:
public enum TimerType {
A,
B;
}
and create TimerA and TimerB classes extending CountDownTimer:
private class TimerA extends CountDownTimer {
final EventType onTickEvent = new EventType("onTick", TimerType.A);
final EventType onFinishEvent = new EventType("onFinish", TimerType.A);
#Override
public void onTick(long millisUntilFinished) {
notifyObservers(onTickEvent);
}
#Override
public void onFinish() {
notifyObservers(onFinishEvent)
}
}
The Observerwill receive the EventType instance via its update(Observable o, Object arg); in the arg argument
I have a simple example of the add-on switch with vaadin, what I want is to keep the state of the switch even when I update the UI, that is, I support multiple tabs, but I can not do it, this push example is very similar to What I want to do but with a textField.
https://github.com/vaadin-marcus/push-example/blob/master/src/main/java/com/vaadin/training/ScrumBoardLayout.java
https://github.com/rucko24/MVP/blob/testingSwitchPushTemu/src/main/java/com/Core/vaadin/pushServer/ejemploPushMarkus/ScrumBoard.java
To my example I add a bulb so that when another accesses the application can see the current state of the bulb. My example in github is this with only 3 classes
https://github.com/rucko24/MVP/tree/testingSwitchPushTemu/src/main/java/com/Core/vaadin/pushServer/ejemploPushMarkus
This is the swithc listener that changes my bulb, but when I get the boolean value (true, or false), I still do not understand the right way to push the other switch
switchTemu.addValueChangeListener(new Property.ValueChangeListener() {
private static final long serialVersionUID = 1L;
#Override
public void valueChange(Property.ValueChangeEvent event) {
boolean estado = (boolean) event.getProperty().getValue();
ScrumBoard.addSwitch(estado);
switchTemu.removeValueChangeListener(this);
if(estado == Boolean.TRUE) {
bombilla.setIcon(bombillaON);
}else {
bombilla.setIcon(bombillaOFF);
}
switchTemu.addValueChangeListener(this);
}
});
Update
In my example github achievement, change the state of all switches to all UI, but I still do not know how to get the state of the switches
I made a couple of changes to your sources (still basic, but it gets you started):
only 1 common shared state
switch value change listeners now just trigger a state changed event
state changed listeners now update the UI elements when triggered
upon registration, a state changed listeners is informed (triggered) about the current state
The main idea is to have just a single shared state and any change is communicated to all the listeners (including the one where the change originated).
Below you can find the code: (P.S. I did not recompile my widgetset so the nice switch icon falls back to the default check box style)
1) SwitchState - represents the state of the switch shared between all the app instances
public enum SwitchState {
ON(true, new ThemeResource("img/on.png")), OFF(false, new ThemeResource("img/off.png"));
private final boolean value;
private final ThemeResource icon;
SwitchState(boolean value, ThemeResource icon) {
this.value = value;
this.icon = icon;
}
public boolean getValue() {
return value;
}
public ThemeResource getIcon() {
return icon;
}
public static SwitchState from(boolean value) {
return value ? ON : OFF;
}
}
2) ScrumBoard common state and listeners manager
public class ScrumBoard {
// list of listeners
private static List<SwitchChangeListener> LISTENERS = new ArrayList<>();
// initial state
private static SwitchState STATE = SwitchState.OFF;
// state change listener contract
public interface SwitchChangeListener {
void handleStateChange(SwitchState state);
}
// handle a a state change request
public static synchronized void updateState(boolean value) {
STATE = SwitchState.from(value);
fireChangeEvent(STATE);
}
// register a new state listener
public static synchronized void addSwitchChangeListener(SwitchChangeListener listener) {
System.out.println("Added listener for " + listener);
LISTENERS.add(listener);
// when a new listener is registered, also inform it of the current state
listener.handleStateChange(STATE);
}
// remove a state listener
public static synchronized void removeSwitchListener(SwitchChangeListener listener) {
LISTENERS.remove(listener);
}
// fire a change event to all registered listeners
private static void fireChangeEvent(SwitchState state) {
for (SwitchChangeListener listener : LISTENERS) {
listener.handleStateChange(state);
}
}
}
3) ScrumBoardLayout - UI layout and components
public class ScrumBoardLayout extends VerticalLayout implements ScrumBoard.SwitchChangeListener {
private Label icon = new Label();
private Switch mySwitch = new Switch();
public ScrumBoardLayout() {
setMargin(true);
setSpacing(true);
addHeader();
// listen for state changes
ScrumBoard.addSwitchChangeListener(this);
}
private void addHeader() {
mySwitch.setImmediate(true);
icon.setSizeUndefined();
// notify of state change
mySwitch.addValueChangeListener((Property.ValueChangeListener) event -> ScrumBoard.updateState((Boolean) event.getProperty().getValue()));
VerticalLayout layout = new VerticalLayout();
layout.setHeight("78%");
layout.addComponents(icon, mySwitch);
layout.setComponentAlignment(icon, Alignment.BOTTOM_CENTER);
layout.setComponentAlignment(mySwitch, Alignment.BOTTOM_CENTER);
layout.setExpandRatio(mySwitch, 1);
addComponents(layout);
}
#Override
public void handleStateChange(SwitchState state) {
// update UI on state change
UI.getCurrent().access(() -> {
mySwitch.setValue(state.getValue());
icon.setIcon(state.getIcon());
Notification.show(state.name(), Type.ASSISTIVE_NOTIFICATION);
});
}
#Override
public void detach() {
super.detach();
ScrumBoard.removeSwitchListener(this);
}
}
4) Result
I could see that with the ThemeResource () class, changing the bulb to its ON / OFF effect is strange, but I solve it as follows
.bombillo-on {
#include valo-animate-in-fade($duration: 1s);
width: 181px;
height: 216px;
background: url(img/on.png) no-repeat;
}
.bombillo-off {
#include valo-animate-in-fade($duration: 1s);
width: 181px;
height: 216px;
background: url(img/off.png) no-repeat;
}
public enum Sstate {
ON(true,"bombillo-on"),
OFF(false,"bombillo-off");
private boolean value;
private String style;
Sstate(boolean value, String style) {
this.value = value;
this.style = style;
}
public boolean getValue() { return value;}
public String getStyle() { return style;}
public static Sstate from(boolean value) { return value ? ON:OFF;}
}
And the handleChangeEvent It stays like this
#Override
public void handleChangeEvent(Sstate state) {
ui.access(() -> {
bombilla.setStyleName(state.getStyle());
s.setValue(state.getValue());
System.out.println(state+" values "+s);
});
}
UPDATE:
I notice an issue, that when I add a new view, or change using the buttonMenuToggle, it loses the synchronization, and update the bulb quite strange, clear with the themeResource does not happen that.
Solution:
to avoid UiDetachedException when using the Navigator try this, It works very well
#Override
public void handleChangeEvent(Sstate state) {
if(!ui.isAttached()) {
BroadcastesSwitch.removeListener(this);
return;
}
ui.access(() -> {
bombilla.setStyleName(state.getStyle());
s.setValue(state.getValue());
System.out.println(state+" values "+s);
});
}
Just find some information about non-blocking algorithms, so want to use them in practice. I changed some code from synchronized to non-blocking, so I want to ask does I made everything right and saved previous functionality.
synchronized code:
protected PersistentState persistentState;
protected ClassConstructor(final ID id)
{
super(id);
this.persistentState = PersistentState.UNKNOWN;
}
public final synchronized PersistentState getPersistentState()
{
return this.persistentState;
}
protected synchronized void setPersistentState(final PersistentState newPersistentState)
{
if (this.persistentState != newPersistentState)
{
this.persistentState = newPersistentState;
notifyPersistentStateChanged();
}
}
my alternative in non-blocking algorithm:
protected AtomicReference<PersistentState> persistentState;
protected ClassConstructor(final ID id)
{
super(id);
this.persistentState = new AtomicReference<PersistentState>(PersistentState.UNKNOWN);
}
public final PersistentState getPersistentState()
{
return this.persistentState.get();
}
protected void setPersistentState(final PersistentState newPersistentState)
{
PersistentState tmpPersistentState;
do
{
tmpPersistentState = this.persistentState.get();
}
while (!this.persistentState.compareAndSet(tmpPersistentState, newPersistentState));
// this.persistentState.set(newPersistentState); removed as not necessary
notifyPersistentStateChanged();
}
Do I've done everything correctly, or I missed something? Any suggestions for the code and using non-blocking method for setting abject in general?
Depends what you mean by thread-safe. What do you want to happen if two threads try to write at the same time? Should one of them chosen at random be chosen as the correct new value?
This would be it at it's simplest.
protected AtomicReference<PersistentState> persistentState = new AtomicReference<PersistentState>(PersistentState.UNKNOWN);
public final PersistentState getPersistentState() {
return this.persistentState.get();
}
protected void setPersistentState(final PersistentState newPersistentState) {
persistentState.set(newPersistentState);
notifyPersistentStateChanged();
}
private void notifyPersistentStateChanged() {
}
This would still call notifyPersistentStateChanged in all cases, even if the state hasn't changed. You need to decide what should happen in that scenario (one thread makes A -> B and another goes B -> A).
If, however, you need to only call the notify if successfully transitioned the value you could try something like this:
protected void setPersistentState(final PersistentState newPersistentState) {
boolean changed = false;
for (PersistentState oldState = getPersistentState();
// Keep going if different
changed = !oldState.equals(newPersistentState)
// Transition old -> new successful?
&& !persistentState.compareAndSet(oldState, newPersistentState);
// What is it now!
oldState = getPersistentState()) {
// Didn't transition - go around again.
}
if (changed) {
// Notify the change.
notifyPersistentStateChanged();
}
}
I have a case where a JComponent needs to have a listener added or removed depending on the state of other fields of a class. The listener should not be added more than once, and it can, of course, be removed only once. Is it a good practice to use a class field to store the listener and use the null value to control the action of registering/unregistering the listener with the Component.
The code I have in mind is something like this (code modified to make it clear that the JComponent is provided to the class):
public class MyClass {
private ActionListener fListener = null;
private JComponent fComponent;
public MyClass(JComponent component) {
fComponent = component; // for example, component = new JButton("Test");
}
public void setListener() {
if (fListener == null ) {
fListener = new MyListener();
fComponent.addActionListener(fListener);
}
}
public void removeListener() {
if (fListener != null) {
fComponent.removeActionListener(fListener);
fListener = null;
}
}
}
Do not instantiate and dispose listener object every time. Use getActionListeners() method to verify that listener is added or not.
public class MyClass {
private ActionListener fListener = new MyListener();
private JButton fComponent = new JButton("Test");
public MyClass() {
fComponent.addActionListener(fListener);
}
public void setListener() {
if (fComponent.getActionListeners().length == 0) {
fComponent.addActionListener(fListener);
}
}
public void removeListener() {
if (fComponent.getActionListeners().length !=0) {
fComponent.removeActionListener(fListener);
}
}
}
Method ActionListener[] getActionListeners() returns array of all the ActionListeners added to this JButton.
Is it absolutely necessary to continually add and remove the listener from the component? Can you just disable the component, or have a flag that you can use to determine if the action can be run?
Can you wrap the listener in another listener that you define? The enveloping listener can have a boolean switch you can flip to control delegation to the real listener.
If worse comes to worst and you absolutely have to remove and add the listener, you can do it as follows, with a twist on AVD's solution:
public void setListener() {
// java.util.List and java.util.Arrays
List<ActionListeners> listenerList = Arrays.asList(fComponent.getActionListeners());
if (!listenerList.contains(fListener) {
fComponent.addActionListener(fListener);
}
}
public void removeListener() {
List<ActionListeners> listenerList = Arrays.asList(fComponent.getActionListeners());
if (listenerList.contains(fListener) {
fComponent.removeActionListener(fListener);
}
}
I am currently implementing custom events and listeners according to the code posted below. I have been told that this is a very dirty implementation and that this needs to be changed. However, i am very new to java and android and do not see what is wrong with the current implementation. The way i have it below works and seems to be doing everything i needed it too. I was wondering if some people could please take a look at my code and make some suggestions on what i should change and what i am doing wrong. Taking my example and modifying it so that i can see what your talking about would be greatly appreciated.
Thanks in advance!
/* SmartApp.java */
public class SmartApp extends Activity
{
private ConnectDevice cD = new ConnectDevice();
private DataRobot dR = new DataRobot();
private DataBuilder dB = new DataBuilder();
private DataSender dS = new DataSender();
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.intro);
cD.addDataReceivedListener(new DataReceivedListener() {
#Override
public void dataReceivedReceived(DataReceivedEvent event) {
// TODO Auto-generated method stub
dR.analyzeData(event.getData());
}
});
dR.addDataAnalyzedListener(new DataAnalyzedListener() {
#Override
public void dataAnalyzedReceived(DataAnalyzedEvent event) {
// TODO Auto-generated method stub
dB.submitData(event.getData());
}
});
dB.addDataBuilderListener(new DataBuilderListener() {
#Override
public void dataBuilderReceived(DataBuilderEvent event) {
// TODO Auto-generated method stub
dS.sendData(event.getData());
}
});
}
}
/* ConnectDevice.java
* This class is implementing runnable because i have a thread running that is checking
* the contents of a socket. Irrelevant to events. */
public class ConnectDevice implements Runnable {
private List _listeners = new ArrayList();
private String data;
/* Constructor */
public ConnectDevice() {// does some socket stuff here, irrelevant to the events}
public void run() {// does some socket stuff here, irrelevant to the events}
public synchronized void addDataReceivedListener(DataReceivedListener listener) {
_listeners.add(listener);
}
public synchronized void removeDataReceivedListener(DataReceivedListener listener) {
_listeners.remove(listener);
}
private synchronized void fireDataReceivedEvent(String temp) {
DataReceivedEvent dRE = new DataReceivedEvent(this, temp);
Iterator listeners = _listeners.iterator();
while(listeners.hasNext()) {
((DataReceivedListener)listeners.next()).dataReceivedReceived(dRE);
}
}
public interface DataReceivedListener {
public void dataReceivedReceived(DataReceivedEvent event);
}
}
/* DataRobot.java */
public class DataRobot {
/* This class is for analyzing the data */
private List _listeners = new ArrayList();
private String data;
public boolean analyzeData(String temp) {
/* Analyze the data
* This function analyzes the data, as explained in the OP
* This function fires the analyzed data event when finished
* analyzing the data.
*/
data = temp;
fireDataAnalyzedEvent(data); // this fires the dataanalyzedevent
return true; //for now this will always return true
}
public synchronized void addDataAnalyzedListener(DataAnalyzedListener listener) {
_listeners.add(listener);
}
public synchronized void removeDataAnalyzedListener(DataAnalyzedListener listener) {
_listeners.remove(listener);
}
private synchronized void fireDataAnalyzedEvent(String temp) {
DataAnalyzedEvent dRE = new DataAnalyzedEvent(this, temp);
Iterator listeners = _listeners.iterator();
while(listeners.hasNext()) {
((DataAnalyzedListener)listeners.next()).dataAnalyzedReceived(dRE);
}
}
public interface DataAnalyzedListener {
public void dataAnalyzedReceived(DataAnalyzedEvent event);
}
}
/* DataBuilder.java */
public class DataBuilder {
private List _listeners = new ArrayList();
private String data;
public boolean submitData(String temp) {
/* Builds the data
* This function builds the data, as explained in the OP
* This function fires the databuilder data event when finished
* building the data.
*/
data = temp;
fireDataBuilderEvent(data); //firing the databuilder event when finished
return true;
}
public synchronized void addDataBuilderListener(DataBuilderListener listener) {
_listeners.add(listener);
}
public synchronized void removeDataBuilderListener(DataBuilderListener listener) {
_listeners.remove(listener);
}
private synchronized void fireDataBuilderEvent(String temp) {
DataBuilderEvent dRE = new DataBuilderEvent(this, temp);
Iterator listeners = _listeners.iterator();
while(listeners.hasNext()) {
((DataBuilderListener)listeners.next()).dataBuilderReceived(dRE);
}
}
public interface DataBuilderListener {
public void dataBuilderReceived(DataBuilderEvent event);
}
}
/* DataSender.java */
/* this class has no event, because it is done firing events at this point */
public class DataSender {
private String data;
public boolean sendData(String temp) {
data = temp;
return true;
}
}
Below here are the event objects for each event. I Have each of this defined in a separate file, not sure if that is good procedure or not.
/* DataReceivedEvent.java */
public class DataReceivedEvent extends EventObject{
private String data;
public DataReceivedEvent(Object source, String temp) {
super(source);
// TODO Auto-generated constructor stub
data = temp;
}
public String getData() {
// this function is just an accessor function
return data;
}
}
/* DataAnalyzedEvent.java */
public class DataAnalyzedEvent extends EventObject{
private String data;
public DataAnalyzedEvent(Object source, String temp) {
super(source);
// TODO Auto-generated constructor stub
data = temp;
}
public String getData() {
// this function is just an accessor function
return data;
}
}
/* DataBuilderEvent.java */
public class DataBuilderEvent extends EventObject {
private String data;
public DataBuilderEvent(Object source, String temp) {
super(source);
// TODO Auto-generated constructor stub
data = temp;
}
public String getData() {
// this function is just an accessor function
return data;
}
}
I would not say it is a "very dirty implementation". Using callbacks/observers/listeners is a good practice in my opinion.
When I write Android applications I like to layer it such that the "application" is plain old Java with no Android imports and could theoretically be used in a Swing app, a Java EE-based web site, etc. The "Android" part is strictly user interface.
What I use callbacks for is to allow the Android code to register interest in events that take place in the application. For example, in a Blackjack game, an Activity might call game.getDealer().playHand() to tell the application to perform the dealer hand play logic. As that logic executes in the application, events are fired like cardDrawn(card), cardFlipped(card), handTotalChanged(handTotal), etc. The Android part of the app listens to these and redraws things on the screen accordingly (but it knows nothing about Blackjack).
I actually just have my activities implement interfaces like CardListener, HandListener, etc. so they can receive the event directly (unlike how you do it), but your style isn't necessarily a bad way.
I agree with #SingleShot in theory, for the parts of your Android application that can be Android-agnostic, and so long as the overhead introduced by all the indirection layers does not slow the app down too much. IMHO, in many apps, there is relatively little that fits this description.
In another post, you proposed your above solution for one activity to communicate to another activity. In Android, activities aren't just some Java objects you can toss around willy-nilly. They are managed by the OS and have particular lifecycles. While the observer/observable pattern is quite delightful in some places, it is unsuitable where the observer/observable connection will create garbage collection problems. In particular, one activity cannot, and should not, be trying to hold some sort of listener interface on another activity.
Similarly, a clean observer/observable pattern may break down in the face of databases, threads, services, and other bits of Android reality.
So, in pure Java code, isolated from Android, what you have is probably OK. However, do not go around recommending it as solutions for Android-specific problems unless you know it will work for those Android-specific problems. And, when you start trying to make your code work in an Android app, please do not be shocked if you run into problems trying to make your textbook pattern implementation work within the constraints placed upon Android apps.