'android'에 해당되는 글 36건

  1. 2013.06.05 [android] 2D 그래픽 엔진 Skia
  2. 2013.05.31 [android] Volley - Network & ImageLoading 라이브러리 ( google I/O 2013 )
  3. 2013.05.24 SharedPreferences 사용시 주의점
  4. 2013.05.16 [android] 새로운 android 개발환경 "android studio"
  5. 2013.05.15 [android] checkstyle 설치및 gen 폴더 제거 설정 1
  6. 2013.05.10 [android] maven 빌드시 @SuppressLint 오류 발생 해결하기
  7. 2013.04.29 [android] TextView의 maxLines과 ellipsize 버그
  8. 2013.04.18 [android] FLAG_ACTIVITY_SINGLE_TOP으로 activity 실행시 intent 받아 처리하기
  9. 2013.04.10 [android] TextView 코드로 생성하면서 style 적용하기
  10. 2013.03.25 [android] View의 setClickable() 과 setOnClickListener() 의 관계

[android] 2D 그래픽 엔진 Skia

android 2013. 6. 5. 14:28

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

안드로이드에서 2D 그래픽 엔진( Graphic engine ) 으로 사용하고 있는 것은 Skia라는 이름의 엔진이다. 개발밥을 먹으면서 써보지는 않았어도 대충 들어는 봤어야 하는데, 생전 처음 듣는 이름 이었다. 역사를 찾아 보니 아래와 같은 기사가 있었다. [1]


게다가 구글은 그 분야의 인수 및 인재 조달도 추진 중이다. 소형기기 제조엡체인 데인저(Danger)의 설립자이자 뒤에 휴대 전화용 소프트웨어 제조업체인 앤드로이드(Android)를 설립한 앤디 루빈(Andy Rubin)은 앤드로이드의 인수와 함께 2005년에 구글에 입사했다.

또한 구글은 모바일 애플리케이션 개발 기업인 레큐와이어리스(Reqwireless) 및 스키아(Skia)라는 기업도 인수했다. 스키아의 첫 제품은 휴대 기기로 2D 그래픽스를 렌더링하는 휴대용 그래픽 엔진이다.

 

안드로이드를 2005 8월에 인수하였고, Skia는 같은해 11월에 인수 하였다. [2]

 

안드로이드에서 GUI를 담당하는 중추 역할인 그래픽엔진임에도 관련 자료가 많이 없는 것 같다. 안드로이드가 openSource 이긴 한데, Skia 관련 자료가 부족한 이유는 google에서 주도적으로 개발하면서 관련된 문서 및 reference가 빈약하기 때문인 것 같다.

 

구글에서 제공하는 skiadocs page에서 약간의 정보를 찾을 수 있었다. [3]

Skia is a complete 2D graphic library for drawing Text, Geometries, and Images.

  • 3x3 matrices w/ perspective
  • antialiasing, transparency, filters
  • shaders, xfermodes, maskfilters, patheffects
  • subpixel text

Device backends for Skia currently include:

  • Raster
  • OpenGL
  • PDF
  • XPS
  • Picture (for recording and then playing back into another Canvas)

 

 

skia에도 GPU 를 직접 사용해서 hardware acceleration을 사용하는 구조가 있는데, 안드로이드 View System은 독자적인 GPU 지원 구조를 만들어서 사용하고 있다고 한다.

 

아래 그림은 안드로이드의 그래픽 서브 시스템을 도식화한 것이다. [4]

 

 

우리가 많이 사용하는 Canvas HWUISkia를 이용해서 Surface로 요청을 하는 구조이다. 3.0 이전에는 Skia로 다 처리되던 것이 3.0 이후부터는 성능 이슈로 인해서 skia 부분이 점점 HWUI로 대체되고 있다. HWUI 모듈은 GPU를 사용하는 UI component 이다. Android 3.0 부터 tablet에 대한 지원이 되었는데, tablet이 화면이 크다보니 기존에 사용하던 skia로는 animation이 매끄럽지 않아서  HWUIrenderscript 같은 것이 등장하게 된 것 이다.

 

