꾸준히 안타치기

스레드 & 핸들러, thread/ haddler 본문

Android _ 서버연동_채팅/Android - study

스레드 & 핸들러, thread/ haddler

글자줍기 2021. 2. 10. 15:09
반응형

velog.io/@dlrmwl15/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C-%EC%8A%A4%EB%A0%88%EB%93%9CThread%EC%99%80-%ED%95%B8%EB%93%A4%EB%9F%ACHandler

 

[안드로이드] 스레드(Thread)와 핸들러(Handler)

스레드(Thread)란 동시 작업을 위한 하나의 실행 단위입니다.앱을 실행하면 메인 스레드라는 하나의 스레드가 시작되는데이 메인 스레드는 앱의 기본 실행을 담당합니다.만약 사용자가 필요에 따

velog.io

스레드와 핸들러를 사용해 1초 마다 1씩 증가하는 값을 출력

public class MainActivity extends AppCompatActivity {

    TextView textView;
    ValueHandler handler = new ValueHandler();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        textView = (TextView) findViewById(R.id.textView);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                BackgroundThread thread = new BackgroundThread();
                thread.start();
            }
        });

        Button button2 = (Button) findViewById(R.id.button2);
        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) { }
        });
    }

    // 스레드 클래스 생성
    class BackgroundThread extends Thread {
        int value = 0;
        boolean running = false;
        public void run() {
            running = true;
            while(running) {
                value += 1;
                Message message = handler.obtainMessage();
                Bundle bundle = new Bundle();
                bundle.putInt("value",value);
                message.setData(bundle);
                handler.sendMessage(message);

                try {
                    Thread.sleep(1000);
                } catch (Exception e) {}
            }
        }
    }

    class ValueHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);

            Bundle bundle = msg.getData();
            int value = bundle.getInt("value");
            textView.setText("현재 값 : " + value);
        }
    }
}

쓰레드란? 동시작업을 위한 하나의 독립적인 실행 단위이다.

앱을 실행하면 메인스레드라는 하나의 스레드가 실행된다.

사용작가 필요에 따라 직접 새로운 스레드를 만들경우에는 / 이미지 파일, UI 리소스에 접근이 필요하다.

이때 메인 스레드가 아닌 스레드가 리소스에 직접 접근하게 되면 문제가 생긴다.

메인스레드와 내가 만든스레드가 하나의 리소스에 접근하면, 데드락이 발생할수 있다.

그이유는 시스템에서 어떤쓰레드 먼저 작업을 해야할지 모르기 때문에...!

그래서 핸들러 설정으로 우선순위를 정해서 처리해주어야한다. 선입선출로.

메인 외의 다른 스레드들은 별도의 제어가 필요하다.

메인 스레드가 아닌 스레드에서는 UI 부분을 다룰때 핸들러를 제어한다.

핸들러는 각각의 스레드 안에 만들어 질수 있다.

다른 스레드에서 요청하는 정보를 메시지 큐(Message Queue)를 통해 순서대로 실행시켜준다.

( = 리소스에 대한 동시 접근의 문제를 해결)

예를 들어 메인 스레드 안에 핸들러를 만들어놓으면다른 스레드에서는 특정 작업을 먼저 핸들러 쪽에 요청합니다.

핸들러는 메시지 큐(Message Queue)를 통해 순차적으로 메인 스레드에서 처리할 메시지를 전달하는 역할을 담당합니다.

핸들러 사용법 3단계

  • obtainMessage() : 호출의 결과로 메시지 객체를 리턴 받게함
  • sendMessage() : Message Queue 에 넣음
  • handleMessage() : 메소드에 정의된 기능이 수행됨

스레드에서 핸들러로 메시지를 보내려면 Message 객체를 사용합니다.

Message 객체를 obtainMessage 메소드로 참조한 후 sendMessage 메시지를 이용해 핸들러로 보내면 handleMessage 메소드가 자동으로 호출되기 때문에 전달된 Message 객체를 처리할 수 있습니다.

이 때 handleMessage 메소드는 메인 스레드에서 실행됩니다.

 

https://m.blog.naver.com/PostView.nhn?isHttpsRedirect=true&blogId=akj61300&logNo=80131663053 

 

알짜만 배우는 안드로이드 - 스레드, 핸들러 (Thread, Handler)

프로그램의 모든 작업이 굉장히 빠르게 실행 된다면 좋겠지만 그렇지 못한 경우가 분명 있습니다. 대표적으...

blog.naver.com

 

 

핸들러를 사용해 원형프로그래스바를 실행하고, 

종료시 finish 토스트 메시지를 띄우는 작업을 해보겠습니다. 

핸들러에게 메시지를 나눠서 보낼수있습니다.

 

만들 예제 이미지 -> 프로그래스바가 5초 회전후 종료시 finish토스트를 출력하는 모습

 

프로그래스바를 1초마다 실행시키기위해서는 쓰레드를 생성해야합니다.

쓰레드란 무엇일까요?

쓰레드란, 동시작업을 위한 하나의 독립적인 실행단위입니다.

쓰레드는 하나의 프로세스안에서 동시에 수행되어야 하는 작업을 위해서 필요합니다.

 

앱을 실행하면 메인스레드라는 하나의 쓰레드가 실행이 되는데,

