Context?

Ruinak·2021년 8월 9일
0

Glossary

목록 보기
14/26
post-thumbnail

1. Context 정의

  • Application 환경에 대한 전역 정보를 접근하기 위한 인터페이스.

  • Context를 통해 어플리케이션에 특화된 리소스나 클래스에 접근할 수 있다.

  • Activity 실행, Intent 브로드캐스팅 그리고 Intent 수신 등과 같은 응용 프로그램 수준의 작업을 수행하기 위한 API를 호출 할 수 있다.

  • 안드로이드 시스템에서 제공하는 API 를 호출할 수 있는 기능을 제공한다.

2. 안드로이드 애플리케이션 정보 관리 주체

  • 안드로이드 시스템에서 어플리케이션 정보를 관리하고 있는 것은 AcitivityManagerService 라는 일종의 또 다른 어플리케이션이다.

  • 안드로이드에서는 어플리케이션과 관련된 정보에 접근하고자 할 때는 AcitivityManagerService를 통해야만 한다.

3. Context의 역할

  • 자신이 어떤 어플리케이션을 나타내고 있는지 알려주는 ID 역할

  • ActivityManagerService에 접근할 수 있도록 하는 통로 역할

4. Context의 종류

  • Application Context - Application Life-Cycle에 관련 - 싱글톤

  • Activity Context - Activity Life-Cycle에 관련 - 액티비티마다 생성

  • Application Context는 애플리케이션이 실행되어 종료될 때까지 동일한 객체인 반면, - Activity Context는 하나의 액티비티가
    onDestroy() 된 경우 사라질 수 있는 객체이다.

5. Context 생성 시기

  • Activity 혹은 Service가 생성될 때 Context가 만들어진다.

  • BroadcastReceiver가 호출될 때도 Context가 만들어진다.

  • 이 둘의 Context는 각기 다른 인스턴스이다.

6. Context 에 접근하는 구체적인 방법

View.getContext()

  • 현재 뷰가 가지고 있는 context를 반환하는데, 일반적으로는 Activity에서 View를 띄우기 때문에 Activity의 Context가 된다.

Activity.getApplicationContext()

  • 애플리케이션 전체의 컨텍스트를 반환합니다.

  • 현재 액티비티뿐만 아니라 애플리케이션의 수명주기와 관련된 컨텍스트가 필요한 경우 Activity Context대신 이 값을 사용하면 된다.

  • getApplicationContext() 는 애플리케이션의 생명주기와 관련되어 있기 때문에 현재 Context와 분리된 어떤 Context가 필요하거나, 현재 Activity Scope를 벗어난 작업을 할 때 필요하다.

7. ApplicationContext() 를 잘못 사용한 경우

  • Application Context는 Activity가 하는 모든 것을 지원하는 은총알 같은 Context는 아니다.

  • Application Context로는 대부분 GUI(화면, View, 등) 작업은 할 수 없다.

  • Activity 만 가능하다.

  • 예를 들어 Application Context를 이용하여 AlertDialog를 띄우려고 한다면 다음과 같은 에러를 볼 수 있다.

  • java.lang.IllegalStateException: You need to use a Theme.AppCompat theme (or descendant) with this activity.

  • 그런데 Toast는 Application Context를 이용해도 아무 문제가 없이 잘 뜬다.

  • Toast의 경우 특정 액티비티에 연관된 윈도우에 속하지 않고, 자신만의 윈도우를 생성하기 때문이다.

