Program/Android Java

리플렉션(Reflection)을 활용한 안드로이드 위젯 매핑(Mapping) 간소화 하기 (2)

너구리V 2012. 6. 28. 17:49

1. 리플렉션(Reflection)을 활용한 안드로이드 위젯 매핑(Mapping) 간소화 하기(1)
2. 리플렉션(Reflection)을 활용한 안드로이드 위젯 매핑(Mapping) 간소화 하기(2)

리플렉션(Reflection)을 활용한 안드로이드 위젯 매핑(Mapping) 간소화 하기(1) 에서는 리플렉션을 사용해서 다음과 같은 작업을 진행했습니다.

1. Reflection으로 액티비티에 선언된 필드 리스트 가져오기
2. 필드명으로 리소스 identifier 값 (R.id.XXXX)을 가져오기
3. findViewById(R.id.xxx) 으로 View 가져오기
4. Reflection으로 필드에 View Injection

위젯의 id 값과 필드의 이름이 일치한다는 규칙을 정한 것으로 간소화 작업을 진행한 것입니다.
헌데 Inject 될 View와 아닌 View가 같이 섞여 있다거나 R.id.xxxx 값을 찾는 것이 성능상 안좋아 Annotation 기반으로 바꾸어 UI Mapping을 간소화하려고 합니다.


@InjectView(id=R.id.textview)
TextView textview;

위와 같은 결과를 얻게 되는 것이겠죠.
실작업은 다음과 같이 이루어 집니다.

1. Custom Annotation 만들기(InjectView)
2. 필드에서 어노테이션을 가져와서 처리
3. mappingView 함수 매번 호출하지 않게 변경(Activity 클래스를 상속하는 것이 아닌 InjectViewActivity 클래스 상속으로 변경)

Custom Annotation인 InjectView.java 파일을 먼저 만듭니다.

1
2
3
4
5
6
7
8
9
10
11
12
package org.softwaregeeks;
 
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
 
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
    int id() default 0;
}

그리고 리플렉션(Reflection)을 활용한 안드로이드 위젯 매핑(Mapping) 간소화 하기(1)에서 보았던 mappingViews 메소드를 InjectViewActivity로 옮기고 아래 코드를 추가합니다.

1
2
3
4
InjectView injectView = field.getAnnotation(InjectView.class);
if( injectView == null )
  continue;
int identifier = injectView.id();

InjectViewActivity.java 전체소스는 다음과 같습니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package org.softwaregeeks;
 
import java.lang.reflect.Field;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
 
public class InjectViewActivity extends Activity {
    private static void mappingViews(Object object) {
         
        if( !(object instanceof Activity) )
            return;
         
        Activity activity = (Activity)object;
         
        Field[] fields = activity.getClass().getDeclaredFields();
        for(Field field : fields) {
             
            InjectView injectView = field.getAnnotation(InjectView.class);
            if( injectView == null )
                continue;
             
            int identifier = injectView.id();
            if( identifier == 0 ) {
                String identifierString = field.getName();
                identifier = activity.getResources().getIdentifier(identifierString, "id", activity.getPackageName());
            }
             
            if( identifier == 0 )
                continue;
             
            View view = activity.findViewById(identifier);
            if( view == null)
                continue;
             
            if(view.getClass() == field.getType()) {
                try {
                    field.setAccessible(true);
                    field.set(object, view);
                } catch (IllegalArgumentException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
             
            Log.i("Inject", field.getName()  + "," + identifier + "," + view);
        }
    }
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
        mappingViews(this);
        super.onCreate(savedInstanceState);
    }
}

실제 사용하면 복잡한 매핑과정들이 아주 깔끔해집니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package org.softwaregeeks;
 
import java.lang.reflect.Field;
 
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
 
public class HelloWorldActivity extends InjectViewActivity {
     
    @InjectView(id=R.id.hello1)
    private TextView hello1;
     
    @InjectView
    private TextView hello2;
     
    @InjectView
    private TextView hello3;
     
    @InjectView
    private TextView hello4;
     
    @InjectView
    private TextView hello5;
     
    @Override
    public void onCreate(Bundle savedInstanceState) {
        setContentView(R.layout.main);
        super.onCreate(savedInstanceState);
         
        hello1.setText("테스트");
        hello2.setText("테스트2");
        hello3.setText("테스트3");
         
//        hello1 = (TextView)findViewById(R.string.hello1);
//        hello2 = (TextView)findViewById(R.string.hello2);
//        hello3 = (TextView)findViewById(R.string.hello3);
//        hello4 = (TextView)findViewById(R.string.hello4);
//        hello5 = (TextView)findViewById(R.string.hello5);
    }
}

눈으로 보고 싶으신 분들을 위해 스크린캐스트로 제공하고 있으니 간소화하는 방법을 보시죠~
그럼 도움이 되셨길 바랍니다~ :D



반응형