Skia에 대해서 더 궁금한분은 직접 소스를 받아 보시길.. [5]

 

참고

[1] 신문기사: http://www.zdnet.co.kr/news/news_view.asp?artice_id=00000039156220&type=det

[2] http://academic.naver.com/view.nhn?doc_id=47296809&dir_id=0&page=0&query=Android%20skia&ndsCategoryId=20300

[3] 스키아 문서 : https://sites.google.com/site/skiadocs/home

[4] 안드로이드 그래픽 서브 시스템 : http://developer.mips.com/2012/04/11/learning-about-android-graphics-subsystem/

[5] skia 소스 : https://android.googlesource.com/platform/external/skia/

 

 

 



:

[android] Volley - Network & ImageLoading 라이브러리 ( google I/O 2013 )

android 2013. 5. 31. 14:32

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

Google I/O 2013에서 volley 라는 새로운 라이브러리를 발표했습니다. 주요 역할은 Http통신 및 이미지 로딩을 해주는 것입니다.

 

주요 특징

* requestQueue를 이용한 동시요청 처리

* 요청 우선순위 설정 가능 ( A요청이 B요청보다 먼저 응답을 받아야 할 경우 )

* 요청 취소 기능 ( adapter 같은 곳에서 scrolling 이 빠른경우 응답이 않왔을때는 취소가 필요하죠. )

* android 하위 버전(2.3)에서 존재하던 HttpURLConnection의 버그 해결

* NetworkImageView 제공

 

Google I/O의 발표영상

 

 

초간단 사용법

 

// 초기화

mQueue = Volley.newRequestQueue(context);// thread pool(4)

            

mImageLoader = new ImageLoader(mQueue, new BitmapCache());

기본으로 4개의 thread pool을 사용하게 되어 있다. 

 

 

// requestQueue 이용

final ImageView imageView = (ImageView) findViewById(R.id.image_view);

 

// clear

imageView.setImageBitmap(null);

 

// start load

Listener<Bitmap> listener = new Listener<Bitmap>() {

@Override

public void onResponse(Bitmap result) {

imageView.setImageBitmap(result);

}

};

 

ErrorListener errorListener = new ErrorListener() {

@Override

public void onErrorResponse(VolleyError error) {

       // error handling

       }

};

 

ImageRequest imageRequest = new ImageRequest(URL_IMAGE, listener, 0, 0, Config.ARGB_8888, errorListener);

imageRequest.setTag(TAG);

mQueue.add(imageRequest);

 ImageRequest를 생성해서 큐(queue)에 넣어주면 되는데, ImageRequest에  url과 성공, 실패시 처리할 리스터(listener)를 넘겨준다.

 

// NetworkImageView 이용

NetworkImageView imageView = (NetworkImageView) findViewById(R.id.network_image_view);

 

// clear

imageView.setImageUrl(null, null);

 

// start load

imageView.setImageUrl(URL_IMAGE, mImageLoader);

NetworkImageView는 정말 간단하다. 그냥 url 과 imageLoader만 넘겨주면 된다.  

 

// GET 호출 ( with parameter )

Listener<String> listener = new Listener<String>() {

                    @Override

                    public void onResponse(String result) {

                           // some action

                    }

             };

 

String uri = String.format("http://somesite.com/some_endpoint.php?param1=%1$s&param2=%2$s", num1, num2);

             StringRequest myReq = new StringRequest(Method.GET,

                    uri,

                    listener,

                    errorListener);

             mQueue.add(myReq);

GET 방식으로 이미지 호출이 아닌 api 호출해서 data를 받아 오는 경우도 흔하므로 위와 같이 StringRequest 이용해서 사용하면 된다. Parameter Get  방식이므로 url 전달하면 된다. ( Json 형식을 사용할땐, StringRequest 대신에 JsonRequest를 사용하면 된다. )

 

// POST 호출 ( with parameter )

StringRequest myReq = new StringRequest(Method.POST,

                    "http://somesite.com/some_endpoint.php",

                    listener,

                    errorListener) {

 

                    @Override

                    protected Map<String, String> getParams() throws com.android.volley.AuthFailureError {

                           Map<String, String> params = new HashMap<String, String>();

                           params.put("param1", num1);

                           params.put("param2", num2);

                           return params;

                    };

             };

             mQueue.add(myReq);

