흔히들 BroadcastReceiver 를 사용할때 등록하는것은 예제코들 잘 보고 실천을 하지만

해제하는것에 대해서는 심각하게 생각들을 안하는 것 같다.

 

BroadCastReceiver를 등록한다는것 자체가 익명의 클래스를 생성해서 Android Framework에 등록을 하게된다.

아직  BroadCastReceiver 를 등록했던 액티비티가 사라지게되면 어떻게 될까?

 

해당 액티비티의 context를 Android Framework가 쥐고있기에 완벽하게 해제가 되지않고 memory leak 이 발생하게 된다.

 

onStop 혹은 onDestroy method에서 적절하게 BroadCastReceiver를 필히 해제해줘야 할 것이다.

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
29
30
31
32
33
34
35
36
 
 
public BroadCastActivitiy extends AppCompatActivity {
 
    private BroadCastReceiver br;
 
 
    ....
 
    protected void onStart() {
        super.onstart();
        br = new BroadCastReceiver() {
            @override
            public void onReceive(Context context, Intent intent) {
 
            }
          }
        registerReceiver(br, new IntentFilter("hello.myworld"));
    }
 
 
 
    protected void onStop() {
        super.onStart();
        if (br != null)
             unregisterReceiver(br);        
    }
 
    protected void onDestory() {
        super.onDestory();
        if (br != null)
             unregisterReceiver(br);
    }
 
 
}
 
 

 

 

앞선 포스팅 (3. memory leak 회피방법: Inner Class Reference를 주의하라)

과 원리는 동일하다.

 

 

Class에서 익명 class를 만들게되면 익명클래스의 instance는 outer class의 instance에 대해서 

reference를 가지게 된다.

 

 

상황 1. 참고싸이트에서 해결방법 요약

(https://android.jlelse.eu/9-ways-to-avoid-memory-leaks-in-android-b6d81648e35e)

익명클래스로 선언하고 outer class의 context를 static inner class instance로 넘김.

static inner class는 outer class의 instance를 가지지만 WeakReference로 가지기 때문에

스레드에서 긴작업을 하는도중 outer class의 instance가 해제되면, GC에 의해 잘 수거가 이루어지게 되고

WeakReference.get()을 하게되면 null값 반환후 종료되게된다.

 

 

상황2.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 
public class Outer{
    public void sampleMethod () {
        SampleThread st = new SampleThread();
        st.start();
    }
    
    private static class SampleThread extends Thread {
        public void run() {
            Object sampleObject = new Object();
            // ...
        }
    }
 
}
 
 
s

위의 예제는 올바르다고 볼수있는가? => 그렇다.

Main thread (GC Root)는 Outer와 Static inner class를 따로 참조하고있으며

Outer와 static inner class간에는 서로 참조관계가 없다.

 

 

 

아래의 예제는 올바르다고 볼수있는가? => 아니다.

static inner class를 사용했지만 익명객체를 선언하게 되면서 (New Runnable...)

Runnable 객체가 Outer Class의 instance를 가지게 되고, SampleThread(static inner class)

익명의 Runnable 을 받게되어버리면 다시 Outer class의 intance를 reference하기에 문제가 생기게된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
public class Outer{
    public void sampleMethod () {
        SampleThread st = new SampleThread(new Runnable() {
            public void run () {
                Object sampleObject = new Object();
                // ...
            }
        });
        st.start();
    }
    
    private static class SampleThread extends Thread {
        public SampleThread(Runnable runnable) {
            super(runnable);
        }
    }
 
}
 
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter
 

 

 

Outer가 일을 끝내서 소멸되려고 하는찰나에, 익명의 runable이 실행시간이 길게된다면 이는 outer class의 reference를 계속 잡고있기에 outer class의 memory leak이 발생하게된다.

 

 

 

참고

https://android.jlelse.eu/9-ways-to-avoid-memory-leaks-in-android-b6d81648e35e

 

9 ways to avoid memory leaks in Android

I have been an android developer for quite some time now. And I realised that most of that time, I tend to spend on adding new features to…

android.jlelse.eu

 

최악의 상황을 가정해보자

 

1. static변수가 Inner class의 인스턴스를 저장하고있다.

2. inner class가 outer class의 context 정보를 가지고 있다.

 

 

해결방법

 

1. static변수에 context를 담지말고 일반변수로 담아라

2. inner class 를 -> static inner class로 변경해라. => static inner class는 hidden으로 outer class instance의 reference를 가지지 않는다.

3. WeakReference를 이용해서 context를 받고 필요할때 get으로 꺼내서 지역변수 수준으로 사용해라.

 

static inner class 생성자 {

   private final WeakReference<Activity> activityRef = new WeakReference<>(activtiy);

}

...

 

public void someMethod() {

  Activtiy activity =  activityRef.get();

 

  if (activtiy != null) {

   ....

  }

 

}

 

 

 

 

 

 

참고

https://android.jlelse.eu/9-ways-to-avoid-memory-leaks-in-android-b6d81648e35e

 

9 ways to avoid memory leaks in Android

I have been an android developer for quite some time now. And I realised that most of that time, I tend to spend on adding new features to…

android.jlelse.eu

 

+ Recent posts