안드로이드의 UI는 단일 스레드 모델이기 때문에 UI단에서 스레드를 사용하고 싶다면 핸들러를 사용해야 합니다.

1.public void onClick(View v) {
2.new Thread(new Runnable() {
3.public void run() {
4.txtView.setText("안녕하세요?"); // 텍스트뷰의 내용변경
5.}
6.}).start();
7.}

위와 같은 코드를 실행하게 된다면 해당코드는 다른스레드에서 UI에 접근하기때문에

CalledFromWrongThreadException 예외가 발생하게 되죠

이런 문제를 해결하기 위해 쓰는것이 바로 핸들러가 되겠습니다.

핸들러를 가지고 위의 코드를 수정해 보겠습니다.

01.Handler handler = new Handler();
02. 
03.public void onClick(View v) {
04.new Thread(new Runnable() {
05.public void run() {
06. 
07.handler.post(new Runnable() {
08.public void run() {
09.txtView.setText("이제는 됩니다.");
10.}
11.});
12. 
13.}
14.}).start();
15.}

이렇게 Handler 인스턴스를 만들어놓고 post안에 Runnable을 구현하면 됩니다.

post안에 Runnable을 구현하는 방법 외에도 많은 방법이 존재합니다.


- CalledFromWrongThreadException 발생 원인 -

왜 다른스레드에서 UI를 변경하려고 하면 해당 예외가 발생하는지 안드로이드 기본소스를 통하여

알아보자면 UI변경이 있게되면 안드로이드 뷰에서는 invalidate를 호출하게 되는데

1.// View.java
2.public void invalidate() {
3....
4.final ViewParent p = mParent;
5....
6.p.invalidateChild(this, r);
7.}

여기서 보게 되면 invalidate()에서는 ViewParent의 invalidateChild()를 호출하는군요

01.// ViewRoot.java
02.public void invalidateChild(View child, Rect dirty) {
03.checkThread();
04....
05.}
06. 
07.public checkThread() {
08.if (mThread != Thread.currentThread()) {
09.throw new CalledFromWrongThreadException(
10."Only the original thread that created a view hierarchy can touch its views.");
11.}
12.}

invalidate()에서는 checkThread()를 호출합니다. checkThread()에서는 위와 같이

현재 실행중인 스레드가 ViewRoot가 가지고 있는 mThread와 참조가 같은지 비교하고

아니라면 CalledFromWrongThreadException 예외를 던지는군요

해결책 2
--------------------------------------------------------------
new Thread(new Runnable() {
    @Override
    public void run() {    
        runOnUiThread(new Runnable(){
            @Override
             public void run() {
                 // 해당 작업을 처리함
             }
        });
    }
}).start();
--------------------------------------------------------------


출처 :  
http://www.androidpub.com/android_dev_info/57470 

+ Recent posts