Open ghost opened 10 years ago
@zump I have in the past used the EventManager
and @Observes
event system to pass data to and from the Activity/Fragments. You can see a working example of this here:
Does this work for you? IMO, This is one area that Transfuse could be better, but I'm not sure what the answer is. Do you have an idea for anything that may work better?
I like the event based pattern... but it's going to be a pain to retrofit. Also, it's going to be tricky if there are return values involved, right?
How about something like this...
@Activity
@Delegate(interfaces = {CustomInterface1.class, CustomInterface2.class})
public class Main implements CustomInterface1, CustomeInterface2 {
@Override public boolean customMethod1() {
return true;
}
@Override public void customMethod2(boolean boo) {
// do something with bool...
}
}
which would give you something like this:
public class MainActivity extends Activity implements ContextScopeHolder, CustomInterface1, CustomInterface2 {
private Main main$$0;
public void onCreate(Bundle bundle$$1) { .... }
@Override public boolean customMethod1() {
return main$$0.customMethod1();
}
@Override public void customMethod2(boolean boo) {
main$$0.customMethod2(boo);
}
}
That's not a bad idea, and it relates to the "Call-through" events nicely.
I have a feeling that I'll be doing a lot of Transfuse tinkering this weekend :smiley:
Great, let me know if I can be of assistance... I've never done any work with writing annotation processing code.. but I can certainly help test it out. In the meantime, I guess I'll see how far I can get with the migration to event based stuff.
You're more than welcome to dive into the code and I'll let you know if/when I come up with something around this.
@zump I was thinking about this some more. Is what you require an object that is scoped to the Activity injected into your Fragments?
I need to be able to call methods on the delegate from an interested fragment or activity.
Ok, so I'd imagine if you could inject the delegate, your problem would be solved. Is this correct?
Yeah, that would do it.
This might get trickier than I thought... The app I'm currently converting has a very deep hierarchy of activity -> fragment(s) -> view -> view -> view... that at each level are expecting to get the context and cast it to one of several interfaces which the parent activity implements... to either trigger some behavior to propagate back down the hierarchy or grabbing the current state of data if some event bubbles up. So to retrofit this app, I would need to be able to expose that set of interfaces and have them delegate from the actual activity to the delegate.
I'm going to introduce a/some new injected object(s) to take the place of the existing mechanism.. but it seems like it might get to be a weird combination of singletons and events... I need to think it through more.
I'm slowly working my way through this massive refactor, but it is becoming really annoying to do fragment -> activity -> fragment communication... especially when there is shared state between two fragments that live in an activity... especially when only one fragment is "live" at a time.. that means the Observer pattern just wont work as the state needs to propagate once a different fragment is made live. I can't call methods on the fragments directly since they don't delegate arbitrary methods.
I am going to have to use a shared context scoped object or a singleton to handle the shared state... but it would be nice to just be able to inject the activity by an interface and share state that way... thoughts?
The shared object is problematic in that the activity or fragment may need to know when the state in that object has changed, which means registering listeners... then I get concerned about leaking context if someone (obviously not me!) is sloppy.
Could you do a combination of @Observes
event listeners and context/singleton scoped objects? @Observes
broadcasts in a way that will not leak. You could also use Otto instead of the EventManager
if you want the @Produces
feature.
... just a warning, context scoping may have issues as I've never fully tested it.
By the way, is there any way I can see the results of your refactor? Im curious to see the results.
I think that would mean that I would need both FragmentNotifyingActivityEvent and ActivityNotifyingFragmentEvent so that the activity doesn't Observe its own events?
It looks like otto would help, but it seems too error prone with all the manual registering and what not...
Unfortunately I can't share my source... but I could walk you through it on a screen share or something if you were interested.
Could the Fragment -> Activity "notification" just be a method call on a singleton, then the resulting update to the fragments be an @Observes
event? Otherwise this sounds good.
I have a branch on my machine of Otto integration without manual registration, but that's with the seemingly abandoned version 2... I wonder if I could get it to work with version 1.x. (Another thing I would love to stick in a plugin library)
I'd be very interested in a screen share walk through. Contact me via email (in my profile) to coordinate.
So the fragment would call a method on the singleton, and the activity would be alerted how? I can see how to do this with bi-directional events.. but it seems like it would be tricky for anyone who didn't write it to follow....
Otto integration would be really fantastic... It's a really cool library. I'm not familiar with the 2.0 changes.. are they substantial?
This plugin framework you keep mentioning sounds glorious :)
I'll email you shortly.
Looks like this branch is still kicking... https://github.com/square/otto/tree/otto2
What I am envisioning is your sate being held in a singleton (or some scoped object) that would act as the central point of coordination. This singleton could be updated directly that would then broadcast out to subscribers that a change has occurred.... possibly the Activity could be a consumer of this event as well?
Here's the general idea:
@Singleton
class StateManager{
@Inject EventManager eventManager;
public void setState(State s){
//update state
eventMAnager.trigger(StateUpdate(s));
}
}
@Activity
class ExampleActivity{
@Inject StateManager
//...
public void onSomething(){
stateMAnager.setState(...);
}
@Observers
public void update(StateUpdate u){...}
}
@Fragment
class ExampleFragment{
@Inject StateManager
public void onSomethingElse(){
stateMAnager.setState(...);
}
@Observers
public void update(StateUpdate u){...}
}
Hmmm, looks like is some activity. Lets hope they release it soon. This plugin framework will be glorious! I should start work on it this weekend.
Yeah, that's kinda the path I started on... I'll let you know how it turns out.
I ended up cleaning up a bunch of these interactions.. it worked out fine. I still think we need the ability to delegate interfaces or at least inject the delegate in some situations.. but I think I'm past all the refactoring spots with very workable solutions.
Great to hear. I think there could be a handful of injections that could happen, namely @Activity
-> @Fragment
, and possibly @Service
-> others (#28). I need to focus on fixing up context scoping and possibly fragment scoping.
We use the pattern in our existing app where Fragments require an interface on the containing activity to communicate back to the activity so that in onAttach we can validate that the Activity is of a type that can support the given fragment:
So that we can later delegate to the activity to handle intra-fragment communication. Is there an existing way to cause transfuse to wire up the delegation from the generated activity to the transfuse activity to support this, or is there a better pattern to achieve this same mechanic?