Overview
I have solved a similar problem, which is to re-render the top-level Litho component when an external action occurs by doing the following:
- storing a reference to the
LithoView
created in my Activities onCreate
method
- define some kind of object to track the state across renders, this must contain any state needed to render your component tree. this will be a
@Prop
on your top-level component
- create an initial state in
onCreate
and derive my initial component from this
- when I receive a callback, compute the new state object and create a new
Component
instance from this
- call
LithoView#setComponent(Component)
with that instance
This is essentially an implementation of the MVI approach as explained here for Android with Mosby, though the example shown is highly simplified.
Example:
Activity:
public class CounterActivity extends Activity {
private LithoView lithoView; // 1: keeps the same LithoView instance for the entirety of the Activity
private ComponentContext c;
private State currentState; // 2: remembers the current State
static class State {
private int counter;
State(int count) {
this.counter = count;
}
public int getCounter() {
return counter;
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
c = new ComponentContext(this);
// 3: create the initial UI state (note: you probably need to use savedInstanceState or some other external state here)
setState(getInitialApplicationState());
}
// 4: A silly example of an Activity-level callback to drive state updates
@Override
public void onBackPressed() {
setState(new State(currentState.getCounter() + 1));
}
// This will store the new state in the Activity and update the component accordingly
private void setState(State newState) {
currentState = newState;
updateView(newState);
}
// There is a 1:1 mapping between State and UI
private Component componentForState(State state) {
return CounterComponent.create(c).state(state).build();
}
// 5: set the Component on the LithoView for the current state
private void updateView(State currentState) {
Component contentComponent = componentForState(currentState);
if (lithoView == null) {
lithoView = LithoView.create(this, contentComponent);
setContentView(lithoView);
} else {
lithoView.setComponent(contentComponent);
}
}
private State getInitialApplicationState() {
return new State(0);
}
}
Spec:
@LayoutSpec
public class CounterComponentSpec {
@OnCreateLayout
static ComponentLayout onCreateLayout(
ComponentContext c,
@Prop CounterActivity.State state) {
return Text.create(c)
.text("Count: " + state.getCounter())
.textSizeSp(44f)
.buildWithLayout();
}
}