Repository navigation
startActivityForResult in activity intent builder #270
Description
Activity
Yes, we thought about that, the only problem is that startActivityForResult is a method that only exists on the
Activityclass, not on theContextclass. So this basically means we'd have to create two IntentBuilder class per Activity class.Yep, missed that. Probably, it can be done smth like this, without generating fully same classes:
public static class IntentBuilder2<T extends Context> { protected T context_; protected final Intent intent_; public IntentBuilder2(T context) { context_ = context; intent_ = new Intent(context, ValveData_.class); } ... } public static class ActivityIntentBuilder_ extends IntentBuilder2<Activity> { public ActivityIntentBuilder_(Activity context) { super(context); } public void start(int request) { ((Activity)context_).startActivityForResult(intent_, request); } }And additional static method in activity:
public static<T extends Context> IntentBuilder2<T> intent(T context) { return new IntentBuilder2<T>(context); } public static ActivityIntentBuilder_ intent(Activity context) { return new ActivityIntentBuilder_(context); }Yeah, that's an interesting solution. A few notes :
- we don't need the cast in
((Activity)context_).startActivityForResult(intent_, request);, that's the whole point of using generics here :) . - The first method doesn't need to be parameterized, it will provide the same features this way :
public static IntentBuilder2<Context> intent(Context context) { return new IntentBuilder2<Context>(context); }
- I would name the start method
startForResult()
- we don't need the cast in
Hum, giving it a few more thoughts, it can't work this way. The fluid API pattern requires using self bounded generics, to be able to do something such as :
intent(activity).flags(0).startForResult(42):flags()is defined in the supertype and returnsthis, but this is an instance of supertype, unless we have it return T, T being a self bounded generic.We could also go down the "unsafe but ok road", just add the following
startForResult()method to the current implementation :public void starForResult(int requestCode) { if (context instanceof Activity) { ((Activity) context_).startActivityForResult(intent_, requestCode); } else { context_.startActivity(intent_); } }
- added a commit that references this issue
on Jul 12, 2012 Haven't tried yet, but what do you think?
public static class IntentBuilder2<T extends Context, Super extends IntentBuilder2<?, ?>> { protected T context_; protected final Intent intent_; public IntentBuilder2(T context) { context_ = context; intent_ = new Intent(context, ValveData_.class); } Super data() { return (Super) this; } } public static class ACtivityIntentBuilder extends IntentBuilder2<Activity, ACtivityIntentBuilder> { public ACtivityIntentBuilder(Activity context) { super(context); } } public static<T extends Context> IntentBuilder2<T, IntentBuilder2<?,?>> intent(T context) { return new IntentBuilder2<T, IntentBuilder2<?,?>>(context); } public static ACtivityIntentBuilder intent(Activity context) { return new ACtivityIntentBuilder(context); }Probably, there is a solution for compile time checks.
Yeah, this is what I called "self bounded generics".
As you probably noticed, I just implemented a "simpler" solution in #271.
Yep, saw that. I don't know, if it is possible to make a compile-time warning, when we call startForResult from non activity context. One of the main feature of AA is compile-time checks, and i like that :)
Agreed. However, for this specific case, I see no better solution.
@pyricau, why don't you want to use "self bounded generics"?
The other issue, probably a warning should be, if we use startForResult with non activity code.
@naixx Because "self bounded generics" are a nice nerdy things that 99% of java developers know nothing about, and would be scared to hell when seeing what Eclipse tell them about the return type of the
intent()method :) .We could have also created two IntentBuilder classes per activity, one that takes a context and one that takes an activity.
We cannot put a compilation warning on method calls. Only on compilation elements (ie declarations). We could log a warning at runtime if the context isn't an activity, I guess.
@pyricau, But developers would see only clean interface, which will or not have
startForResult, they don't even need to know about internalIntentBuilderclasses. But it will provide them much more safety.I meant a runtime warning to the
Log. In this case we need somehow to tell developer, that the program would not behave as expected(he will never receive a result). Probably even an exception could be thrown?Although I like making my app crash in debug mode when something's unexpected, to force devs to fix it, I wouldn't enforce this in an open source framework :) . I think the runtime warning is a good enough solution.
Regarding the self bounded generic, the developer will use the autocompletion and see in the autocompletion doc that "intent()" returns a weird type and get scared :) . At least that's my theory.
@pyricau Didn't check, but what if:
public static class ContextIntentBuilder extends IntentBuilder2<Context, ContextIntentBuilder > { public ContextIntentBuilder(Context context) { super(context); } }So, we will have
ContextIntentBuilderandActivityIntentBuilderthat will be returned fromintent(). Is it possible in Java?Yep, warning would be good anyway.
Yes, it's possible but doesn't change a thing on the signature of methods implemented by IntentBuilder2 :) . The'll still return a
IntentBuilder2<>, <>, withcapture-of*adding a lot of noise :)@pyricau Actually, i didn't clearly understand the problem.
IntentBuilder2<>, <>is hidden, so whats the noise?When you write
MyActivity_.intent(context).flags(0)and let Eclipse show you the signature of theflags()method. This method belongs toIntentBuilder2<>, <>.Ok, now i understand :) For me, its not so scary. Developer won't see this class in his own code, only auto-completion in IDE. There are a lot of generics in standard library and even android (e.g. Simple*Adapters), but people use them :).
It could be useful to have an overloaded method in intent builder