8. 안드로이드 애플리케이션은 프로세스가 없어도 살아 움직인다.

  • 안드로이드 플랫폼에서는 프로세스가 없는 상황에도 어플리케이션은 살아있는 것처럼 사용자에게 표시되기도 하고, 메모리가 부족한 상황이 될 경우, 작동중이던 프로세스가 강제로 종료되고, 대시 해당 프로세스에서 작동중이던 어플리케이션에 관한 일부 정보만 별도로 관리하고, 이 후에 메모리 공간이 확보되면 저장되어있던 어플리케이션 정보를 바탕으로 새로운 프로세스를 시작하는등의 신기한 일이 벌어진다.

  • 안드로이드에서도 프로세스는 당연히 OS 커널 (리눅스)에서 관리됩니다. 어플리케이션과 프로세스가 별도로 관리되고 있다면, 어플리케이션 정보는 어디에서 관리하고 있을까요? 안드로이드의 시스템 서비스 중 하나인 ActivityManagerService 에서 그 책임을 진다. 그렇다면 ActivityManagerService 는 어떤식으로 어플리케이션을 관리하고 있을까요? 이외로 단순 합니다. 특정 토큰을 키값으로 'Key-Value' 쌍으로 이루어진 배열을 이용해 현재 작동중인 어플리케이션 정보를 관리한다.

  • 거의 결론에 다다른거 같습니다. Context 는 어플리케이션과 관련된 정보에 접근하고자 하거나 어플리케이션과 연관된 시스템 레벨의 함수를 호출하고자 할 때 사용됩니다. 그런데 안드로이드 시스템에서 어플리케이션 정보를 관리하고 있는 것은 시스템이 아닌, ActivityManagerService 라는 일종의 또 다른 어플리케이션입니다. 따라서 다른 일반적은 플랫폼과는 달리, 안드로이드에서는 어플리케이션과 관련된 정보에 접근하고자 할때는 ActivityManagerService 를 통해야만 합니다. 당연히 정보를 얻고자 하는 어플리케이션이 어떤 어플리케이션인지에 관한 키 값도 필요해집니다.

  • 일반 OS 플랫폼에서 어플리케이션은 곧 Process 입니다. 특정 어플리케이션이 OS 에게 내가 어떤 Process 인지만 알려주면 어플리케이션 관련된 정보를 얼마든지 획득 할 수 있습니다. 하지만 안드로이드에서 어플리케이션은 프로세스라고 할 수 없습니다. ActivityManagerService 라는 애가 어플리케이션을 관리하고 있기 때문에 ActivityManagerService 이 친구가 프로세스입니다.

  • Context 는 어플리케이션이 시작될 때는 물론이요, 어플리케이션 컴포넌트들이 생성될때마다 태어납니다.

  • 안드로이드가 어플리케이션을 관리하는 핵심은 프로세스를 깔끔하게 종료시키지 않는 것입니다. 사용자가 어플리케이션을 떠나는 순간, 해당 어플리케이션의 프로세스는 계속 유지되며, 백그라운드 상에서 필요한 경우 어떠한 작업(예를 들어 웹페이지 다운로드와 같은)을 수행할 수 있습니다. 그리고, 사용자가 해당 어플리케이션으로 돌아오면 그 즉시 포그라운드로 전환됩니다. 만일 디바이스의 메모리가 충분하다면, 안드로이드는 모든 어플리케이션 프로세스들을 유지하게 되고, 말 그대로 모든 어플리케이션은 동시에 작동(Running) 할 수 있습니다.

  • 메모리는 무한하지 않습니다. 이러한 한계를 극복하기 위해, 안드로이드 시스템은 더이상 필요하지 않은 프로세스를 종료해야만 합니다. 즉, 각각의 프로세스들은 정해진 규칙에 따라 그 중요도가 결정되고, 가장 중요하지 않은 프로세스가 종료되게 됩니다. 이러한 과정이 안드로이드의 '프로세스 생명주기' (Process Lifecycle) 를 만들어 냅니다.

  • '모든 어플리케이션은 항상 작동하고 있다' 라는 사용자 경험을 만족시키기 위해, 만일 사용자가 이미 종료된 어플리케이션으로 돌아가기를 원하는 경우, 해당 어플리케이션의 마지막 상황과 동일한 형태로 어플리케이션이 시작되어야 합니다. 이를 위해, 사용자에게 보여지는 어플리케이션 요소 (즉, Activity)은 늘 기록 되며, 필요한 경우 특정 Activity가 화면상에 보였던 상태 정보와 함께 Activity 를 재시작 합니다. Activity의 상태 정보는 어플리케이션 종료 시점이 아니라, 사용자가 어플리케이션을 떠날 때 마다 생성됨으로, 커널은 사용자가 어플리케이션을 벗어난 후에는 비교적 자유롭게 해당 어플리케이션을 종료 할 수 있습니다.

  • 어떤면으로 보면, 안드로이드가 프로세스를 관리하는 방법은 공간 교체(swap space)의 형식으로 여겨질 수 있습니다. 어플리케이션 프로세스들은 사용중인 메모리 공간을 나타냅니다. 메모리가 부족하게 될 경우 몇몇 프로세스들은 강제로 종료 되고(교체 당함 - Swapped Out) ,해당 프로세스들이 다시 필요하게 될 경우 마지막으로 저장된 상태 정보를 기반으로 다시 시작(교체 투입 - Swapped In)될 수 있습니다.

9. 예제 코드

package com.cos.contextex01;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

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

        Button button = findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Context c1 = v.getContext();
                Context c2 = MainActivity.this;
                Context c3 = getApplicationContext();

                AlertDialog.Builder builder = new AlertDialog.Builder(c1);
                builder.setTitle("인사말").setMessage("반갑습니다");
                AlertDialog alertDialog = builder.create();
                alertDialog.show();

                Toast.makeText(c3, "안녕", Toast.LENGTH_SHORT).show();
            }
        });
    }
}
profile
Nil Desperandum <절대 절망하지 마라>

0개의 댓글