diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/IgnoredWhenDetached.java b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/IgnoreWhen.java similarity index 74% rename from AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/IgnoredWhenDetached.java rename to AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/IgnoreWhen.java index 19d7a48774..4519ee5169 100644 --- a/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/IgnoredWhenDetached.java +++ b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/IgnoreWhen.java @@ -25,7 +25,9 @@ * When used standalone in an {@link EFragment} or in conjunction with the * {@link UiThread} or {@link Background} annotations, the annotated method will * be wrapped in an 'if attached' block such that no code will be executed if - * the {@link EFragment} is no longer bound to its parent activity. + * the {@link EFragment} is no longer bound to its parent activity or + * DETACHEDthe {@link EFragment} views are destroyed + * VIEW_DESTROYED. *

*

* Should be used on method that must meet the following criteria @@ -47,13 +49,13 @@ * ... * * @UiThread - * @IgnoredWhenDetached + * @IgnoreWhen(IgnoreWhen.State.DETACHED) * void killActivity() { * getActivity().finish(); * } * * - * @IgnoredWhenDetached + * @IgnoreWhen(IgnoreWhen.State.VIEW_DESTROYED) * void updateTitle(String title) { * getActivity().setTitle(title); * } @@ -69,6 +71,29 @@ */ @Retention(RetentionPolicy.CLASS) @Target(ElementType.METHOD) -public @interface IgnoredWhenDetached { +public @interface IgnoreWhen { + /** + * The lifecycle state after the method should not be executed. + * + * @return the state that skips method execution + */ + State value(); + + /** + * The lifecycle state after the method should not be executed. + */ + enum State { + + /** + * Skip execution if the {@link EFragment} is no longer bound to its + * parent activity. + */ + DETACHED, + + /** + * Skip execution if the {@link EFragment} views are destroyed. + */ + VIEW_DESTROYED + } } diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/efragment/MyListFragment.java b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/efragment/MyListFragment.java index 4b9ba2d544..fec7653b1c 100644 --- a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/efragment/MyListFragment.java +++ b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/efragment/MyListFragment.java @@ -17,7 +17,7 @@ import org.androidannotations.annotations.Background; import org.androidannotations.annotations.EFragment; -import org.androidannotations.annotations.IgnoredWhenDetached; +import org.androidannotations.annotations.IgnoreWhen; import org.androidannotations.annotations.ItemClick; import org.androidannotations.annotations.UiThread; import org.androidannotations.annotations.ViewById; @@ -58,7 +58,7 @@ void uiThread() { } @UiThread(propagation = UiThread.Propagation.REUSE) - @IgnoredWhenDetached + @IgnoreWhen(IgnoreWhen.State.DETACHED) void uiThreadIgnored() { didExecute = true; } @@ -74,16 +74,21 @@ void backgroundThread() { } @Background - @IgnoredWhenDetached + @IgnoreWhen(IgnoreWhen.State.DETACHED) void backgroundThreadIgnored() { didExecute = true; } - @IgnoredWhenDetached + @IgnoreWhen(IgnoreWhen.State.DETACHED) void ignored() { didExecute = true; } + @IgnoreWhen(IgnoreWhen.State.VIEW_DESTROYED) + void ignoreWhenViewDestroyed() { + didExecute = true; + } + void notIgnored() { didExecute = true; } diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/efragment/MyListFragmentTest.java b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/efragment/MyListFragmentTest.java index f2a4b512ed..b48ea48ffb 100644 --- a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/efragment/MyListFragmentTest.java +++ b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/efragment/MyListFragmentTest.java @@ -122,6 +122,46 @@ public void ignoredWhenDetachedWorksForIgnoredMethod() { assertFalse(myListFragment.didExecute); } + @Test + public void notIgnoredAfterOnCreateView() { + assertFalse(myListFragment.didExecute); + myListFragment.onCreateView(null, null, null); + assertFalse(myListFragment.didExecute); + myListFragment.ignoreWhenViewDestroyed(); + assertTrue(myListFragment.didExecute); + } + + @Test + public void ignoredWhenViewDestroyedForIgnoredMethod() { + assertFalse(myListFragment.didExecute); + myListFragment.onDestroyView(); + myListFragment.ignoreWhenViewDestroyed(); + assertFalse(myListFragment.didExecute); + } + + @Test + public void notIgnoredAfterFragmentRecreate() { + assertFalse(myListFragment.didExecute); + myListFragment.onDestroyView(); + myListFragment.onCreateView(null, null, null); + myListFragment.ignoreWhenViewDestroyed(); + assertTrue(myListFragment.didExecute); + } + + @Test + public void notIgnoredBeforeDetached() { + assertFalse(myListFragment.didExecute); + myListFragment.ignored(); + assertTrue(myListFragment.didExecute); + } + + @Test + public void notIgnoredBeforeViewDestroyed() { + assertFalse(myListFragment.didExecute); + myListFragment.ignoreWhenViewDestroyed(); + assertTrue(myListFragment.didExecute); + } + @Test public void layoutNotInjectedWithoutForce() { View buttonInInjectedLayout = myListFragment.getView().findViewById(R.id.conventionButton); diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EFragmentHolder.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EFragmentHolder.java index f5637e9b03..5e2dfa0cd2 100644 --- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EFragmentHolder.java +++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EFragmentHolder.java @@ -15,6 +15,8 @@ */ package org.androidannotations.holder; +import static com.helger.jcodemodel.JExpr.FALSE; +import static com.helger.jcodemodel.JExpr.TRUE; import static com.helger.jcodemodel.JExpr._new; import static com.helger.jcodemodel.JExpr._null; import static com.helger.jcodemodel.JExpr._super; @@ -23,6 +25,7 @@ import static com.helger.jcodemodel.JMod.PRIVATE; import static com.helger.jcodemodel.JMod.PUBLIC; import static com.helger.jcodemodel.JMod.STATIC; +import static com.helger.jcodemodel.JMod.VOLATILE; import static org.androidannotations.helper.ModelConstants.generationSuffix; import javax.lang.model.element.TypeElement; @@ -46,6 +49,7 @@ public class EFragmentHolder extends EComponentWithViewSupportHolder implements HasInstanceState, HasOptionsMenu, HasOnActivityResult, HasReceiverRegistration, HasPreferences { private JFieldVar contentView; + private JFieldVar viewDestroyedField; private JBlock setContentViewBlock; private JVar inflater; private JVar container; @@ -208,6 +212,19 @@ private void setContentView() { contentView = generatedClass.field(PRIVATE, getClasses().VIEW, "contentView" + generationSuffix()); } + public JFieldVar getViewDestroyedField() { + if (viewDestroyedField == null) { + setViewDestroyedField(); + } + return viewDestroyedField; + } + + private void setViewDestroyedField() { + viewDestroyedField = generatedClass.field(PRIVATE | VOLATILE, getCodeModel().BOOLEAN, "viewDestroyed" + generationSuffix()); + getSetContentViewBlock().assign(viewDestroyedField, FALSE); + getOnDestroyViewAfterSuperBlock().assign(viewDestroyedField, TRUE); + } + private void setOnCreateView() { JMethod onCreateView = generatedClass.method(PUBLIC, getClasses().VIEW, "onCreateView"); onCreateView.annotate(Override.class); diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java index 1c0e9862ca..a2f868f1cd 100644 --- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java +++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java @@ -60,7 +60,7 @@ import org.androidannotations.internal.core.handler.HierarchyViewerSupportHandler; import org.androidannotations.internal.core.handler.HtmlResHandler; import org.androidannotations.internal.core.handler.HttpsClientHandler; -import org.androidannotations.internal.core.handler.IgnoredWhenDetachedHandler; +import org.androidannotations.internal.core.handler.IgnoreWhenHandler; import org.androidannotations.internal.core.handler.InjectMenuHandler; import org.androidannotations.internal.core.handler.InstanceStateHandler; import org.androidannotations.internal.core.handler.ItemClickHandler; @@ -206,7 +206,7 @@ public List> getHandlers(AndroidAnnotationsEnvironment andr annotationHandlers.add(new PageScrollStateChangedHandler(androidAnnotationEnv)); annotationHandlers.add(new PageSelectedHandler(androidAnnotationEnv)); - annotationHandlers.add(new IgnoredWhenDetachedHandler(androidAnnotationEnv)); + annotationHandlers.add(new IgnoreWhenHandler(androidAnnotationEnv)); annotationHandlers.add(new AfterInjectHandler(androidAnnotationEnv)); annotationHandlers.add(new AfterExtrasHandler(androidAnnotationEnv)); @@ -231,7 +231,7 @@ public List> getHandlers(AndroidAnnotationsEnvironment andr /* * UIThreadHandler and BackgroundHandler must be after TraceHandler and - * IgnoredWhenDetached + * IgnoreWhen */ annotationHandlers.add(new UiThreadHandler(androidAnnotationEnv)); annotationHandlers.add(new BackgroundHandler(androidAnnotationEnv)); diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/IgnoredWhenDetachedHandler.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/IgnoreWhenHandler.java similarity index 70% rename from AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/IgnoredWhenDetachedHandler.java rename to AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/IgnoreWhenHandler.java index 708f89e7c4..3705298cd6 100644 --- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/IgnoredWhenDetachedHandler.java +++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/IgnoreWhenHandler.java @@ -23,17 +23,18 @@ import org.androidannotations.AndroidAnnotationsEnvironment; import org.androidannotations.ElementValidation; -import org.androidannotations.annotations.IgnoredWhenDetached; +import org.androidannotations.annotations.IgnoreWhen; import org.androidannotations.handler.BaseAnnotationHandler; import org.androidannotations.holder.EFragmentHolder; import com.helger.jcodemodel.JBlock; +import com.helger.jcodemodel.JConditional; import com.helger.jcodemodel.JMethod; -public class IgnoredWhenDetachedHandler extends BaseAnnotationHandler { +public class IgnoreWhenHandler extends BaseAnnotationHandler { - public IgnoredWhenDetachedHandler(AndroidAnnotationsEnvironment environment) { - super(IgnoredWhenDetached.class, environment); + public IgnoreWhenHandler(AndroidAnnotationsEnvironment environment) { + super(IgnoreWhen.class, environment); } @Override @@ -53,6 +54,17 @@ public void process(Element element, EFragmentHolder holder) throws Exception { JMethod delegatingMethod = codeModelHelper.overrideAnnotatedMethod(executableElement, holder); JBlock previousMethodBody = codeModelHelper.removeBody(delegatingMethod); - delegatingMethod.body()._if(invoke(holder.getGeneratedClass().staticRef("this"), "getActivity").ne(_null()))._then().add(previousMethodBody); + IgnoreWhen ignoreWhen = element.getAnnotation(IgnoreWhen.class); + JBlock methodBody = delegatingMethod.body(); + JConditional conditional = null; + switch (ignoreWhen.value()) { + case VIEW_DESTROYED: + conditional = methodBody._if(holder.getViewDestroyedField().not()); + break; + case DETACHED: + conditional = methodBody._if(invoke(holder.getGeneratedClass().staticRef("this"), "getActivity").ne(_null())); + break; + } + conditional._then().add(previousMethodBody); } }