package com.zhuinden.simpleservicesexample.utils; import android.util.Log; import com.zhuinden.servicetree.ServiceTree; import com.zhuinden.simpleservicesexample.application.Key; import com.zhuinden.simplestack.Bundleable; import com.zhuinden.simplestack.StateChange; import com.zhuinden.statebundle.StateBundle; import java.util.List; /** * Created by Zhuinden on 2017.03.02.. */ public class ServiceManager { private final ServiceTree serviceTree; private final Object rootKey; public ServiceManager(ServiceTree serviceTree, Object rootKey) { this.serviceTree = serviceTree; this.rootKey = rootKey; } public static final String SERVICE_STATES = "SERVICE_BUNDLE"; private static final String TAG = "ServiceManager"; public StateBundle persistStates() { StateBundle serviceStates = new StateBundle(); serviceTree.traverseTree(ServiceTree.Walk.PRE_ORDER, (node, cancellationToken) -> { StateBundle keyBundle = new StateBundle(); for(ServiceTree.Node.Entry entry : node.getBoundServices()) { if(entry.getService() instanceof Bundleable) { keyBundle.putParcelable(entry.getName(), ((Bundleable) entry.getService()).toBundle()); } } serviceStates.putParcelable(node.getKey().toString(), keyBundle); }); return serviceStates; } public void setupServices(StateChange stateChange) { // services StateBundle states = serviceTree.getNode(rootKey).getService(SERVICE_STATES); for(Object _previousKey : stateChange.getPreviousState()) { Key previousKey = (Key) _previousKey; if(!stateChange.getNewState().contains(previousKey)) { ServiceTree.Node previousNode = serviceTree.getNode(previousKey); if(states != null) { serviceTree.traverseSubtree(previousNode, ServiceTree.Walk.POST_ORDER, (node, cancellationToken) -> { states.remove(node.getKey().toString()); Log.i(TAG, "Destroy [" + node + "]"); }); } serviceTree.removeNodeAndChildren(previousNode); } } for(Object _newKey : stateChange.getNewState()) { Key newKey = (Key) _newKey; if(!serviceTree.hasNodeWithKey(newKey)) { ServiceTree.Node node; if(newKey instanceof Child) { node = serviceTree.createChildNode(serviceTree.getNode(((Child) newKey).parent()), newKey); } else { node = serviceTree.createRootNode(newKey); } newKey.bindServices(node); restoreServiceStateForKey(states, newKey, node); if(newKey instanceof Composite) { buildComposite(states, node, ((Composite) newKey)); } } } // end services } private void buildComposite(StateBundle states, ServiceTree.Node parentNode, Composite composite) { for(Object _nestedKey : composite.keys()) { Key nestedKey = (Key) _nestedKey; ServiceTree.Node nestedNode = serviceTree.createChildNode(parentNode, nestedKey); nestedKey.bindServices(nestedNode); restoreServiceStateForKey(states, nestedKey, nestedNode); if(nestedKey instanceof Composite) { buildComposite(states, nestedNode, (Composite) nestedKey); } } } private void restoreServiceStateForKey(StateBundle states, Key key, ServiceTree.Node node) { if(states != null) { StateBundle keyBundle = states.getParcelable(key.toString()); if(keyBundle != null) { List<ServiceTree.Node.Entry> entries = node.getBoundServices(); for(ServiceTree.Node.Entry entry : entries) { if(entry.getService() instanceof Bundleable) { ((Bundleable) entry.getService()).fromBundle(keyBundle.getParcelable(entry.getName())); } } } } } public void setRestoredStates(StateBundle states) { serviceTree.getNode(rootKey).bindService(SERVICE_STATES, states); } public ServiceTree getServiceTree() { return serviceTree; } }