본문 바로가기

Programming/과거포스팅

Android Handler을 통한 스레드 동기화

안드로이드 프로그래밍을 하다보면 스레드를 이용할 일이 많다..

보통 UI스레드(메인)와 백그라운드 스레드로 나뉜다.

안드로이드에서는 백그라운드 스레드가 UI스레드에 접근하는 것을 허용하지 않는다..

만약 허용한다면 동기화 문제가 발생하기 때문이다.

그렇기 때문에 핸들러는 통한 스레드의 메시지 전달을 이용하여 처리해야 한다.

그럼 어떨 경우 에러가 발생하는가 부터.. 어떻게 처리를 해야하는지에 대해서 간단한 소스로 알아보도록하자..


기본 UI이다 TextView 1개에 Button 1개로 이루어져 있다..



layout소스이다.. 

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    tools:context=".MainActivity" >

   <TextView
        android:id="@+id/textView1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:gravity="center"
        android:text="@string/hello_world" />
    
    <Button
        android:id="@+id/button1"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:onClick="onClick"
        android:gravity="center"
        android:text="카운터시작" />

</RelativeLayout>


아래는 자바소스이다. 
package com.example.testhandler;

import android.os.Bundle;
import android.os.SystemClock;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    Button button;
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textView  = (TextView)findViewById(R.id.textView1);
        button = (Button)findViewById(R.id.button1);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
    class Counter extends Thread {
        int count = 0;
        
        @Override
        public void run() {
            
            while(true) {
                textView.setText(count + "");  //스레드에서 메인스레드의 뷰를 직접 건드리게 된다.. 어떻게 될까?? 
                count++;
                if ( count == 100) 
                    break;
                SystemClock.sleep(1000L);
            }
        }
    }
    
    public void onClick(View v) {
        
        switch (v.getId()) {  //버튼을 클릭하면...
            case R.id.button1 : {
                new Counter().start();  //스레드를 시작한다.
                break;
            }
        }
    }

}


위의 소스를 실행하면..  Thread Runtime Exception이 발생한다.. 그럼 핸들러를 이용한 스레드 동기화를 하는 방법을 알아보도록하자..




위의 소스를 핸들러를 이용해서 변경해보자..
package com.example.testhandler;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
import android.app.Activity;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {
    
    Button button;
    TextView textView;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        textView  = (TextView)findViewById(R.id.textView1);
        button = (Button)findViewById(R.id.button1);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.activity_main, menu);
        return true;
    }
    
    class Counter extends Thread {
        int count = 0;
        
        @Override
        public void run() { // 핸들러로 카운터를 보낸다.
            
            while(true) {
                mHandler.sendEmptyMessage(count);
                count++;
                if ( count == 100) 
                    break;
                SystemClock.sleep(1000L);
            }
        }
    }
    
    public void onClick(View v) {
        
        switch (v.getId()) {
            case R.id.button1 : {
                new Counter().start();
                break;
            }
        }
    }
    
    private final Handler mHandler = new Handler() { //핸들러를 통해 UI스레드에 접근한다.

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            
            textView.setText(msg.what + "");
        }
        
    };

}


위의 예제는 간단한 동작 원리를 구현하기 위해서 최대한 심플하게 구현했다.. Handler도 메시지들을 받는 여러가지 방법이 있으니 자세한 부분은 API를 참조하기 바란다.

위와 같이 코딩한 후 동작을 시키면 잘 작동하는 것을 확인 할 수 있을 것이다.

 

'Programming > 과거포스팅' 카테고리의 다른 글

프로퍼티로서의 변수  (0) 2013.03.24
자바스크립트 Hoisting 끌어올림  (0) 2013.03.24
XmlSerializer  (0) 2013.02.25
안드로이드 레이아웃 속성 - 아주 기초적인것 제외  (0) 2013.02.25
git이란  (0) 2013.02.25