728x90

Handler는 잘 사용하지 않는데, Handler를 이용한 코딩이 필요하여 다시 Handler 개념 살펴보면서 적어둔다.


public class HandlerActivity extends AppCompatActivity {
    Handler mainThreadHandler;

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

        mainThreadHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                if(msg.what == 1){
                }
            }
        };
    }
}

public class HandlerActivity extends AppCompatActivity {
    CHandler mainThreadHandler;

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

        mainThreadHandler = new Handler();
    }
    private class CHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(msg.what == 1){
                //handle message
            }
        }
    }
}


보통의 경우 위와 같이 Handler 클래스를 생성하는 방법으로 사용한다. 하지만 이런 방식의 경우 "The handler class should be static or leak might occur." 라는 메모리 누수 경고 문구가 발생할 수 있다.


Activity가 종료되더라도 Garbage collect 가 실행되지 않게 되고 결국 Message가 Message Queue에 상당 시간동안 남아있게 되어 Memory Leak 의 원인이 된다.


이를 해결할 방법은 static inner class 로 Handler를 정의해주고 WeakReference 를 이용하여 Activity 메소드를 호출하는 코드를 구현한다.


import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

import java.lang.ref.WeakReference;

public class HandlerActivity extends AppCompatActivity {
    Button handlerStartButton;
    Button handlerStopButton;
    Handler mainThreadHandler;
    static TextView handlerExampleTextView;
    static int workValue = 0;
    boolean running = true;

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

        handlerStartButton = findViewById(R.id.btn_start);
        handlerStopButton = findViewById(R.id.btn_stop);
        handlerExampleTextView = findViewById(R.id.tv);

        mainThreadHandler = new MyHandler(this);

        handlerStartButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                running = true;
                startCount();
            }
        });
        handlerStopButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                running = false;
                workValue = 0;
            }
        });
    }

    private void startCount(){
        // Start a child thread when button is clicked.
        WorkerThread thread = new WorkerThread();
        thread.start();
    }

    private static class MyHandler extends Handler{
        private final WeakReference<HandlerActivity> mActivity;

        private MyHandler(HandlerActivity activity) {
            mActivity = new WeakReference<HandlerActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            HandlerActivity activity = mActivity.get();
            if(activity != null){
                if(msg.what == 1){
                    handlerExampleTextView.setText("BackValue:" + workValue);
                }
            }
        }
    }

    private class WorkerThread extends Thread{
        @Override
        public void run() {
            super.run();
            while(running){
                workValue++;  // 작업스레드 값 증가
                try {
                    java.lang.Thread.sleep(1000); // 1000ms(1초)이므로 1초 단위로 실행
                    System.out.println(java.lang.Thread.currentThread().getName());
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                // Create a message in child thread.
                Message childThreadMessage = new Message();
                childThreadMessage.what = 1;
                childThreadMessage.arg1 = workValue;
                // Put the message in main thread message queue.
                mainThreadHandler.sendMessage(childThreadMessage);
            }

        }
    }
}

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <LinearLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <Button
            android:id="@+id/btn_start"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="center"
            android:text="시작"/>
        <Button
            android:id="@+id/btn_stop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:text="중지"/>

    </LinearLayout>

    <TextView
        android:id="@+id/tv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="20dp"
        android:layout_gravity="center"
        android:gravity="center"
        android:text="결과"
        android:textSize="20dp"/>

</LinearLayout>


참조 : https://blog.naver.com/zoomen1004/220053616676


블로그 이미지

Link2Me

,