Skip to content

Commit 98d4f37

Browse files
committed
Using an executor service instead of a new thread each time an @background method is called. Fixes issue 4. I also had to catch FilerExceptions that happens when creating twice the same file for different rounds...
1 parent 7a2523b commit 98d4f37

4 files changed

Lines changed: 69 additions & 21 deletions

File tree

AndroidAnnotations/src/main/java/com/googlecode/androidannotations/AndroidAnnotationProcessor.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ private void processThrowing(Set<? extends TypeElement> annotations, RoundEnviro
169169

170170
AnnotationElements validatedModel = validateAnnotations(extractedModel, rClass, androidSystemServices, androidManifest);
171171

172-
JCodeModel codeModel = processAnnotations(validatedModel, rClass, androidSystemServices);
172+
JCodeModel codeModel = processAnnotations(validatedModel, rClass, androidSystemServices, androidManifest);
173173

174174
generateSources(codeModel);
175175
}
@@ -230,12 +230,12 @@ private ModelValidator buildModelValidator(IRClass rClass, AndroidSystemServices
230230
return modelValidator;
231231
}
232232

233-
private JCodeModel processAnnotations(AnnotationElements validatedModel, IRClass rClass, AndroidSystemServices androidSystemServices) {
234-
ModelProcessor modelProcessor = buildModelProcessor(rClass, androidSystemServices);
233+
private JCodeModel processAnnotations(AnnotationElements validatedModel, IRClass rClass, AndroidSystemServices androidSystemServices, AndroidManifest androidManifest) {
234+
ModelProcessor modelProcessor = buildModelProcessor(rClass, androidSystemServices, androidManifest);
235235
return modelProcessor.process(validatedModel);
236236
}
237237

238-
private ModelProcessor buildModelProcessor(IRClass rClass, AndroidSystemServices androidSystemServices) {
238+
private ModelProcessor buildModelProcessor(IRClass rClass, AndroidSystemServices androidSystemServices, AndroidManifest androidManifest) {
239239
ModelProcessor modelProcessor = new ModelProcessor();
240240
modelProcessor.register(new EnhanceProcessor(processingEnv, rClass));
241241
modelProcessor.register(new RoboGuiceProcessor());
@@ -251,7 +251,7 @@ private ModelProcessor buildModelProcessor(IRClass rClass, AndroidSystemServices
251251
}
252252
modelProcessor.register(new UiThreadProcessor());
253253
modelProcessor.register(new UiThreadDelayedProcessor());
254-
modelProcessor.register(new BackgroundProcessor());
254+
modelProcessor.register(new BackgroundProcessor(androidManifest));
255255
modelProcessor.register(new TransactionalProcessor());
256256
modelProcessor.register(new ExtraProcessor());
257257
modelProcessor.register(new SystemServiceProcessor(androidSystemServices));

AndroidAnnotations/src/main/java/com/googlecode/androidannotations/generation/SourceCodewriter.java

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,57 @@
44
import java.io.OutputStream;
55

66
import javax.annotation.processing.Filer;
7+
import javax.annotation.processing.FilerException;
78
import javax.tools.JavaFileObject;
89

910
import com.sun.codemodel.CodeWriter;
1011
import com.sun.codemodel.JPackage;
1112

1213
public class SourceCodewriter extends CodeWriter {
13-
14+
1415
private final Filer filer;
15-
16+
17+
private static final VoidOutputStream VOID_OUTPUT_STREAM = new VoidOutputStream();
18+
19+
private static class VoidOutputStream extends OutputStream {
20+
@Override
21+
public void write(int arg0) throws IOException {
22+
// Do nothing
23+
}
24+
}
25+
1626
public SourceCodewriter(Filer filer) {
1727
this.filer = filer;
1828
}
1929

2030
@Override
2131
public OutputStream openBinary(JPackage pkg, String fileName) throws IOException {
2232
String qualifiedClassName = toQualifiedClassName(pkg, fileName);
23-
24-
JavaFileObject sourceFile = filer.createSourceFile(qualifiedClassName);
25-
26-
return sourceFile.openOutputStream();
33+
34+
try {
35+
JavaFileObject sourceFile = filer.createSourceFile(qualifiedClassName);
36+
return sourceFile.openOutputStream();
37+
} catch (FilerException e) {
38+
/*
39+
* This exception is expected, when some files are created twice. We
40+
* cannot delete existing files, unless using a dirty hack. Files a
41+
* created twice when the same file is created from different
42+
* annotation rounds. Happens when renaming classes, and for
43+
* Background executor.
44+
*/
45+
return VOID_OUTPUT_STREAM;
46+
}
2747
}
2848

2949
private String toQualifiedClassName(JPackage pkg, String fileName) {
3050
int suffixPosition = fileName.lastIndexOf('.');
3151
String className = fileName.substring(0, suffixPosition);
32-
33-
String qualifiedClassName = pkg.name() + "."+className;
52+
53+
String qualifiedClassName = pkg.name() + "." + className;
3454
return qualifiedClassName;
3555
}
3656

3757
@Override
38-
public void close() throws IOException {}
58+
public void close() throws IOException {
59+
}
3960
}

AndroidAnnotations/src/main/java/com/googlecode/androidannotations/processing/ActivitiesHolder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,14 @@
55

66
import javax.lang.model.element.Element;
77

8+
import com.sun.codemodel.JDefinedClass;
9+
import com.sun.codemodel.JMethod;
10+
811
public class ActivitiesHolder {
912

1013
private Map<Element, ActivityHolder> activityHolders = new HashMap<Element, ActivityHolder>();
14+
public JMethod executorMethod;
15+
public JDefinedClass backgroundExecutor;
1116

1217
public ActivityHolder create(Element activityElement) {
1318
ActivityHolder activityHolder = new ActivityHolder();

AndroidAnnotations/src/main/java/com/googlecode/androidannotations/processing/BackgroundProcessor.java

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,15 @@
1818
import java.lang.annotation.Annotation;
1919
import java.util.ArrayList;
2020
import java.util.List;
21+
import java.util.concurrent.Executor;
22+
import java.util.concurrent.Executors;
2123

2224
import javax.lang.model.element.Element;
2325
import javax.lang.model.element.ExecutableElement;
2426
import javax.lang.model.element.VariableElement;
2527

2628
import com.googlecode.androidannotations.annotations.Background;
29+
import com.googlecode.androidannotations.helper.AndroidManifest;
2730
import com.sun.codemodel.JBlock;
2831
import com.sun.codemodel.JCatchBlock;
2932
import com.sun.codemodel.JClass;
@@ -32,6 +35,7 @@
3235
import com.sun.codemodel.JDefinedClass;
3336
import com.sun.codemodel.JExpr;
3437
import com.sun.codemodel.JExpression;
38+
import com.sun.codemodel.JFieldVar;
3539
import com.sun.codemodel.JInvocation;
3640
import com.sun.codemodel.JMethod;
3741
import com.sun.codemodel.JMod;
@@ -40,6 +44,12 @@
4044

4145
public class BackgroundProcessor implements ElementProcessor {
4246

47+
private final AndroidManifest androidManifest;
48+
49+
public BackgroundProcessor(AndroidManifest androidManifest) {
50+
this.androidManifest = androidManifest;
51+
}
52+
4353
@Override
4454
public Class<? extends Annotation> getTarget() {
4555
return Background.class;
@@ -50,6 +60,17 @@ public void process(Element element, JCodeModel codeModel, ActivitiesHolder acti
5060

5161
ActivityHolder holder = activitiesHolder.getEnclosingActivityHolder(element);
5262

63+
if (activitiesHolder.backgroundExecutor == null) {
64+
activitiesHolder.backgroundExecutor = codeModel._class(androidManifest.getApplicationPackage() + ".BackgroundExecutor_");
65+
66+
JInvocation newCachedThreadPool = codeModel.ref(Executors.class).staticInvoke("newCachedThreadPool");
67+
68+
JFieldVar executorStaticField = activitiesHolder.backgroundExecutor.field(JMod.STATIC | JMod.PRIVATE | JMod.FINAL, codeModel.ref(Executor.class), "executor", newCachedThreadPool);
69+
activitiesHolder.executorMethod = activitiesHolder.backgroundExecutor.method(JMod.PUBLIC | JMod.STATIC, codeModel.VOID, "execute");
70+
JVar runnableParam = activitiesHolder.executorMethod.param(Runnable.class, "runnable");
71+
activitiesHolder.executorMethod.body().invoke(executorStaticField, "execute").arg(runnableParam);
72+
}
73+
5374
// Method
5475
String backgroundMethodName = element.getSimpleName().toString();
5576
JMethod backgroundMethod = holder.activity.method(JMod.PUBLIC, codeModel.VOID, backgroundMethodName);
@@ -65,16 +86,16 @@ public void process(Element element, JCodeModel codeModel, ActivitiesHolder acti
6586
parameters.add(param);
6687
}
6788

68-
JDefinedClass anonymousThreadClass = codeModel.anonymousClass(Thread.class);
89+
JDefinedClass anonymousRunnableClass = codeModel.anonymousClass(Runnable.class);
6990

70-
JMethod runMethod = anonymousThreadClass.method(JMod.PUBLIC, codeModel.VOID, "run");
91+
JMethod runMethod = anonymousRunnableClass.method(JMod.PUBLIC, codeModel.VOID, "run");
7192
runMethod.annotate(Override.class);
7293

7394
JBlock runMethodBody = runMethod.body();
7495
JTryBlock runTry = runMethodBody._try();
75-
96+
7697
JExpression activitySuper = holder.activity.staticRef("super");
77-
98+
7899
JInvocation superCall = runTry.body().invoke(activitySuper, backgroundMethod);
79100
for (JVar param : parameters) {
80101
superCall.arg(param);
@@ -93,8 +114,9 @@ public void process(Element element, JCodeModel codeModel, ActivitiesHolder acti
93114
runCatch.body().add(errorInvoke);
94115

95116
JBlock backgroundBody = backgroundMethod.body();
96-
97-
backgroundBody.add(JExpr._new(anonymousThreadClass).invoke("start"));
98-
117+
118+
JInvocation executeCall = activitiesHolder.backgroundExecutor.staticInvoke(activitiesHolder.executorMethod).arg(JExpr._new(anonymousRunnableClass));
119+
120+
backgroundBody.add(executeCall);
99121
}
100122
}

0 commit comments

Comments
 (0)