1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.example.android.voicemail.common.inject; 18 19 import android.app.Activity; 20 21 import java.lang.annotation.Annotation; 22 import java.lang.reflect.Field; 23 24 /** 25 * Very lightweight form of injection, inspired by RoboGuice, for injecting common ui elements. 26 * <p> 27 * Usage is very simple. In your Activity, define some fields as follows: 28 * 29 * <pre class="code"> 30 * @InjectView(R.id.fetch_button) 31 * private Button mFetchButton; 32 * @InjectView(R.id.submit_button) 33 * private Button mSubmitButton; 34 * @InjectView(R.id.main_view) 35 * private TextView mTextView; 36 * </pre> 37 * <p> 38 * Then, inside your Activity's onCreate() method, perform the injection like this: 39 * 40 * <pre class="code"> 41 * setContentView(R.layout.main_layout); 42 * Injector.get(this).inject(); 43 * </pre> 44 * <p> 45 * See the {@link #inject()} method for full details of how it works. Note that the fields are 46 * fetched and assigned at the time you call {@link #inject()}, consequently you should not do this 47 * until after you've called the setContentView() method. 48 */ 49 public final class Injector { 50 private final Activity mActivity; 51 52 private Injector(Activity activity) { 53 mActivity = activity; 54 } 55 56 /** 57 * Gets an {@link Injector} capable of injecting fields for the given Activity. 58 */ 59 public static Injector get(Activity activity) { 60 return new Injector(activity); 61 } 62 63 /** 64 * Injects all fields that are marked with the {@link InjectView} annotation. 65 * <p> 66 * For each field marked with the InjectView annotation, a call to 67 * {@link Activity#findViewById(int)} will be made, passing in the resource id stored in the 68 * value() method of the InjectView annotation as the int parameter, and the result of this call 69 * will be assigned to the field. 70 * 71 * @throws IllegalStateException if injection fails, common causes being that you have used an 72 * invalid id value, or you haven't called setContentView() on your Activity. 73 */ 74 public void inject() { 75 for (Field field : mActivity.getClass().getDeclaredFields()) { 76 for (Annotation annotation : field.getAnnotations()) { 77 if (annotation.annotationType().equals(InjectView.class)) { 78 try { 79 Class<?> fieldType = field.getType(); 80 int idValue = InjectView.class.cast(annotation).value(); 81 field.setAccessible(true); 82 Object injectedValue = fieldType.cast(mActivity.findViewById(idValue)); 83 if (injectedValue == null) { 84 throw new IllegalStateException("findViewById(" + idValue 85 + ") gave null for " + 86 field + ", can't inject"); 87 } 88 field.set(mActivity, injectedValue); 89 field.setAccessible(false); 90 } catch (IllegalAccessException e) { 91 throw new IllegalStateException(e); 92 } 93 } 94 } 95 } 96 } 97 } 98