package com.trovebox.android.common.utils.lifecycle;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import android.content.Intent;
import android.os.Bundle;
import com.trovebox.android.common.util.CommonUtils;
import com.trovebox.android.common.util.RunnableWithParameter;
/**
* Lifecycle event handler. Stores event listener and can fire events to them
*
* @author Eugene Popovich
*/
/**
* @author Eugene
*/
public class LifecycleEventHandler {
private static final String TAG = LifecycleEventHandler.class.getSimpleName();
String holderClassName;
/**
* the registered listeners
*/
private List<LifecycleListener> listeners = new ArrayList<LifecycleListener>();
/**
* the pending listeners to remove list
*/
private List<LifecycleListener> listenersToRemove = new ArrayList<LifecycleListener>();
/**
* the work indicator
*/
private AtomicInteger workers = new AtomicInteger(0);
void trackEvent(String event) {
CommonUtils.debug(TAG, event + ": " + holderClassName);
}
public LifecycleEventHandler(Object holder) {
if (holder == null) {
throw new IllegalArgumentException("holder argument should not be null");
}
this.holderClassName = holder.getClass().getSimpleName();
}
/**
* Add the lifecycle listener
*
* @param listener
*/
public void addLifecycleListener(LifecycleListener listener) {
trackEvent("addLifecycleListener");
synchronized (listeners) {
trackEvent("addLifecycleListener.Synchronized");
listeners.add(listener);
}
}
/**
* Remove the lifecycle listener
*
* @param listener
*/
public void removeLifecycleListener(LifecycleListener listener) {
trackEvent("removeLifecycleListener");
try {
if (workers.getAndIncrement() == 0) {
trackEvent("removeLifecycleListener. No pending work, removing listener");
synchronized (listeners) {
trackEvent("removeLifecycleListener. No pending work, removing listener. Synchronized");
listeners.remove(listener);
}
} else {
trackEvent("removeLifecycleListener. Where is pending work, adding listener to delayed removal");
synchronized (listenersToRemove) {
CommonUtils
.debug(TAG,
"removeLifecycleListener. Where is pending work, adding listener to delayed removal. Synchronized");
listenersToRemove.add(listener);
}
}
} finally {
workers.decrementAndGet();
}
}
/**
* Fire event occurred
*
* @param runnable
*/
private void fireEventOccurred(RunnableWithParameter<LifecycleListener> runnable) {
workers.getAndIncrement();
try {
for (LifecycleListener listener : listeners) {
if (!listenersToRemove.contains(listener)) {
runnable.run(listener);
}
}
} finally {
workers.decrementAndGet();
}
performListenersRemoval();
}
/**
* Process listeners waiting for removal
*/
private void performListenersRemoval() {
try {
if (workers.getAndIncrement() == 0) {
trackEvent("performListenersRemoval. Performing delayed listeners removal");
synchronized (listeners) {
trackEvent("performListenersRemoval. Performing delayed listeners removal. Synchronized listeners");
synchronized (listenersToRemove) {
CommonUtils
.debug(TAG,
"performListenersRemoval. Performing delayed listeners removal. Synchronized listenersToRemove");
trackEvent("performListenersRemoval. Synchronized lists for removal");
if (listenersToRemove.isEmpty()) {
CommonUtils
.debug(TAG,
"performListenersRemoval. Listeners to remove are empty. Skipping");
} else {
for (LifecycleListener listener : listenersToRemove) {
trackEvent("performListenersRemoval. Removing listener");
listeners.remove(listener);
}
trackEvent("performListenersRemoval. Clearing listenersToRemove");
listenersToRemove.clear();
}
}
}
}
} finally {
workers.decrementAndGet();
}
}
/**
* Should be called on the holder onStart() method. This will fire onStart
* event to all registered event listeners
*/
public void fireOnStartEvent() {
trackEvent("fireOnStartEvent");
fireEventOccurred(onStartRunnable);
}
/**
* Should be called on the holder onStop() method. This will fire onStop
* event to all registered event listeners
*/
public void fireOnStopEvent() {
trackEvent("fireOnStopEvent");
fireEventOccurred(onStopRunnable);
}
/**
* Should be called on the holder onSaveInstanceState() method. This will
* fire onSaveInstanceState event to all registered event listeners
*/
public void fireOnSaveInstanceStateEvent(final Bundle outState) {
trackEvent("fireOnSaveInstanceStateEvent");
onSaveInstanceStateRunnable.outState = outState;
fireEventOccurred(onSaveInstanceStateRunnable);
}
/**
* Should be called on the holder onCreate() method. This will fire onCreate
* event to all registered event listeners
*/
public void fireOnCreateEvent(final Bundle savedInstanceState) {
trackEvent("fireOnCreateEvent");
onCreateRunnable.savedInstanceState = savedInstanceState;
fireEventOccurred(onCreateRunnable);
}
/**
* Should be called on the holder onDestroy() method. This will fire
* onDestroy event to all registered event listeners
*/
public void fireOnDestroyEvent() {
trackEvent("fireOnDestroyEvent");
fireEventOccurred(onDestroyRunnable);
}
/**
* Should be called on the holder onResume() method. This will fire onResume
* event to all registered event listeners
*/
public void fireOnResumeEvent() {
trackEvent("fireOnResumeEvent");
fireEventOccurred(onResumeRunnable);
}
/**
* Should be called on the holder onPause() method. This will fire onPause
* event to all registered event listeners
*/
public void fireOnPauseEvent() {
trackEvent("fireOnPauseEvent");
fireEventOccurred(onPauseRunnable);
}
/**
* Should be called on the holder onActivityResult() method. This will fire
* onActivityResult event to all registered event listeners
*/
public void fireOnActivityResultEvent(final int requestCode, final int resultCode,
final Intent data) {
trackEvent("fireOnActivityResultEvent");
onActivityResultRunnable.requestCode = requestCode;
onActivityResultRunnable.resultCode = resultCode;
onActivityResultRunnable.data = data;
fireEventOccurred(onActivityResultRunnable);
}
/**
* On start runnable which is used on fire method
*/
RunnableWithParameter<LifecycleListener> onStartRunnable = new RunnableWithParameter<LifecycleListener>() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onStartRunnable.run");
listener.onStart();
}
};
/**
* On stop runnable which is used on fire method
*/
RunnableWithParameter<LifecycleListener> onStopRunnable = new RunnableWithParameter<LifecycleListener>() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onStopRunnable.run");
listener.onStop();
}
};
/**
* On save instance state runnable which is used on fire method
*/
OnSaveInstanceStateRunnable onSaveInstanceStateRunnable = new OnSaveInstanceStateRunnable() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onSaveInstanceStateRunnable.run");
super.run(listener);
}
};
/**
* On create runnable which is used on fire method
*/
OnCreateRunnable onCreateRunnable = new OnCreateRunnable() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onCreateRunnable.run");
super.run(listener);
}
};
/**
* On destroy runnable which is used on fire method
*/
RunnableWithParameter<LifecycleListener> onDestroyRunnable = new RunnableWithParameter<LifecycleListener>() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onDestroyRunnable.run");
listener.onDestroy();
}
};
/**
* On resume runnable which is used on fire method
*/
RunnableWithParameter<LifecycleListener> onResumeRunnable = new RunnableWithParameter<LifecycleListener>() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onResumeRunnable.run");
listener.onResume();
}
};
/**
* On pause runnable which is used on fire method
*/
RunnableWithParameter<LifecycleListener> onPauseRunnable = new RunnableWithParameter<LifecycleListener>() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onPauseRunnable.run");
listener.onPause();
}
};
/**
* On activity result runnable which is used on fire method
*/
OnActivityResultRunnable onActivityResultRunnable = new OnActivityResultRunnable() {
@Override
public void run(LifecycleListener listener) {
trackEvent("onActivityResultRunnable.run");
super.run(listener);
}
};
/**
* Basic on save instance state runnable. Need separate class because it
* holds the parameter
*/
private class OnSaveInstanceStateRunnable implements RunnableWithParameter<LifecycleListener> {
Bundle outState;
@Override
public void run(LifecycleListener listener) {
listener.onSaveInstanceState(outState);
}
}
/**
* Basic on create runnable. Need separate class because it holds the
* parameter
*/
private class OnCreateRunnable implements RunnableWithParameter<LifecycleListener> {
Bundle savedInstanceState;
@Override
public void run(LifecycleListener listener) {
listener.onCreate(savedInstanceState);
}
}
/**
* Basic on activity result runnable. Need separate class because it holds
* the parameters
*/
private class OnActivityResultRunnable implements RunnableWithParameter<LifecycleListener> {
int requestCode;
int resultCode;
Intent data;
@Override
public void run(LifecycleListener listener) {
listener.onActivityResult(requestCode, resultCode, data);
}
}
/**
* Objects containing {@link LifecycleEventHandler} may implement this
* interface
*/
public static interface HasLifecycleEventHandler {
/**
* Get the lifecycle event handler
*
* @return
*/
LifecycleEventHandler getLifecycleEventHandler();
}
}