Activity 상태 및 메모리에서 제거

growdeveloper ㅣ 2021. 4. 12. 13:51

Activity 상태 및 메모리에서 제거


시스템은 RAM에 여유 공간이 필요할 대 프로세스를 종료합니다. 시스템이 특정 프로세스를 종료할 가능성은 그 시점의 프로세스 상태에 따라 달라집니다. 그리고 프로세스 상태는 프로세스 실행되는 활동 상태에 따라 달라집니다.

 

표1. 프로세스 수명 주기와 액티비티 상태 간의 관계

종료될 가능성 프로세스 상태 액티비티 상태
최소 포그라운드(포커스가 있거나 포커스를 가져올 예정) 생성됨
시작됨
재개됨
더보기 백그라운드(포커스 상실) 일시중지됨
최대 백그라운드(보이지 않음)
비우기
중지됨
소멸됨

 

시스템은 메모리 공간을 확보하기 위해 절대 활동을 직접 종료하지 않습니다. 그 대신, 활동을 실행하는 프로세스를 종료하여 활동뿐 만 아니라 프로세스 에서 실행되는 다른 모든 작업을 함께 소멸시킵니다.

 

시스템 제약으로 인해 활동이 소멸되면 ViewModel, onSaveInstanceState() 및/또는 로컬 저장소를 결합하여 사용자의 임시 UI 상태를 보존해야 합니다. 사용자의 기대와 시스템의 동작을 자세히 비교하여, 시스템이 시작한 활동과 프로세스에서 복잡한 UI 상태 데이터를 가장 잘 보존하는 방법을 알아보려면  UI 상태 저장을 참조해야합니다.

아래 링크 참조

developer.android.com/topic/libraries/architecture/saving-states?hl=ko

 

UI 상태 저장  |  Android 개발자  |  Android Developers

구성 변경 시 UI 상태를 유지하는 방법을 알아봅니다.

developer.android.com

 

이 섹션에서는 인스턴스 상태가 무엇인지 활동 자체에 관한 콜백인 onSaveInstance() 메서드를 어떻게 구현하는지 간략히 설명합니다. 원시 데이터 유형이거나 간단한 객체와 같이 UI 데이터가 간단하고 가벼울 경우, onSaveInstanceState()만으로도 모든 구성 변경 및 시스템이 시작한 프로세스가 종료된 상황에서 UI 상태를 보존할 수 있습니다. 그러나 onSaveInstanceState()가 직렬화/역직렬화 비용을 발생시키기 때문에 대부분의 경우에는 ViewModel과 onSaveInstanceState()를 모두 사용해야 합니다.

 

인스턴스 상태

정상적인 앱 동작으로 인해 활동이 소멸되는 시나리오는 몇 가지가 있습니다. 예를 들어 사용자가 뒤로 버튼을 누르거나 활동이 finish() 메서드를 호출하여 자체적인 소멸 신호를 보내느 경우입니다. 사용자가 뒤로 버튼을 누르거나 활동이 자체적으로 종료되어 활동이 소멸되는 경우 해달 Activity 인스턴스에 관한 시스템과 사용자의 콘셉트가 모두 영구적으로 사라집니다. 이 시나리오에서 사용자의 기대가 시스템의 동작과 일치하므로 추가적인 작업이 필요하지 않습니다.

 

그러나 시스템이 시스템제약(예: 구성 변경 또는 메모리 부족)으로 인해 활동을 소멸시킬 경우, 실제 Activity 인스턴스는 사라지더라도 시스템에 존재했다는 정보는 남아 있습니다. 사용자가 활동으로 다시 돌아가려고 시도하면 시스템은 소멸 당시 활동의 상태를 설명하는 저장된 데이터 세트를 사용하여 해당 활동의 새로운 인스턴스를 생성합니다.

 

시스템이 이전 상태를 복원하기 위해 사용하는 저장된 데이터를 인스턴스 상태라고 하며, 이는 Bundle 객체에 저장된 키-값 쌍의 컬렉션입니다. 기본적으로 시스템은 Bundle 인스턴스 상태를 사용하여 활동 레이아웃의 각 View 객체 관련 정보를 저장합니다. 따라서 활동 인스턴스가 소멸되고 재생성된 경우, 레이아웃의 상태는 별도의 코드 요청 없이 이전 상태로 복원됩니다. 하지만 활동에서 사용자 진행 상태를 추적하는 멤버 변수처럼 활동에 복원하고자 하는 상태 정보가 더 많이 있는 경우도 있습니다.

 

