티스토리 뷰

반응형

Sub Thread에서 UI수정이 필요할 경우에 Sub Thread에서 직접 수정할 수 없다.

왜냐하면 여러 Sub Thread가 존재할 때 동시에 접근할 수 있는 동기화문제가 존재하기 때문이다.

 

Q. 그러면 Sub Thread에서 처리하는 내용은 전부 UI와 관련 없는 내용이여야할까??

A. 그건 말도안됨;

 

Message를 생성하는 방법은 Message.obtain~~~ 혹은 mHandler.obtainMessage~~~ 이 있다. 이 두가지의 차이점이 없기 때문에 기억만해두고 편리한걸 이용하면 될 듯하다.

 

그래서 Sub Thread에서 UI 수정이 필요할 경우 Main Thread에 Request를 보내서 처리하게 된다.

이 때 Sub Thread는 Handler와 Message를 사용해서 Request를 보내게 된다.

 

그 방법에는 크게 3가지로 사용되는데 차례대로 살펴보자.

1. Runnable 익명 객체 생성 후 Message에 포함시키는 방법

Handler mHandler = new Handler();

protected void onCreate(Bundle savedInstanceState) {
	Thread countThread = new Thread("Count Thread") {
    	public void run() {
        	for(int i=0; i<10; ++i) {
            	mCount++;
                
                Runnable callback = new Runnable() {
                	public void run() {
                    	log.i("ch4njun_log", "Count : " + mCount);
                        mCountTextView.setText("Count : " + mCount);
                    }
                }
                
                // Message Queue에 담을 Message 생성.
                Message message = Message.obtain(mHandler, callback);
   		mHandler.sendMessage(message);
		try {
			Thread.sleep(1000);
		}
		catch(InterruptedException e) {
			e.printStackTrace();
		}
            }
        }
    };
    
	countThread.start();   
}

Runnable 객체(익명 클래스 혹은 별도의 클래스)를 미리 정의해둔다. → callback 함수로써의 역할.

그리고 Handler 객체를 호출할 때 Message에 Runnable 객체를 포함시킨다.

 

이 과정은 코드를 Message에 담아서 Message Queue로 전송하는 것이다.

 

2. Main Thread에서 handlerMessage Override한 후 Message를 전달해 재정의한 handlerMessage 함수가 호출되도록 하는 방법

public class ThreadActivity extends Activity {
	int mCount = 0;
    TextView mCountTextView = null;
    
    static final private int MESSAGE_DRAW_CURRENT_COUNT = 1;
    Handler mHandler = new Handler() {
    	public void handleMessage(Message msg) {
        	switch(msg.what) {
            	case MESSAGE_DRAW_CURRENT_COUNT:
                    int currentCount = msg.arg1;
                    TextView countTextView = (TextView)msg.obj;
                    
                    countTextView.setText("Count : " + currentCount);
                    break;
            }
        }
    }
    
    protected void onCreate(Bundle savedInstanceState) {
    	Thread countThread = new Thread("Count Thread") {
            public void run() {
            	for(int i=0; i<10; ++i) {
		    	mCount++;
                    	Message msg = Message.obtain(mHandler);
                    	msg.what = MESSAGE_DRAW_CURRENT_COUNT;
                    	msg.arg1 = mCount;
                    	msg.obj = mCountTextView;
                    
                	mHnadler.sendMessage(msg);
		}
            }
        };
    }
}

Main Thread에 아예 Handler 객체 내부의 handleMessage 메소드를 오버라이딩으로 구현.

 ( Main Thread 내부에 Handler 객체를 익명 클래스 기법을 사용해서 구현한다는 뜻 !! )

 

그리고 Sub Thread에서는 이 핸들러 객체에 sendMessage, sendEmptyMessage 등의 메소드를 통해 호출.

 

Sub Thread에서는 Runnable 객체 대신에 Message를 구성하는 변수들(int what, int arg1, int arg2, Object obj, Bundle data)를 설정한다. 그리고 Main Thread 에서는 메세지를 받아서 처리하는 handleMessage함수를 재정의 하게되고, 결국 이 함수는 Looper에 의해서 실행된다.

 

