Providing bindings for ListViews #2

Open
wants to merge 4 commits into
from
@@ -19,7 +19,11 @@
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
import java.util.Set;
import android.app.Activity;
@@ -46,6 +50,7 @@
public static boolean LOG_PERFORMANCE;
protected final Context context;
+ protected final View ui;
protected final Object target;
protected final Activity activity;
protected final Resources resources;
@@ -59,10 +64,15 @@ public Injector(Context context) {
}
public Injector(Context context, Object target) {
+ this(context, null, target);
+ }
+
+ public Injector(Context context, View ui, Object target) {
if (context == null || target == null) {
throw new IllegalArgumentException("Context/target may not be null");
}
this.context = context;
+ this.ui = ui;
this.target = target;
resources = context.getResources();
if (context instanceof Activity) {
@@ -80,7 +90,7 @@ public Injector(Context context, Object target) {
clazz = target.getClass();
}
- public static Injector injectInto(Context context) {
+ public static Injector injectInto(Context context) {
return inject(context, context);
}
@@ -90,6 +100,12 @@ public static Injector inject(Context context, Object target) {
return injector;
}
+ public static Injector inject(Context context, View view, Object target) {
+ Injector injector = new Injector(context, view, target);
+ injector.injectAll();
+ return injector;
+ }
+
/** Injects into fields and wires methods. */
public void injectAll() {
injectFields();
@@ -99,7 +115,7 @@ public void injectAll() {
/** Injects into fields. */
public void injectFields() {
long start = System.currentTimeMillis();
- Field[] fields = clazz.getDeclaredFields();
+ Collection<Field> fields = getAllFields(clazz);
for (Field field : fields) {
Annotation[] annotations = field.getAnnotations();
for (Annotation annotation : annotations) {
@@ -120,14 +136,14 @@ public void injectFields() {
}
if (LOG_PERFORMANCE) {
long time = System.currentTimeMillis() - start;
- Log.d("greenInject", "Injected fields in " + time + "ms (" + fields.length + " fields checked)");
+ Log.d("greenInject", "Injected fields in " + time + "ms (" + fields.size() + " fields checked)");
}
}
- /** Wires OnClickListeners to methods. */
+ /** Wires OnClickListeners to methods. */
public void bindMethods() {
long start = System.currentTimeMillis();
- Method[] methods = clazz.getDeclaredMethods();
+ Collection<Method> methods = getAllMethods(clazz); // TODO get recursive
Set<View> modifiedViews = new HashSet<View>();
for (final Method method : methods) {
Annotation[] annotations = method.getAnnotations();
@@ -139,11 +155,11 @@ public void bindMethods() {
}
if (LOG_PERFORMANCE) {
long time = System.currentTimeMillis() - start;
- Log.d("greenInject", "Bound methods in " + time + "ms (" + methods.length + " methods checked)");
+ Log.d("greenInject", "Bound methods in " + time + "ms (" + methods.size() + " methods checked)");
}
}
- protected boolean bindOnClickListener(final Method method, OnClick onClick, Set<View> modifiedViews) {
+ protected boolean bindOnClickListener(final Method method, OnClick onClick, Set<View> modifiedViews) {
Class<?>[] parameterTypes = method.getParameterTypes();
boolean invokeWithView;
if (parameterTypes.length == 0) {
@@ -206,7 +222,14 @@ protected View findView(Member field, int viewId) {
throw new InjectException("Views can be injected only in activities (member " + field.getName() + " in "
+ context.getClass());
}
- View view = activity.findViewById(viewId);
+ View view = null;
+ if (ui != null) {
+ view = ui.findViewById(viewId);
+ }
+ if (view == null) {
+ // fall back to activity if it's not found in ui
+ view = activity.findViewById(viewId);
+ }
if (view == null) {
throw new InjectException("View not found for member " + field.getName());
}
@@ -218,7 +241,7 @@ private void checkValueBinder() {
if (activity == null) {
throw new InjectException("Value binding requires an activity");
}
- valueBinder = new ValueBinder(activity, target);
+ valueBinder = new ValueBinder(activity, ui, target);
}
}
@@ -234,4 +257,32 @@ public void uiToValues() {
valueBinder.uiToValues();
}
+ private Collection<Method> getAllMethods(Class<?> type) {
+ List<Method> methods = new LinkedList<Method>();
+ methods.addAll(Arrays.asList(type.getDeclaredMethods()));
+
+ if (type.getSuperclass() != null) {
+ methods.addAll(getAllMethods(type.getSuperclass()));
+ }
+ for( Class<?> intf : type.getInterfaces() ) {
+ methods.addAll(getAllMethods(intf));
+ }
+
+ return methods;
+ }
+
+ private Collection<Field> getAllFields(Class<?> type) {
+ List<Field> fields = new LinkedList<Field>();
+ fields.addAll(Arrays.asList(type.getDeclaredFields()));
+
+ if (type.getSuperclass() != null) {
+ fields.addAll(getAllFields(type.getSuperclass()));
+ }
+ for( Class<?> intf : type.getInterfaces() ) {
+ fields.addAll(getAllFields(intf));
+ }
+
+ return fields;
+ }
+
}
@@ -18,6 +18,9 @@
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -27,6 +30,7 @@
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.View;
+import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.TextView;
import de.greenrobot.inject.annotation.Value;
@@ -43,6 +47,7 @@
protected final Object target;
protected final Activity activity;
+ protected final View ui;
protected List<Field> valueFields;
protected List<View> valueViews;
@@ -57,16 +62,28 @@ public ValueBinder(Activity activity) {
/** If the value fields are in a object different from the activity. */
public ValueBinder(Activity activity, Object target) {
+ this(activity, null, target);
+ }
+
+ /** If the value fields are in a object different from the activity. */
+ public ValueBinder(Activity activity, View ui, Object target) {
if (activity == null || target == null) {
throw new IllegalArgumentException("Context/target may not be null");
}
this.activity = activity;
+ this.ui = ui;
this.target = target;
clazz = target.getClass();
}
protected View findView(Member field, int viewId) {
- View view = activity.findViewById(viewId);
+ View view = null;
+ if (ui != null) {
+ view = ui.findViewById(viewId);
+ }
+ if (view == null) {
+ view = activity.findViewById(viewId);
+ }
if (view == null) {
throw new InjectException("View not found for member " + field.getName());
}
@@ -89,8 +106,12 @@ public void valuesToUi() {
} catch (Exception e) {
throw new InjectException("Could not get value for field " + field.getName(), e);
}
- if (view instanceof TextView) {
- ((TextView) view).setText(value != null ? value.toString() : null);
+ if (view instanceof CompoundButton) {
+ if( value != null ) {
+ ((CompoundButton) view).setChecked( ((Boolean)value).booleanValue() );
+ }
+ } else if (view instanceof TextView) {
+ ((TextView) view).setText(value != null ? value.toString() : null);
} else if (view instanceof ImageView) {
ImageView imageView = (ImageView) view;
if (value == null || value instanceof Bitmap) {
@@ -121,7 +142,10 @@ public void uiToValues() {
Field field = valueFields.get(i);
View view = valueViews.get(i);
- if (view instanceof TextView) {
+ if (view instanceof CompoundButton) {
+ boolean value = ((CompoundButton) view).isChecked();
+ injectIntoField(field, value);
+ } else if (view instanceof TextView) {
String value = ((TextView) view).getText().toString();
injectIntoField(field, value);
}
@@ -149,7 +173,7 @@ protected void checkValueFields() {
if (valueFields == null || valueViewIds == null) {
valueFields = new ArrayList<Field>();
valueViewIds = new ArrayList<Integer>();
- Field[] fields = clazz.getDeclaredFields();
+ Collection<Field> fields = getAllFields(clazz); // TODO get recursive
for (Field field : fields) {
Value annotation = field.getAnnotation(Value.class);
if (annotation != null) {
@@ -183,5 +207,19 @@ public void refreshUiViews() {
valueViews.add(view);
}
}
+
+ private Collection<Field> getAllFields(Class<?> type) {
+ List<Field> fields = new LinkedList<Field>();
+ fields.addAll(Arrays.asList(type.getDeclaredFields()));
+
+ if (type.getSuperclass() != null) {
+ fields.addAll(getAllFields(type.getSuperclass()));
+ }
+ for( Class<?> intf : type.getInterfaces() ) {
+ fields.addAll(getAllFields(intf));
+ }
+
+ return fields;
+ }
}
@@ -10,5 +10,6 @@
<uses-library android:name="android.test.runner" />
<activity android:name="TestActivity"></activity>
+ <activity android:name="TestInheritedActivity"></activity>
</application>
</manifest>
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<RelativeLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <TextView android:layout_height="wrap_content" android:text="TextView" android:layout_width="wrap_content" android:layout_alignParentTop="true" android:layout_alignParentLeft="true" android:id="@+id/itemLabel"></TextView>
+ <Button android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="Button" android:layout_alignParentTop="true" android:layout_alignParentRight="true" android:layout_marginRight="20dp" android:id="@+id/itemButton"></Button>
+
+</RelativeLayout>
@@ -44,6 +44,7 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"></Button>
</LinearLayout>
+ <CheckBox android:text="CheckBox" android:id="@+id/checkBox1" android:layout_width="wrap_content" android:layout_height="wrap_content"></CheckBox>
<EditText
android:id="@+id/editText1"
android:layout_width="fill_parent"
@@ -52,4 +53,5 @@
</EditText>
<ImageView android:layout_width="wrap_content" android:id="@+id/imageView1" android:layout_height="wrap_content"></ImageView>
<ImageView android:layout_width="wrap_content" android:id="@+id/imageView2" android:layout_height="wrap_content"></ImageView>
+ <ListView android:layout_height="wrap_content" android:layout_width="fill_parent" android:id="@+id/listView"></ListView>
</LinearLayout>
@@ -25,16 +25,19 @@
import android.test.UiThreadTest;
import android.view.View;
import android.widget.Button;
+import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ImageView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
import android.widget.TextView;
import de.greenrobot.inject.Injector;
-public class ActivityInjectTest extends ActivityInstrumentationTestCase2<TestActivity> {
+public class ActivityInjectTest extends ActivityInstrumentationTestCase2<TestInheritedActivity> {
private final boolean methodTracing = false;
public ActivityInjectTest() {
- super("de.greenrobot.inject.test", TestActivity.class);
+ super("de.greenrobot.inject.test", TestInheritedActivity.class);
}
protected void setUp() throws Exception {
@@ -58,11 +61,14 @@ protected void tearDown() throws Exception {
public void testInject() {
TestActivity activity = getActivity();
assertNotNull(activity.textViewReference);
+ assertNotNull(activity.listViewReference);
assertNull(activity.textView);
+ assertNull(activity.listView);
assertNull(activity.app_name);
assertNull(activity.icon);
Injector.injectInto(activity);
assertSame(activity.textViewReference, activity.textView);
+ assertSame(activity.listViewReference, activity.listView);
assertEquals(activity.getString(R.string.app_name), activity.app_name);
BitmapDrawable drawable = (BitmapDrawable) activity.getResources().getDrawable(R.drawable.icon);
assertEquals(drawable.getBitmap().getHeight(), activity.icon.getBitmap().getHeight());
@@ -80,6 +86,27 @@ public void testClick() {
assertTrue(activity.button1Clicked);
}
+ @UiThreadTest
+ public void testItemClick() {
+ TestActivity activity = getActivity();
+ Injector.injectInto(activity);
+
+ ListView list = (ListView)activity.findViewById(R.id.listView);
+ ListAdapter adapter = list.getAdapter();
+ TestItemHolder item0 = (TestItemHolder) adapter.getItem(0);
+ TestItemHolder item1 = (TestItemHolder) adapter.getItem(1);
+ assertFalse(item0.clicked);
+ assertFalse(item1.clicked);
+
+ list.setSelection(0);
+ View itemView = list.getSelectedView();
+ Button button = (Button) itemView.findViewById(R.id.itemButton);
+ assertTrue(button.performClick());
+
+ assertTrue(item0.clicked);
+ assertFalse(item1.clicked);
+ }
+
@UiThreadTest
public void testClickTwoViews() {
TestActivity activity = getActivity();
@@ -141,6 +168,24 @@ public void testValue() {
assertEquals("tiger", activity.value);
}
+ @UiThreadTest
+ public void testCheckBox() {
+ TestActivity activity = getActivity();
+ Injector injector = new Injector(activity);
+
+ assertFalse(activity.check);
+
+ activity.check = true;
+ injector.valuesToUi();
+
+ CheckBox checkBox = (CheckBox) activity.findViewById(R.id.checkBox1);
+ assertTrue(checkBox.isChecked());
+
+ checkBox.setChecked(false);
+ injector.uiToValues();
+ assertFalse(activity.check);
+ }
+
@UiThreadTest
public void testValueImageViewResId() {
TestActivity activity = getActivity();
Oops, something went wrong.