Post로 호출할 경우에는 StringRequestgetParams() 함수를 overriding 해주면 된다. 리턴형식으로 Map<String, String>을 사용하므로 여러 개의 파라미터를 전달 할 수 있다.

 

 

<참고>

valley : https://android.googlesource.com/platform/frameworks/volley

샘플 : https://github.com/ogrebgr/android_volley_examples

 

 

 



:

SharedPreferences 사용시 주의점

android 2013. 5. 24. 20:46

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

1. 가장 흔하게 실수하는 case

SharedPreferences preference = context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);

preference.edit().putBoolean(“testKey”, 10);

preference.edit().commit();

 

edit()를 각각 호출함으로써  editor A 에 값을 설정하고, editor B 를 커밋한 경우입니다. Edit() 설명을 보면 아래와 같습니다.

/**

     * Create a new Editor for these preferences, through which you can make

     * modifications to the data in the preferences and atomically commit those

     * changes back to the SharedPreferences object.

     *

     * <p>Note that you <em>must</em> call {@link Editor#commit} to have any

     * changes you perform in the Editor actually show up in the

     * SharedPreferences.

     *

     * @return Returns a new instance of the {@link Editor} interface, allowing

     * you to modify the values in this SharedPreferences object.

     */

    Editor edit();

리턴부분을 보면 new instance 라고 되어 있습니다. 즉 항상 새로운 editor instance를 반환하도록 되어 있습니다.  

 

2. Multi-process 환경에서

 

SharedPreferences를 이용하여 주로 설정값을 저장하는 용도로 사용하고 있습니다. 그런데 저장한 값이 읽어지지 않는 경우가 있었습니다. 더 정확하게는 예전의 값이 그대로 유지되는 경우입니다 

경험한 환경은 아래와 같습니다.

 

ProcessA에서 int 10을 씁니다 

SharedPreferences preference = context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);

Editor editor = preference.edit();

editor.putBoolean(“testKey”, 10);

editor.commit();

 

ProcessB에서 값을 읽습니다 ( 값이 않읽어진다. )

SharedPreferences preference = context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_PRIVATE);

int localeIdx = preference.getInt(“testKey”, -1);

 

아래의 API 문서에서도 나와 있듯이 SharedPreferences는 process 사이에서 communication하기 좋은 방법입니다. 그런데 안된다 ㅠㅠ

API 문서를 찾아보니 아래와 같습니다 

public static final int MODE_MULTI_PROCESS

Added in API level 11

SharedPreference loading flag: when set, the file on disk will be checked for modification even if the shared preferences instance is already loaded in this process. This behavior is sometimes desired in cases where the application has multiple processes, all writing to the same SharedPreferences file. Generally there are better forms of communication between processes, though.

This was the legacy (but undocumented) behavior in and before Gingerbread (Android 2.3) and this flag is implied when targetting such releases. For applications targetting SDK versions greater than Android 2.3, this flag must be explicitly set if desired.

 

간단히 볼드부분을 번역하면 아래와 같습니다.

Gingerbread (Android2.3) 까지는 기본으로 MODE_MULTI_PROCESS가 설정되어 있었다.

Target SDK 버전이 Gingerbread (Android2.3) 보다 높으면 명시적으로 설정해야 된다.

( API level이 11 이므로 3.0 부터 사용하능하다는 이야기니까, 2.3 까지는 않써도 된다고 생각함. 그러나 버전 상관없이 다 동작하려면 항상 써주는게 좋다. )

결론은 아래처럼 변경하면 됩니다.

 

SharedPreferences preference = context.getSharedPreferences(PREFERENCE_FILE_NAME, Context.MODE_MULTI_PROCESS); // 여기

int localeIdx = preference.getInt(“testKey”, -1);

 

코드상으로는 MODE_PRIVATE | MODE_MULTI_PROCESS 이렇게 해주는 좋을것 같으나,