Bundle 객체는 메인 스레드에서 직렬화되어야 하고 시스템 프로세스 메모리를 사용하므로 소량의 데이터를 보존하는 데만 적합합니다. 극 소량 이상의 데이터를 보존하려면 영구 로컬 저장소,onSaveInstanceState() 메서드, ViewModel 클래스로 데이터를 보존하는 복합적인 방법을 사용해야 합니다.

 

onSaveInstanceSate()를 사용하여 간단하고 가벼운 UI 상태 저장

활동이 정지되기 시작하면 인스턴스 상태 번들에 상태 정보를 저장할 수 있도록 시스템이 onSaveInstanceState() 메서드를 호출합니다. 이 메서드의 기본 구현은 EditText 위젯 내 텍스트 또는 ListView 위젯의 스크롤 위치와 같은 활동의 뷰 계층 구조에 대한 임시 정보를 저장합니다.

 

활동의 추가적인 인스턴스 상태 정보를 저장하려면 onSaveInstanceSate()를 재정의 하고, 활동이 예상치 못하게 소멸된 경우 저장되는 Bundle 객체에 키-값 쌍을 추가해야 합니다. onSaveInstanceState()를 재정의할 경우 기본 구현에서 뷰 계층 구조의 상태를 저장하고자 한다면 상위 클래스 구형을 호출해야 합니다. 

 

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
// ...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // Save the user's current game state
    savedInstanceState.putInt(STATE_SCORE, currentScore);
    savedInstanceState.putInt(STATE_LEVEL, currentLevel);

    // Always call the superclass so it can save the view hierarchy state
    super.onSaveInstanceState(savedInstanceState);
}

참고: 사용자가 활동을 명시적으로 닫는 경우 또는 finish()가 호출된 경우에는onSaveInstanceState()가 호출되지 않습니다.

저장된 인스턴스 상태를 사용하여 활동 UI 상태 복원

onCreate() 메서드는 시스템이 활동의 새 인스턴스를 생성하든 이전 인스턴스르 재 생성하든 호출되므로 읽기를 시도하기 전에 번들 상태가 Null인지 확인해야 합니다. Null일 경우 시스템은 이전에 소멸된 활동의 인스턴스를 복원하지 않고 새 인스턴스를 생성합니다.

 

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // Always call the superclass so it can restore the view hierarchy
    super.onRestoreInstanceState(savedInstanceState);

    // Restore state members from saved instance
    currentScore = savedInstanceState.getInt(STATE_SCORE);
    currentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

 

이러한 방법을 사용하라고 공식홈페이지에는 나와있지만 실제로 동작했을때 잘 동작되지 않는다.. 문제 해결을 하기 보다는 더좋은 방법이 있는 것 같아서 그방법을 써보자.

@Override
    protected void onPause() {
        super.onPause();
        Log.d("onPause","onPause() 함수 호출 됨.");

        //가지고 있던 데이터값을 저장해두기.
        SharedPreferences pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
        //name은 저장할 때와 복구할 때 같은 이름으로 지정해주어야함

        SharedPreferences.Editor editor = pref.edit();
        editor.putString("name","난저장된 onPause() 함수야");
        //put으로 넣고 get으로 가져옴
        editor.commit();
        //commit을 꼭 해주어야 저장이 됨.

    }
     @Override
    protected void onResume() {
        super.onResume();
        Log.d("onResume","onResume() 함수 호출 됨.");
        //onPause일 때 저장해두었던 데이터를 복구해봅시다.
        SharedPreferences pref = getSharedPreferences("pref", Activity.MODE_PRIVATE);
        if(pref != null){
            String name = pref.getString("name","");
            //name값이 없는 경우에는 빈 값을 달라는 뜻
            Log.d("onResume","복구 된 이름 : "+name);
        }
    }

 

 

 

 

'안드로이드' 카테고리의 다른 글

RecyclerView로 동적 목록 만들기  (0) 2021.10.15
프래그먼트  (0) 2021.08.02
View 와 ViewGroup 이해하기  (0) 2021.06.04
Crashlytic  (0) 2021.04.16
안드로이드 생명주기  (0) 2021.04.09