C 를 개발하다가, Java 전향 시 객제지향언어 문법을 확인하지 않고 사용하면 생기는 문제 중에 하나가 메모리 누수이다.
뜬금없이 뭔 소리냐 하면 C에서는 DB나 file에 쓰지 않고도 앱 실행 중에 특정 값들이 지속적인 값을 유지하여 참고할 수 있다. static 지시어를 이용해서 변수에다 값을 저장해서 각 함수에서 편하게 flag 로 활용해서 사용하고 있다.
static flag 와 extern 으로 가지고 노는 것을 플래그질이라고 말하기도 하는 데....
Java 에서는 static 은 클래스에 선언 시 컴파일러의 의해 즉시 메모리에 바로 로드되어진다. 이러면 인스턴스화 과정을 거치지 않고 사용이 가능해진다.
Java 에서는 플래그질에 static을 사용하는 것은 자제하고, 값의 저장소 개념이 아니라 하나의 클래스가 다중 인스턴화가 만들어지는 상황에서 각 인스턴스들이 같은 값을 가지고 있길 바랄 때 사용하는 것이 바람직하다.
예를 들자면 장치를 On/Off 시키는 클래스를 설계하고 전체소등 기능을 구현한다고 가정해보자.간단하게 추상화하면 이런 그림이 될 것이다.
Clone 은 장치들을 꺼고 키는 단순한 메소드를 가진 클래스의 선언이다.
Clone.java
public class Clone {
public static boolean allOff = false;
public int turnOff() {return 0;}
public int turnOn() {return 0;}
public void setAllOff(boolean value) {
allOff = value;
}
public boolean getAllOff() {
return allOff;
}
}
자식 클래스들은 아래와 같이 상속하여 구현한다.
LedConLedControl.java
import android.util.Log;
public class LedControl extends Clone {
private static final String TAG = "LedControl";
public boolean bExit = false;
private void printState() {
Log.d(TAG, "printState: = " + getAllOff());
if (getAllOff()) {
Log.d(TAG, "printState: 모든 LED가 종료됩니다.");
}
}
public LedControl() {
Thread thread = new Thread(()->{
Log.d(TAG, "LedControl 시작합니다.");
while (!bExit) {
if (getAllOff()) {
printState();
bExit = true;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
LampControl.java
import android.util.Log;
public class LampControl extends Clone {
private static final String TAG = "LedControl";
public boolean bExit = false;
private void printState() {
Log.d(TAG, "printState: = " + getAllOff());
if (getAllOff()) {
Log.d(TAG, "printState: 모든 LEMP 종료됩니다.");
}
}
public LampControl() {
Thread thread = new Thread(()->{
Log.d(TAG, "LampControl 시작합니다.");
while (!bExit) {
if (getAllOff()) {
printState();
bExit = true;
}
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
thread.start();
}
}
각각 클래스 인스턴스을 만들어 각 클래스들은 Lamp 와 LED를 각각 제어할 것이다.
만일 전체장치 Off 기능(일괄소등) 을 만들어야 한다면, 기능을 구현하기 위해 여러분은 어떻게 할 것인가? 부지런하게 각 클래스들을 Array에 일일이 카피해서 turnOff() 메소드를 일일이 호출할 것인가? 그렇다면 여러분은 성실한 개발자이다.
게으른 나는 그냥 꼼수와 설계로 마무리 할 것이다.
Clone 부모클래스에서 staic 필드로 선언한 부분을 기억하는가?
public static boolean allOff = false;
일괄소등 버튼을 만든 후에 onClick이벤트 영역에 아래의 코딩 한줄이면 모든 인스턴스들이 종료기능을 수행한다. 간단하지 않는가?
Clone.allOff = true
예제들을 실행하면 결과가 원하는 데로 나오는 것을 확인할 수 있다.
클래스 내 static 영역은 해당 클래스의 모든 인스턴스들이 값을 공유한다. 즉 한 인스턴스에서 값이 변경되면 전체 인스턴스의 값이 자동으로 변경되는 것이다. 이런 경우에 이용을 추천하고 static을 생명주기를 가진 객체의 인스턴스 선언에 사용하지 말길 바란다. 구글에서도 경고를 했던 상황이니 꼭 피하길 바람 (생명주기 작동오류 생겨서 동작 안정성 보장못함)
MainActivity.java
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button mBtnStart, mBtnAllClose;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBtnStart = findViewById(R.id.button1);
mBtnStart.setOnClickListener(v -> {
LampControl lampControl = new LampControl();
LedControl ledControl = new LedControl();
});
mBtnAllClose = findViewById(R.id.button2);
mBtnAllClose.setOnClickListener(v -> Clone.allOff = true);
}
}
언어의 특성을 알고쓰면 코딩량이 줄어드는 개꿀같은 일이 생김을 잊지 말고 심심할때 자료 검색하는 시간 가져보시길 ~~
'개발 이야기 > Android (안드로이드)' 카테고리의 다른 글
Android RESTful 개발 Kotlin 코드 (0) | 2023.06.26 |
---|---|
Android RESTful 개발 Java 코드 (0) | 2023.06.26 |
RecycerView adapter 간단정리 (0) | 2023.06.07 |
Android | 영상통화자료 (2) | 2023.06.02 |
Android Hardware Acceleration 옵션 꺼기 (0) | 2017.07.07 |
범용성과 독립성 (0) | 2016.12.09 |
Android Eclipse + ADT 개발환경셋팅방법 (0) | 2015.07.23 |
Android ClassCastException at android.app.Application 오류 수정 (0) | 2014.02.04 |