정의를 보면 MODE_PRIVATE 가 0으로 정의되어 있어서 그냥 MODE_MULTI_PROCESS 만 적어주었다.

 

public static final int MODE_PRIVATE = 0x0000;

public static final int MODE_MULTI_PROCESS = 0x0004;

 

참고 : http://developer.android.com/reference/android/content/Context.html#MODE_MULTI_PROCESS

 

 

 



:

[android] 새로운 android 개발환경 "android studio"

android 2013. 5. 16. 15:53

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

NDK를 다운받기 위해 안드로이드 개발 page에 들어갔더니 “android studio” 라는 것이 생겼습니다. Studio 하니 예전의 visual studio가 생각이 나면서 연결되는 것은 .Netdesign studio 였습니다. ( Page의 화면도 그렇고 ) 뭔가 XML을 편하게 해주는 것인가..

 

그리고 내용을 보니 IntelliJ 기반의 새로운 android 개발 환경이라고 하네요. Intell-J 는 유료라서 써보고 싶기만 했던 것인데 ( 막연히 eclipse 보다 뭔가 더 좋겠지 라는 생각을 가지고 있는 툴이었고 blog 등을 보면 좋아하는 사람은 엄청 좋아하더라구요.. )

Android studio가 제공하는 것들은 다음과 같다고 합니다.

* gradle 기반의 빌드

* android에 특화된 refactoring과 빠른 오류 수정

* 성능, 사용성, 버전 호환성 등등의 오류를 알려주는 Lint tool

* ProGuard 지원과  App – signing

* 템플릿(Template)기반의 위저드 기능

* 강력해진 layout 편집기, 멀티화면의 미리보기등

 

아직은 early access preview 버전이므로 주의 하시요. ( 버전이 0.1 이므로 완성도가 당연히 떨어지리라 예상함 )

 

검색해보니 Google I/O 2013에서 발표한 것 같네요. 우연히도 빠르게 발견하게 되었네요 ㅎㅎ

아래는 android studio를 소개하는 간단한 영상 입니다.  

 

 

 

 

 

 

 

 

 

 

 



:

[android] checkstyle 설치및 gen 폴더 제거 설정

android 2013. 5. 15. 19:06

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

android에서 checkstyle을 적용하려고 설치하고 적용하다가 몇가지 유용한 것을 발견 하였다.

1. 설치하기

eclipse에서 Help->Install New Software.. 에서 아래를 설정하면 간략하게 local 환경에 설치할수 있다.

http://eclipse-cs.sf.net/update

 

2. checkstyle violations View

메뉴에서 “Window -> Show View -> Others -> checkstyle을 선택한뒤 “checkstyle violoations”를 클릭하면 보인다.  ( 참고로 checkstyle violation char 를 선택하면 차트로 볼 수도 있다. )

그런데 project가 많은경우 보기가 복잡하므로 내가 선택한 project의 위반사항만 보도록 설정한다.  아래 그림의 빨간 버튼을 누르면 환경설정창이 하나 뜬다.  

 

본인은  “on any resource in same project”를 선택하였다.

 

3. gen 폴더 제외 하기

Package explorer에서 원하는 project를 선택한 다음, 마우스 오른쪽버튼을 클릭해서

Checkstyle -> check code with checkstyle을 실행하면 checkstyle을 위반하는 것을 보여준다.

 

이런..  gen 폴더에서 무수히 많은 violations이 발생한다.  android에서 생성하는 gen 폴더는 checkstyle 에서 제외시켜야 한다.

Project의 환경설정에서 “files from packages” check 하고 오늘쪽의  “change” 버튼을 눌러서 제외할 package를 선택하면 된다.

 

 

이 설정을 하고 나면 project 폴더에 .checkstyle 이라는 파일이 생긴다.

내용은 xml 이라서 직감적으로 알 수 있다.

<?xml version="1.0" encoding="UTF-8"?> 

<fileset-config file-format-version="1.2.0" simple-config="true" sync-formatter="false">

  <fileset name="all" enabled="true" check-config-name="My Checks" local="false">

    <file-match-pattern match-pattern="." include-pattern="true"/>

  </fileset>

  <filter name="FilesFromPackage" enabled="true">

    <filter-data value="gen"/>

  </filter>

