Zhuinden / flowless

[DEPRECATED] Based on Flow 1.0-alpha. To keep your life simple, use zhuinden/simple-stack instead.
Apache License 2.0
141 stars 7 forks source link

Apps using Flowless? #11

Open selalipop opened 7 years ago

selalipop commented 7 years ago

Are there any apps out there using this library that care to review what it's been like?

Zhuinden commented 7 years ago

I made a complete app using the SingleRootDispatcher preset (no tablet / master-detail view was needed, and AnimatorSet was used instead of the transition framework for view animations), but it's an internal one so I can't actually share it.

I can guarantee to you that if it hadn't been a positive experience, I wouldn't have made an article about it.


I must however also admit that I haven't actually tried mocking the context.getSystemService() call that Flow uses in the background, so I can't tell you how well it interacts with Robolectric at the moment. (it's exactly why I have a refactor planned for the future, I just haven't got to it)

The only other difficulty I know of is orientation locking, because that requires some additional magical configuration in the Dispatcher, considering you need to force the activity to die and be restored in the orientation that you want.

And scoping is manual. So subscoping the dependencies (think Dagger) is in your own hands. Personally in my project, I kinda took the shortcut route and just persist my presenter out and restore it on config change - it makes sense with Realm. So I have no ready-made solution for subscoping the view dependencies, my component provided singletons and unscoped only.

Zhuinden commented 7 years ago

I had to implement scoping Dagger components in an earlier project that I migrated to Flowless.

ServiceProvider serviceProvider = Flow.services(newContext);

// destroyNotIn()
Iterator<Object> aElements = traversal.origin != null ? traversal.origin.reverseIterator() : Collections.emptyList().iterator();
Iterator<Object> bElements = traversal.destination.reverseIterator();
while(aElements.hasNext() && bElements.hasNext()) {
    BaseKey aElement = (BaseKey) aElements.next();
    BaseKey bElement = (BaseKey) bElements.next();
    if(!aElement.equals(bElement)) {
        serviceProvider.unbindServices(aElement);  // returns map of bound services
        break;
    }
}
while(aElements.hasNext()) {
    BaseKey aElement = (BaseKey) aElements.next();
    serviceProvider.unbindServices(aElements.next()); // returns map of bound services
}
// end destroyNotIn

// create service for keys
for(Object destination : traversal.destination) {
    if(!serviceProvider.hasService(destination, DaggerService.TAG) {
        serviceProvider.bindService(destination, DaggerService.TAG, ((BaseKey) destination).createComponent());
    }
}

and

public class DaggerService {
    public static final String TAG = "DaggerService";

    @SuppressWarnings("unchecked")
    public static <T> T getComponent(Context context) {
        //noinspection ResourceType
        return (T) Flow.services(context).getService(Flow.getKey(context), TAG);
    }
}

Then

private void init(Context context) {
    if(!isInEditMode()) {
        LoginComponent loginComponent = DaggerService.getComponent(context);
        loginComponent.inject(this);
    }
}

This is what it looked like, it might seem magical, but I mostly took this code from Flow-Path 0.12. It allows all "components" to exist while the history contains the keys. They get unbound when they are no longer in history.

I also added it to the README.