Skip to content

Commit 36a76e2

Browse files
committed
Add Data Binding support
1 parent 13c5192 commit 36a76e2

27 files changed

Lines changed: 881 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/**
2+
* Copyright (C) 2016-2017 the AndroidAnnotations project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.annotations;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.RetentionPolicy;
21+
import java.lang.annotation.Target;
22+
23+
/**
24+
* <p>
25+
* Can be used on fields, methods and method parameters in enhanced Activities,
26+
* Fragments and ViewGroups to access the binding object used in Data Binding.
27+
* </p>
28+
* <p>
29+
* The declaring class must be annotated with {@link DataBound}. The type must
30+
* extends <code>ViewDataBinding</code>. The following injections are allowed:
31+
* </p>
32+
* <blockquote>
33+
*
34+
* <pre>
35+
* &#064;DataBound
36+
* &#064;EActivity(R.layout.my_activity)
37+
* public class MyActivity extends Activity {
38+
*
39+
* &#064;BindingObject
40+
* MyActivityBinding binding;
41+
*
42+
* &#064;BindingObject
43+
* void methodInjection(MyActivityBinding binding) {
44+
* // use binding
45+
* }
46+
*
47+
* void paramInjection(&#064;BindingObject MyActivityBinding binding) {
48+
* // use binding
49+
* }
50+
*
51+
* }
52+
* </pre>
53+
*
54+
* </blockquote>
55+
*
56+
* @see DataBound
57+
*/
58+
@Retention(RetentionPolicy.CLASS)
59+
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
60+
public @interface BindingObject {
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* Copyright (C) 2016-2017 the AndroidAnnotations project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.annotations;
17+
18+
import java.lang.annotation.ElementType;
19+
import java.lang.annotation.Retention;
20+
import java.lang.annotation.RetentionPolicy;
21+
import java.lang.annotation.Target;
22+
23+
/**
24+
* <p>
25+
* Can be used on enhanced Activities, Fragments and ViewGroups to mark
26+
* them to use the Data Binding library to inflate the layout.
27+
* </p>
28+
* <blockquote>
29+
*
30+
* Example :
31+
*
32+
* <pre>
33+
* &#064;DataBound
34+
* &#064;EActivity(R.layout.my_activity)
35+
* public class MyActivity extends Activity {
36+
*
37+
* }
38+
* </pre>
39+
*
40+
* </blockquote>
41+
*
42+
* @see BindingObject
43+
*/
44+
@Retention(RetentionPolicy.CLASS)
45+
@Target(ElementType.TYPE)
46+
public @interface DataBound {
47+
}

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/CanonicalNameConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
22
* Copyright (C) 2010-2016 eBusiness Information, Excilys Group
3+
* Copyright (C) 2016-2017 the AndroidAnnotations project
34
*
45
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
56
* use this file except in compliance with the License. You may obtain a copy of
@@ -165,6 +166,9 @@ public final class CanonicalNameConstants {
165166
public static final String PARCEL_ANNOTATION = "org.parceler.Parcel";
166167
public static final String PARCELS_UTILITY_CLASS = "org.parceler.Parcels";
167168

169+
public static final String DATA_BINDING_UTIL = "android.databinding.DataBindingUtil";
170+
public static final String VIEW_DATA_BINDING = "android.databinding.ViewDataBinding";
171+
168172
private CanonicalNameConstants() {
169173
}
170174

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/**
2+
* Copyright (C) 2016-2017 the AndroidAnnotations project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.holder;
17+
18+
import static org.androidannotations.helper.ModelConstants.generationSuffix;
19+
20+
import com.helger.jcodemodel.IJExpression;
21+
import com.helger.jcodemodel.JFieldVar;
22+
import com.helger.jcodemodel.JMod;
23+
24+
class DataBindingDelegate extends GeneratedClassHolderDelegate<EComponentWithViewSupportHolder> {
25+
26+
private JFieldVar dataBindingField;
27+
28+
DataBindingDelegate(EComponentWithViewSupportHolder holder) {
29+
super(holder);
30+
}
31+
32+
JFieldVar getDataBindingField() {
33+
if (dataBindingField == null) {
34+
setDataBindingField();
35+
}
36+
37+
return dataBindingField;
38+
}
39+
40+
private void setDataBindingField() {
41+
dataBindingField = holder.generatedClass.field(JMod.PRIVATE, getClasses().VIEW_DATA_BINDING, "viewDataBinding" + generationSuffix());
42+
}
43+
44+
IJExpression getDataBindingInflationExpression(IJExpression contentViewId, IJExpression container, boolean attachToRoot) {
45+
return getClasses().DATA_BINDING_UTIL.staticInvoke("inflate") //
46+
.arg(getClasses().LAYOUT_INFLATER.staticInvoke("from").arg(holder.getContextRef())) //
47+
.arg(contentViewId) //
48+
.arg(container) //
49+
.arg(attachToRoot);
50+
}
51+
}

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EComponentWithViewSupportHolder.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
import com.helger.jcodemodel.JDefinedClass;
4545
import com.helger.jcodemodel.JExpr;
4646
import com.helger.jcodemodel.JFieldRef;
47+
import com.helger.jcodemodel.JFieldVar;
4748
import com.helger.jcodemodel.JInvocation;
4849
import com.helger.jcodemodel.JMethod;
4950
import com.helger.jcodemodel.JSwitch;
@@ -60,6 +61,7 @@ public abstract class EComponentWithViewSupportHolder extends EComponentHolder i
6061
private JBlock onViewChangedBodyBeforeInjectionBlock;
6162
private JVar onViewChangedHasViewsParam;
6263
protected Map<String, FoundHolder> foundHolders = new HashMap<>();
64+
protected DataBindingDelegate dataBindingDelegate;
6365
protected JMethod findNativeFragmentById;
6466
protected JMethod findSupportFragmentById;
6567
protected JMethod findNativeFragmentByTag;
@@ -73,6 +75,7 @@ public EComponentWithViewSupportHolder(AndroidAnnotationsEnvironment environment
7375
super(environment, annotatedElement);
7476
viewNotifierHelper = new ViewNotifierHelper(this, environment);
7577
keyEventCallbackMethodsDelegate = new KeyEventCallbackMethodsDelegate<>(this);
78+
dataBindingDelegate = new DataBindingDelegate(this);
7679
}
7780

7881
public IJExpression getFindViewByIdExpression(JVar idParam) {
@@ -373,4 +376,12 @@ public JVar getOnKeyUpKeyEventParam() {
373376
return keyEventCallbackMethodsDelegate.getOnKeyUpKeyEventParam();
374377
}
375378

379+
public JFieldVar getDataBindingField() {
380+
return dataBindingDelegate.getDataBindingField();
381+
}
382+
383+
public IJExpression getDataBindingInflationExpression(IJExpression contentViewId, IJExpression container, boolean attachToRoot) {
384+
return dataBindingDelegate.getDataBindingInflationExpression(contentViewId, container, attachToRoot);
385+
}
386+
376387
}

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EFragmentHolder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,14 +252,14 @@ private void setOnDestroyView() {
252252
onDestroyViewAfterSuperBlock = body.blockSimple();
253253
}
254254

255-
private JBlock getOnDestroyViewAfterSuperBlock() {
255+
public JBlock getOnDestroyViewAfterSuperBlock() {
256256
if (onDestroyViewAfterSuperBlock == null) {
257257
setContentViewRelatedMethods();
258258
}
259259
return onDestroyViewAfterSuperBlock;
260260
}
261261

262-
public void clearInjectedView(JFieldRef fieldRef) {
262+
public void clearInjectedView(IJAssignmentTarget fieldRef) {
263263
JBlock block = getOnDestroyViewAfterSuperBlock();
264264
block.assign(fieldRef, _null());
265265
}

AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
/**
22
* Copyright (C) 2010-2016 eBusiness Information, Excilys Group
3+
* Copyright (C) 2016-2017 the AndroidAnnotations project
34
*
45
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
56
* use this file except in compliance with the License. You may obtain a copy of
@@ -32,11 +33,13 @@
3233
import org.androidannotations.internal.core.handler.BackgroundHandler;
3334
import org.androidannotations.internal.core.handler.BeanHandler;
3435
import org.androidannotations.internal.core.handler.BeforeTextChangeHandler;
36+
import org.androidannotations.internal.core.handler.BindingObjectHandler;
3537
import org.androidannotations.internal.core.handler.CheckedChangeHandler;
3638
import org.androidannotations.internal.core.handler.ClickHandler;
3739
import org.androidannotations.internal.core.handler.ColorResHandler;
3840
import org.androidannotations.internal.core.handler.ColorStateListResHandler;
3941
import org.androidannotations.internal.core.handler.CustomTitleHandler;
42+
import org.androidannotations.internal.core.handler.DataBoundHandler;
4043
import org.androidannotations.internal.core.handler.DefaultResHandler;
4144
import org.androidannotations.internal.core.handler.DrawableResHandler;
4245
import org.androidannotations.internal.core.handler.EActivityHandler;
@@ -182,6 +185,7 @@ public List<AnnotationHandler<?>> getHandlers(AndroidAnnotationsEnvironment andr
182185
annotationHandlers.add(new FullscreenHandler(androidAnnotationEnv));
183186
annotationHandlers.add(new RootContextHandler(androidAnnotationEnv));
184187
annotationHandlers.add(new ExtraHandler(androidAnnotationEnv));
188+
annotationHandlers.add(new BindingObjectHandler(androidAnnotationEnv));
185189
annotationHandlers.add(new BeforeTextChangeHandler(androidAnnotationEnv));
186190
annotationHandlers.add(new TextChangeHandler(androidAnnotationEnv));
187191
annotationHandlers.add(new AfterTextChangeHandler(androidAnnotationEnv));
@@ -217,6 +221,8 @@ public List<AnnotationHandler<?>> getHandlers(AndroidAnnotationsEnvironment andr
217221
annotationHandlers.add(new PreferenceClickHandler(androidAnnotationEnv));
218222
annotationHandlers.add(new AfterPreferencesHandler(androidAnnotationEnv));
219223

224+
annotationHandlers.add(new DataBoundHandler(androidAnnotationEnv));
225+
220226
annotationHandlers.add(new TraceHandler(androidAnnotationEnv));
221227

222228
/*
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* Copyright (C) 2016-2017 the AndroidAnnotations project
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
5+
* use this file except in compliance with the License. You may obtain a copy of
6+
* the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed To in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations under
14+
* the License.
15+
*/
16+
package org.androidannotations.internal.core.handler;
17+
18+
import javax.lang.model.element.Element;
19+
import javax.lang.model.element.ElementKind;
20+
import javax.lang.model.element.ExecutableElement;
21+
22+
import org.androidannotations.AndroidAnnotationsEnvironment;
23+
import org.androidannotations.ElementValidation;
24+
import org.androidannotations.annotations.BindingObject;
25+
import org.androidannotations.annotations.EFragment;
26+
import org.androidannotations.handler.MethodInjectionHandler;
27+
import org.androidannotations.helper.CanonicalNameConstants;
28+
import org.androidannotations.helper.InjectHelper;
29+
import org.androidannotations.holder.EComponentWithViewSupportHolder;
30+
import org.androidannotations.holder.EFragmentHolder;
31+
import org.androidannotations.internal.rclass.ProjectRClassFinder;
32+
33+
import com.helger.jcodemodel.IJAssignmentTarget;
34+
import com.helger.jcodemodel.JBlock;
35+
import com.helger.jcodemodel.JDirectClass;
36+
import com.helger.jcodemodel.JExpr;
37+
38+
public class BindingObjectHandler extends CoreBaseAnnotationHandler<EComponentWithViewSupportHolder> implements MethodInjectionHandler<EComponentWithViewSupportHolder> {
39+
40+
private final InjectHelper<EComponentWithViewSupportHolder> injectHelper;
41+
42+
public BindingObjectHandler(AndroidAnnotationsEnvironment environment) {
43+
super(BindingObject.class, environment);
44+
injectHelper = new InjectHelper<>(validatorHelper, this);
45+
}
46+
47+
@Override
48+
protected void validate(Element element, ElementValidation validation) {
49+
if (element.getKind() == ElementKind.METHOD || element.getKind() == ElementKind.PARAMETER) {
50+
ExecutableElement methodElement = (ExecutableElement) (element.getKind() == ElementKind.METHOD ? element : element.getEnclosingElement());
51+
52+
validatorHelper.param.extendsType(CanonicalNameConstants.VIEW_DATA_BINDING).validate(methodElement, validation);
53+
54+
if (!validation.isValid()) {
55+
return;
56+
}
57+
}
58+
59+
injectHelper.validate(BindingObject.class, element, validation);
60+
61+
if (validation.isValid()) {
62+
validatorHelper.isNotPrivate(element, validation);
63+
validatorHelper.extendsType(injectHelper.getParam(element), CanonicalNameConstants.VIEW_DATA_BINDING, validation);
64+
}
65+
}
66+
67+
@Override
68+
public void validateEnclosingElement(Element element, ElementValidation valid) {
69+
coreValidatorHelper.checkDataBoundAnnotation(element.getEnclosingElement(), valid);
70+
coreValidatorHelper.hasEActivityOrEFragmentOrEViewGroup(element.getEnclosingElement(), element, valid);
71+
coreValidatorHelper.enclosingElementHasDataBoundAnnotation(element, valid);
72+
}
73+
74+
@Override
75+
public void process(Element element, EComponentWithViewSupportHolder holder) throws Exception {
76+
injectHelper.process(element, holder);
77+
78+
if (element.getKind() == ElementKind.FIELD && holder instanceof EFragment) {
79+
((EFragmentHolder) holder).clearInjectedView(JExpr._this().ref(element.getSimpleName().toString()));
80+
}
81+
}
82+
83+
@Override
84+
public JBlock getInvocationBlock(EComponentWithViewSupportHolder holder) {
85+
return holder.getOnViewChangedBodyAfterInjectionBlock();
86+
}
87+
88+
@Override
89+
public void assignValue(JBlock targetBlock, IJAssignmentTarget fieldRef, EComponentWithViewSupportHolder holder, Element element, Element param) {
90+
String bindingClassQualifiedName;
91+
92+
if (!param.asType().toString().contains(".")) { // the class is generated in this round, so only the simple name is available
93+
String resourcePackageName = getEnvironment().getOptionValue(ProjectRClassFinder.OPTION_RESOURCE_PACKAGE_NAME);
94+
95+
if (resourcePackageName == null) {
96+
resourcePackageName = getEnvironment().getAndroidManifest().getApplicationPackage();
97+
}
98+
99+
bindingClassQualifiedName = resourcePackageName + ".databinding." + param.asType().toString();
100+
} else {
101+
bindingClassQualifiedName = param.asType().toString();
102+
}
103+
104+
JDirectClass bindingClass = getCodeModel().directClass(bindingClassQualifiedName);
105+
targetBlock.add(fieldRef.assign(JExpr.cast(bindingClass, holder.getDataBindingField())));
106+
}
107+
}

0 commit comments

Comments
 (0)