Please Enable JavaScript!
Gon[ Enable JavaScript ]

반응형

안드로이드(Android) This Handler class should be static or leaks might occur 해결

 

환경 : Eclipse Mars, Android 4.2.2

 

안드로이드에서 Handler 오브젝트는 모든 스레드 반복문에서 참조하는데 어느 한곳에 종속되면 안되기 때문입니다. 그렇게 되면 가비지 컬렉션이 되지 않아 메모리릭이 계속해서 발생하게 되는 것이죠.

 

아래 그림은 This Handler class should be static or leaks might occur 경고가 나 있는 소스를 캡쳐한 것입니다.

 

 

이것을 해결하기 위해 Handler 를 상속받은 클래스를 하나 만들어 static 등록해 놔야 합니다. 아래 소스는 이전 소스이며 이것을 고쳐보도록 하겠습니다.

 

handler = new Handler() {
	@Override
	public void handleMessage(Message msg) {
		// super.handleMessage(msg);
		if (myTextOn) {
			myTextOn = false;
			myText.setVisibility(View.GONE);
		} else {
			myTextOn = true;
			myText.setVisibility(View.VISIBLE);
		}
	}
};

 

Static 클래스를 하나 만듭니다. 그리고 handleMessage() 함수를 오버라이드 해서 메인 activity 에 미리 만들어 놓은 handleMessage() 호출해 줍니다. 호출할때 스레드에서 전달받은 메시지를 메인으로 보내면 되겠죠

 

private final MyHandler mHandler = new MyHandler(this);

// 핸들러 객체 만들기 
private static class MyHandler extends Handler {
	private final WeakReference<BackgroundThreadActivity> mActivity;
	public MyHandler(BackgroundThreadActivity activity) {
		mActivity = new WeakReference<BackgroundThreadActivity>(activity);
	}

	@Override
	public void handleMessage(Message msg) {
		BackgroundThreadActivity activity = mActivity.get();
		if (activity != null) {
			
	        activity.handleMessage(msg);
		}
	}
}

 

Handler 객체에서 전달받은 메시지는 메인 activity handleMessage 에서 받아 처리합니다.

 

// Handler 에서 호출하는 함수 
private void handleMessage(Message msg) {
    if (myTextOn) {
		myTextOn = false;
		myText.setVisibility(View.GONE);
	} else {
		myTextOn = true;
		myText.setVisibility(View.VISIBLE);
	}
}

 

스레드와 Handler 클래스가 포함된 전체 activity 소스입니다.

 

import java.lang.ref.WeakReference;

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

public class BackgroundThreadActivity extends Activity {

	BackgroundThread backgroundThread;
	TextView myText;
	private boolean myTextOn = true;
	//private static Handler handler;
	

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_background_thread);

		myText = (TextView) findViewById(R.id.mytext);

		Toast.makeText(this, "onCreate()", Toast.LENGTH_LONG).show();
	}
	
	private final MyHandler mHandler = new MyHandler(this);
	
	// 핸들러 객체 만들기 
	private static class MyHandler extends Handler {
		private final WeakReference<BackgroundThreadActivity> mActivity;
		public MyHandler(BackgroundThreadActivity activity) {
			mActivity = new WeakReference<BackgroundThreadActivity>(activity);
		}

		@Override
		public void handleMessage(Message msg) {
			BackgroundThreadActivity activity = mActivity.get();
			if (activity != null) {
				
		        activity.handleMessage(msg);
			}
		}
	}
	
	// Handler 에서 호출하는 함수 
	private void handleMessage(Message msg) {
	    if (myTextOn) {
			myTextOn = false;
			myText.setVisibility(View.GONE);
		} else {
			myTextOn = true;
			myText.setVisibility(View.VISIBLE);
		}
	}
	
	@Override
	protected void onStart() {
		super.onStart();

		backgroundThread = new BackgroundThread();
		backgroundThread.setRunning(true);
		backgroundThread.start();
		Toast.makeText(this, "onStart()", Toast.LENGTH_LONG).show();
	}

	@Override
	protected void onStop() {
		super.onStop();

		boolean retry = true;
		backgroundThread.setRunning(false);

		while (retry) {
			try {
				backgroundThread.join();
				retry = false;
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}

		}
		Toast.makeText(this, "onStop()", Toast.LENGTH_LONG).show();
	}

	public class BackgroundThread extends Thread {

		boolean running = false;

		void setRunning(boolean b) {
			running = b;
		}

		@Override
		public void run() {
			while (running) {
				try {
					sleep(1000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
				mHandler.sendMessage(mHandler.obtainMessage());
			}
		}
	}
}

반응형
Posted by 녹두장군

댓글을 달아 주세요

  1. 2015.02.15 10:05  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

  2. sun.park20@gmail.com 2015.12.23 11:36  댓글주소  수정/삭제  댓글쓰기

    잘봤습니다. static으로 만들때 memory leak이 떠서 뭔가 했는데 이거였군요.
    ui랑 네트워크 쓰레드 조작 할 때, 핸들러, AsyncTask, 옵저버패턴등등 써봤는데 할때마다 해깔리고 새롭네요ㅠㅠ

  3. 2020.12.24 16:33  댓글주소  수정/삭제  댓글쓰기

    비밀댓글입니다

    • Favicon of https://mainia.tistory.com 녹두장군 2020.12.25 18:50 신고  댓글주소  수정/삭제

      설계 측면에서는 따로 구분하는 것이 좋은데, 샘플이고 Thread 클래스에 많은 기능이 없어서 같은 곳에서 사용했습니다. 그리고 참고하기도 편하거든요. 클래스 관리 차원에서는 분리하는 것이 좋겠죠. 어떤 에러가 발생하는지 모르겠지만 올려 보세요.

    • Favicon of https://colalove5562.tistory.com colalove5562 2021.01.13 13:38 신고  댓글주소  수정/삭제

      앗 해결했습니다!! 도움 감사합니다 ㅎㅎ