Part 2 of the small AppState refactoring: added methods to AppStateManager

for retrieving an AppState by ID.  Also modified attach() to throw an
IllegalArgumentException if the ID is already registered.
Updated TestAppStateLifeCycle to add a small ID demonstration.
fix-openal-soft-deadlink
Paul Speed 5 years ago
parent 3dd2755c20
commit 36afe829c6
  1. 53
      jme3-core/src/main/java/com/jme3/app/state/AppStateManager.java
  2. 30
      jme3-examples/src/main/java/jme3test/app/TestAppStateLifeCycle.java

@ -37,6 +37,8 @@ import com.jme3.renderer.RenderManager;
import com.jme3.util.SafeArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ConcurrentHashMap;
/**
* The <code>AppStateManager</code> holds a list of {@link AppState}s which
@ -83,6 +85,12 @@ public class AppStateManager {
*/
private final SafeArrayList<AppState> terminating = new SafeArrayList<AppState>(AppState.class);
/**
* Thread-safe index of every state that is currently attached and has
* an ID.
*/
private final ConcurrentMap<String, AppState> stateIndex = new ConcurrentHashMap<>();
// All of the above lists need to be thread safe but access will be
// synchronized separately.... but always on the states list. This
// is to avoid deadlocking that may occur and the most common use case
@ -122,7 +130,8 @@ public class AppStateManager {
/**
* Attach a state to the AppStateManager, the same state cannot be attached
* twice.
* twice. Throws an IllegalArgumentException if the state has an ID and that
* ID has already been associated with another AppState.
*
* @param state The state to attach
* @return True if the state was successfully attached, false if the state
@ -130,11 +139,16 @@ public class AppStateManager {
*/
public boolean attach(AppState state){
synchronized (states){
if( state.getId() != null && stateIndex.putIfAbsent(state.getId(), state) != null ) {
throw new IllegalArgumentException("ID:" + state.getId()
+ " is already being used by another state:"
+ stateIndex.get(state.getId()));
}
if (!states.contains(state) && !initializing.contains(state)){
state.stateAttached(this);
initializing.add(state);
return true;
}else{
} else {
return false;
}
}
@ -175,6 +189,12 @@ public class AppStateManager {
*/
public boolean detach(AppState state){
synchronized (states){
// Remove it from the index if it exists.
// Note: we remove it directly from the values() in case
// the state has changed its ID since registered.
stateIndex.values().remove(state);
if (states.contains(state)){
state.stateDetached(this);
states.remove(state);
@ -249,6 +269,35 @@ public class AppStateManager {
return null;
}
/**
* Returns the state associated with the specified ID at the time it was
* attached or null if not state was attached with that ID.
*/
public <T extends AppState> T getState( String id, Class<T> stateClass ) {
return stateClass.cast(stateIndex.get(id));
}
/**
* Returns true if there is currently a state associated with the specified
* ID.
*/
public boolean hasState( String id ) {
return stateIndex.containsKey(id);
}
/**
* Returns the state associated with the specified ID at the time it
* was attached or throws an IllegalArgumentException if the ID was
* not found.
*/
public <T extends AppState> T stateForId( String id, Class<T> stateClass ) {
T result = getState(id, stateClass);
if( result == null ) {
throw new IllegalArgumentException("State not found for:" + id);
}
return stateClass.cast(result);
}
protected void initializePending(){
AppState[] array = getInitializing();
if (array.length == 0)

@ -65,6 +65,9 @@ public class TestAppStateLifeCycle extends SimpleApplication {
System.out.println("Attaching test state.");
stateManager.attach(new TestState());
System.out.println("Attaching test state with an ID.");
stateManager.attach(new TestState("Test ID"));
}
@Override
@ -75,50 +78,63 @@ public class TestAppStateLifeCycle extends SimpleApplication {
stateManager.detach(stateManager.getState(TestState.class));
System.out.println("Done");
}
if( stateManager.hasState("Test ID") ) {
System.out.println("Detaching test state with an ID.");
stateManager.detach(stateManager.getState("Test ID", TestState.class));
System.out.println("Done");
}
}
public class TestState extends AbstractAppState {
public TestState() {
}
public TestState( String id ) {
super(id);
}
@Override
public void initialize(AppStateManager stateManager, Application app) {
super.initialize(stateManager, app);
System.out.println("Initialized");
System.out.println("Initialized, id:" + getId());
}
@Override
public void stateAttached(AppStateManager stateManager) {
super.stateAttached(stateManager);
System.out.println("Attached");
System.out.println("Attached, id:" + getId());
}
@Override
public void update(float tpf) {
super.update(tpf);
System.out.println("update");
System.out.println("update, id:" + getId());
}
@Override
public void render(RenderManager rm) {
super.render(rm);
System.out.println("render");
System.out.println("render, id:" + getId());
}
@Override
public void postRender() {
super.postRender();
System.out.println("postRender");
System.out.println("postRender, id:" + getId());
}
@Override
public void stateDetached(AppStateManager stateManager) {
super.stateDetached(stateManager);
System.out.println("Detached");
System.out.println("Detached, id:" + getId());
}
@Override
public void cleanup() {
super.cleanup();
System.out.println("Cleanup");
System.out.println("Cleanup, id:" + getId());
}
}

Loading…
Cancel
Save