</fileset-config>

 

 

 



:

[android] maven 빌드시 @SuppressLint 오류 발생 해결하기

android 2013. 5. 10. 21:24

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

eclipse에서 android를 개발하다가 겪게 되는 것 중 하나는 노란색 경고줄이 가면서 마우수를 가져가면 아래처럼 이상한 해결 법이 뜨는 것이다.

 

@SuppressLint 를 추가하면 Lint 에서 해당 코드를 에러로 취급 하지 말라고 선언하는 것이므로, 노란 경고가 보기 싫어서 eclipse가 가이드 하는 대로 @SuppressLint("UseSparseArrays")을 적어줬더니 잘 해결되는 것 같았다.  (적어도 내 local 개발 환경에서는 )  그러나, 빌드 서버에서는 아래와 같은 에러를 뿜고 있군요 ㅠㅠ

 

[INFO]

[INFO] --- maven-compiler-plugin:2.3.2:compile (default-compile) @ android ---

[INFO] Compiling 76 source files to /… 생략… /workspace/target/classes

[INFO] -------------------------------------------------------------

[ERROR] COMPILATION ERROR :

[INFO] -------------------------------------------------------------

[ERROR] /… 생략 … /android/enums/SortType.java:[6,25] package android.annotation does not exist

[ERROR] /… 생략 … /android/enums/SortType.java:[23,2] cannot find symbol

 

빌드 서버에서는 maven을 이용하여 빌드하고 있는데, 위에서 추가한 어노테이션(annotation)을 인식하지 못하여 발생한 듯 합니다.

 

이럴때는 pom.xml에 아래를 추가해주면 됩니다.

 

<dependency>

    <groupId>com.google.android</groupId>

    <artifactId>annotations</artifactId>

    <version>4.1.1.4</version>

</dependency>

 

출처 : https://code.google.com/p/maven-android-plugin/issues/detail?id=287

 

위의  dependency를 추가하면 android에서 사용하는 각종 annotation 들을 maven으로 빌드시 인식하여 빌드가 잘 됩니다.

 

 

 



:

[android] TextView의 maxLines과 ellipsize 버그

android 2013. 4. 29. 21:39

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

기본으로 제공하는 TextView을 이용해서 maxLines ellipse를 이용해서 2줄까지 표시하면서 더 긴경우에는 말줄임으로 하고 싶을때가 있다.  모두가 당연히 아래처럼 설정할 것이다.

 

<TextView

     android:id="@+id/textView1"

     android:layout_width="match_parent"

     android:layout_height="wrap_content"       

     android:maxLines="4"

     android:ellipsize="end"/>

 

maxLines 속성과 ellipsize 속성으로 4줄까지 표시되고 더 긴경우에는 말줄임이 표시되도록 의도한 것이다. Android 4.0에서 확인하면 잘 동작하는데 문제는 2.3이하에서 발생한다. 위처럼 하면 2줄까지 표시되고 말줄임이 되는 것이다.

구글링을 해보니 android의 버그라고 되어 있다.