위와 같이 Main Thread에 Handler 객체를 정의해두고 !!

Sub Thread에서 m.sendToTarget(handler)를 통해 호출한다.

주석에도 나와있지만 handler.sendMessage(m)와 완전히 똑같은 동작을 한다.

 

 

Runnable? Handler handleMessage?

Runnable 객체 : 간단한 실행 코드를 추가하는 목적으로 사용
Handler handleMessage : 메시지의 what 멤버변수로 구분해 여러가지 목적의 실행코드를 한 곳에 모아 처리할 때 사용한다.

만약 Handler handleMessage를 재정의하지 않는다면 처리하려는 실행 코드마다 Runnable 객체를 생성하여 전달해야 하는 번거로움이 존재한다.

 


3. 핸들러의 post로 시작하는 함수를 통해 Runnable 객체를 이용하는 Message를 추가하는 방법

mHandler.post(new Runnable() { ... });
mHandler.postAtFrontOfQueue(new Runnable() { ... });
mHandler.postAtTime(new Runnable() { ... }, long uptimeMillis);
mHandler.postDelayed(new Runnable() { ... }, long delayMillis);

 

Main Thread에는 Handler 객체만 만들어두고, Sub Thread에서

(핸들러 객체).post(new Runnable(){ ..... });

형태로 핸들러를 호출. 

 

내부에서 호출/정의 해서 Message의 전달은 없는 것으로 생각된다.

아래서 설명하겠지만 클래스분할에 대한 처리가 힘든것같다. (내가 못하는걸수도..)

그러니 내부 클래스로 처리할 수 있는정도까지의 내용에 대해서만 사용하자.

 


그럼 위 3가지 과정중에 뭘써야할까...?

Runnable객체 (1, 3) : Sub Thread에 간단한 코드를 추가할 경우.

                            코드가 길어지고 클래스를 분할해야 되는 경우에 어떻게

                            분할된 클래스에서 Activity에 접근해야할지를 모르겠다....

                            그냥 클래스를 분할해야할 경우에는 3번방법을 사용하는게 좋겠다!!!

                            내부클래스로 Sub Thread를 전부 구현할 수 있을 때만 사용하자.

 

handleMessage (2) : what을 이용해 여러 목적의 코드를 Main Thread에 모아놓을 경우.

                          얘는 클래스를 분할해도 어차피 작업은 Activity 단에서 처리하기 때문에

                          모든 상황에 대한 대처가 가능하다.

                           

 


그리고 추가적으로 모든 뷰, 액티비티는 하나의 핸들러객체를 포함한다.

즉, 별다른 Handler객체 선언 없이 Runnable을 이용한 핸들러 호출이 가능하다는 말이다.

                                ( 직관적인 코드 구성에 매우 도움이 된다. )

 

public class ThreadActivity extends Activity {
	int mCount = 0;
    TextView mCountTextView = null;
    
    protected void onCreate(Bundle savedInstanceState) {
    	// ...
        Thread countThread = new Thread("Count Thread") {
        	public void run() {
            	for(int i=0; i<10; ++i) {
                	mCountTextView.post(new Runnable() {
                    	public void run() {
                        	mCountTextView.setText("Count : " + mCount);
                        }
                    });
                }
            }
        }
    }
}

Runnable을 사용한 방식만 가능하며,,, Sub Thread에서 그릴 View에 대한 처리를 해당 View의 Handler를 사용하기 때문에 좀 더 직관적이다.

 

특정 View가 아니라 여러가지 View에 대해서 하고싶다면 아래 코드를 참고하자

ThreadActivity.this.runOnUiThread(new Runnable() {
    public void run() {
    	mCountTextView.setText("Count : " + mCount);
    }
});

 

결국 이걸 다쓰는거 아닌가......................................?

반응형
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2025/02   »
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
글 보관함