사용자가 메인쓰레드 이외에 필요에 따라 직접 새로운 쓰레드를 만들어 사용할 경우에는 UI에 대한 접근이 필요 합니다.

이때 메인쓰레드가 아닌 쓰레드가 리소스에 직접 접근을 하게 되면 문제가 발생합니다.

그 이유는 시스템에서 메인쓰레드와, 새로 만든 쓰레드들간에 어떤순서로 작업을 해야할지 판단 할수 없기 때문입니다.

그래서 핸들러를 사용해서, 우선순위를 정해서 선입선출로 처리를 해주어야 합니다.

 

메인쓰레드 외에 다른 작업쓰레드들은 별도의 제어가 필요합니다. 

이때, UI를 다룰때 핸들러를 사용합니다.

 

이미지출처 - https://www.boostcourse.org/mo316/lecture/259219?isDesc=false

 

핸들러는 각각의 쓰레드 안에 만들수 있습니다.

다른 쓰레드에서 요청하는 정보를 메시지 큐를 통해 순서대로 실행시켜줍니다. 이로서 리소스에 대한 동시 접근의 문제를

해결할수 있습니다. 메인 쓰레드 안에 핸들러를 만들어 놓으면 다른 스레드에서는 특정작업을  먼저 핸들러에게 요청합니다.

핸들러는 메시지큐를 통해 순차적으로 메인스레드에서 처리할 메시지를 전달하는 역할을 합니다.

 

 

 프로그래스바를 만들기위해 XML를 작성하겠습니다.

원형모양의 프로그래스바를 생성

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

<LinearLayout

    xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical"

    >

    <ProgressBar
        android:layout_marginTop="400dp"
        android:id="@+id/ProgressBar"
        style="?android:attr/progressBarStyleLarge"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content">

    </ProgressBar>

</LinearLayout>

 

그리고 액티비티안에 쓰레드와 핸들러를 작성해보겠습니다.

쓰레드를 생성하고, 핸들러클래스를 작성합니다. 쓰레드 안에 핸들러에게 메시지를 보내는 코드를 작성합니다

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ProgressBar;
import android.widget.Toast;

import com.example.myapplication.R;

public class PracticeActivity extends AppCompatActivity {

    ProgressBar progressBar;
    MyHandler handler;

    // 메시지의 종류에 따라 다른 작업을 하기 위해 INCREMENT_PROGRESS 와 FINISH_PROGRESS 상수는 선언
    public static final int INCREMENT_PROGRESS = 0;
    public static final int FINISH_PROGRESS = 1;


    /**
     * Called when the activity is first created.
     */

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_practice);
        // 프로그래스바
        progressBar = (ProgressBar) findViewById(R.id.ProgressBar);
        // 핸들러 생성
        handler = new MyHandler();

        // 1초마다 핸들러에게 메시지를 보내는 쓰레드 생성.
        new Thread() {

            @Override
            public void run() {
                try {
                    for (int i = 0; i < 5; i++) {
                        sleep(1000);
                        // 메시지를 받은 핸들러가 프로그래스바를 진행시킴
                        // for문을 돌때마다
                        // obtainMessage()메소드는 핸들러로부터 메세지를 하나요청
                        // sendMessage() 는 Message Queue 에 넣는 역할
                        handler.sendMessage(handler.obtainMessage(INCREMENT_PROGRESS));
                    }
                    // 핸들러가 종료되었을때, 보내는 메시지.// obj로 토스트 메시지에 띄울 finish라는 텍스트를 보냄
                    handler.sendMessage(handler.obtainMessage(FINISH_PROGRESS, "finish"));

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }.start();

    }


// 핸들러 클래스 작성, sendMessage로부터 메시지를 구분해 받아 실행함.
    class MyHandler extends Handler {

        @Override

        public void handleMessage(Message msg) {
            switch (msg.what) {
                case INCREMENT_PROGRESS:
                    progressBar.incrementProgressBy(5);
                    break;
                case FINISH_PROGRESS:
                    Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_SHORT).show();
                    break;
            }
            super.handleMessage(msg);// handleMessage() 메소드에 정의된 기능이 실행
        }

    }
}

메시지의 종류애 따라 다른 작업을 하기위해서 INCREMENT_PROGRESS 와 FINISH_PROGRESS를 선언해주었습니다.

1초마다 핸들러에게 메시지를 보내는 쓰레드를 작성하고, 하단에 핸들러 클래스를 작성합니다.

메시지를 받은 핸들러가 for문을 돌때마다 INCREMENT_PROGRESS를 요청하고,

종료시 FINISH_PROGRESS를 요청합니다.

 

  • obtainMessage()메소드는 호출결과로 메시지 객체를 리턴받음
  • sendMessage() 는 Message Queue 에 넣는 역할
  • handleMessage() 메소드에 정의된 기능을 실행

 

쓰레드에서 핸들러로 메시지를 보내려면,  Message객체를 사용합니다.

Message객체를 obtainMessage 메소드로 참조한 후 sendMessage 메시지를 이용해 핸들러로 보내면 handleMessage 메소드가 자동으로 호출되기 때문에 전달된 Message 객체를 처리할 수 있습니다.

이 때 handleMessage 메소드는 메인 스레드에서 실행됩니다.

 

반응형
Comments