( 참고 : http://code.google.com/p/android/issues/detail?id=2254 )

관련해서 여러가지 openSource로 해결책이 제시 되어 있다.

 

1. EllipsizingTextView

특징 :

* TextView StaticLayout을 이용하여 특정라인까지의 text를 자르고, 뒤에 을 붙이는 방식

* EllipsizeListener 를 이용하여 말줄임 여부를 체크할수 있도록 되어 있다.

* draw시점에 text를 동적으로 구하는 방식으로 adapter 에서 사용할 경우 성능 이슈가 있을수 있다.

* 확대(expand) / 축소(collapse) 기능 없음.

소스 : https://github.com/KhalidElSayed/EllipsizingTextView

 

 

 

2. TextViewMultilineEllipse

특징

* View를 상속받아서 TextPaint로 각각의 라인을 자르는 방식

* 동적으로 구하는 시점은 onMeasure에서

* 확대 / 축소 기능 있음.

* 내부의 LineBreaker 소스는 참고하면 좋을 듯

* 버그 : space가 없는 문자열인 경우 crash 발생하지만 debugging 하면 금방 고칠수 있음.

* 단점 : View를 상속받아서 TextView의 기능들을 사용할 수 없음 ( , SpannableString )

소스 : http://code.google.com/p/android-textview-multiline-ellipse/source/browse/trunk/TextViewMultilineEllipse.java?r=2

 

결론은 1번의 EllipsizingTextView를 속도 최적화 하여서 사용함.

또다른 버그가 발견했습니다.

Android 4.0 이상에서는 iPhone에서 입력한 이모티콘을 표시해주는 기능이 있는데, 1번의 코드를 사용하면 해당 이모티콘이 안보입니다. TextView를 상속받고 거기서 setText를 하면 발생합니다. 해결책은 여기 참고 https://github.com/sharakova/EmojiTextView/tree/master/src/jp/sharakova/android/emoji

 

* OpenSource는 완벽한게 아니라 해당상황에 대한 간단한 해결책인 경우가 많다. 사용시 여러방면의 test가 필요하다. 그리고 필요하면 수정해서 사용하자.

 

 



:

[android] FLAG_ACTIVITY_SINGLE_TOP으로 activity 실행시 intent 받아 처리하기

android 2013. 4. 18. 10:21

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

 

startActivity를 호출하여 전달할 값을 putExtra()를 호출하여 intent에 설정하고, 호출된 Activity에서 getIntent()intent를 얻어 왔는데 이상하게 넘겨준값이 없다.  한참 고민하다가 발견한 것은 startActivity로 넘겨주는 intent  FLAG_ACTIVITY_SINGLE_TOP을 설정한 점이다.

 

Intent intent = new Intent(context, SomeActivity.class);

intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);

            

intent.putExtra(PARAM_1, value1);

intent.putExtra(PARAM_2, value1);

intent.putExtra(PARAM_3, value1);

 

            

context.startActivity(intent);

 

FLAG_ACTIVITY_SINGLE_TOP Activity를 재사용 하기 위해서 설정한것이고 필요없는 Activity를 재거하기 위해서 FLAG_ACTIVITY_CLEAR_TOP 을 같이 조합하였다.

 

이런경우 SomeActivity에서는 onNewIntent() override 해서 intent를 받아야 한다.

그리고 setIntent()를 호출해서 다음에 ( onResume 같은데서 ) getIntentintent를 다시 참조해야 할 경우를 위해서 대비하는 것이 좋다.

 

@Override

protected void onNewIntent(Intent intent) {

       super.onNewIntent(intent);

 

       if (null != intent) {

             int defaultValue = 0;

              index = intent.getIntExtra(PARAM_1, defaultValue);

            

             setIntent(intent); 

}

}

 

호출되는 순서는 onCreate() 대신에 onNewIntent()가 호출되고 다음으로 onResume() 이 호출된다 

처음 startActivity 호출시

1.     onCreate

2.     onStart

3.     onResume

해당 Activity가 실행된 상태에서  flas를 추가하고 다시 startActivity 호출시

1.     onNewIntent

2.     onResume

 

 

 

 



:

[android] TextView 코드로 생성하면서 style 적용하기

android 2013. 4. 10. 17:17

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

TextView에 글자크기나 글자색깔등의 속성을 묶어서 style로 만들어 놓고 쓰면 편리하다.

아래는 글자크기를 22sp, 색상은 white로 그리고 그림자효과(shadow)를 묶어서 style로 만들었다.

 

<style name="myTitleText">

        <item name="android:textSize">22sp</item>

        <item name="android:textColor">#ffffff</item>

        <item name="android:shadowColor">#4e000000</item>

        <item name="android:shadowDy">2</item>

        <item name="android:shadowRadius">1</item>

        <item name="android:gravity">center_vertical</item>

</style>

 

Xml 파일에서 간단하게 style을 설정하면 된다.

<Textview

       android:id="@+id/my_text"

       style="@style/myTitleText"

       android:layout_width="wrap_content"

       android:layout_height="wrap_content" />

 

그런데 TextViewXML에 선언하지 않고 코드에서 생성해서 style을 적용하려니 잘 안된다. 처음에는 그냥 직접 속성들을 적용하였다.

 

textView.setTextSize(22);

textView.setTextColor(0xffffffff);

textView.setShadowLayer(1, 0, 2, 0x4e000000);

textView.setGravity(Gravity.CENTER_VERTICAL);

 

그러나 뭔가 개운치가 않다. style로 묶은 것은 해당 style을 재사용 하기 위한것인데, XML에 정의해서 다른곳에서 사용하는 부분과, 코드에서 직접 적용한 부분으로 2중으로 정의되어 있으면 향후 style이 변경되었을 때 두군데를 다고쳐야 한다. 유지 보수시에 실수하기 좋은 방식이므로 코드에서 XML에서 정의한 style을 불러다 쓰고 싶었다. 이것저것 찾아보다 TextView에서 setTextAppearance 라는 메소드를 제공한다. 이것을 사용하면 간단하게 적용 가능하다

 

textView = new TextView(getContext());

LayoutParams textParam;

textParam = new LayoutParams(30, 30); // 임의의 크기로 param 생성

textParam.width = LayoutParams.WRAP_CONTENT;

textParam.height = LayoutParams.MATCH_PARENT;

textParam.setMargins(getPaddingLeft(), getPaddingTop(), getPaddingRight(), getPaddingBottom());

                    

addView(textView, textParam);

textView.setTextAppearance(context, R.style.myTitleText);

 

주로 XML을 이용해서 UI 구성을 하다가 가끔 코드로 하려면 익숙지가 않다. 하지만 android도 내부적으로 어차피 XML을 읽어서 적용하는 것이기 때문에 각각의 XML에 매핑되는 함수들이 반드시 존재한다. 다만 가끔씩 직관적이지 않은 것들이 있을 뿐이다.

 



:

[android] View의 setClickable() 과 setOnClickListener() 의 관계

android 2013. 3. 25. 21:25

336x280(권장), 300x250(권장), 250x250, 200x200 크기의 광고 코드만 넣을 수 있습니다.

작성일 : 2013-03-25

작성자 : hanburn

 

오늘 이상한 삽질하다가 발견한 것

setClickable(false)을 호출해도 clickable 하게 동작하는 경우가 발생하였다. 바로 문제의 code  

 

if( 특정조건시 ) {                                   

       somTextView.setText(“클릭불가”);

       somTextView.setClickable(false);

       somTextView.setOnClickListener(null);

} else {                        

       somTextView.setClickable(true);

       somTextView.setText(“클릭가능”);

                   

       somTextView.setOnClickListener(new OnClickListener() {

              @Override

              public void onClick(View v) {

                     doAction();

              }

       });

}

 

위의 코드처럼 만들어서 분명히 setClickable false로 하였는데도 click 가능한 상태로 동작하는 것이다. 이상해서 View클래스의 setOnClickListener 코드를 살펴봤다.

 

[View.class setOnClickListener]

public void setOnClickListener(OnClickListener l) {

        if (!isClickable()) {

            setClickable(true);

        }

        mOnClickListener = l;

    }

 

역시나 이 코드에서 내부적으로 clickable인지 체크해서 아니면 setClickable(true)를 호출해주고 있다. 그래서 setClickable을 호출을 setOnClickListener 다음에 호출하도록 순서만 변경하니 잘 동작한다.

 

if( 특정조건시 ) {                                   

       somTextView.setText(“클릭불가”); 

              somTextView.setOnClickListener(null);

               somTextView.setClickable(false);

} else {                        

       somTextView.setClickable(true);

       somTextView.setText(“클릭가능”);

                   

       somTextView.setOnClickListener(new OnClickListener() {

              @Override

              public void onClick(View v) {

                     doAction();

              }

       });

}

 

 

위의 경우에서 setOnClickListener(null)을 호출 안하면 문제가 발생하지 않기는 하는데, AdaptergetView에서 전형적으로 사용하는 ViewHolder 패턴을 사용하다 보니 꼭 호출해야 되었습니다.

 



: