Android Basic

Activity

hik14 2020. 9. 22. 23:00

Activity

Activity클래스는 Android 앱의 중요한 구성요소로 Activity가 실행되고 결합되는 방식은 플랫폼 애플리케이션 모델의 기본 요소입니다.

 

 main() 메서드를 사용하여 앱을 실행하는 프로그래밍 패러다임과 달리 Android 시스템은 수명 주기의 특정 단계에 해당하는 특정 콜백 메서드를 호출하여 Activity 인스턴스의 코드를 시작합니다.

 

모바일 앱 환경은 사용자와 앱의 상호작용이 항상 동일한 위치에서 시작되는 것이 아니라는 점에서 데스크톱 앱 환경과 다릅니다.

 

대신 사용자 여정은 흔히 비결정론적으로 시작된다(반드시 앱이 동일한 흐름을 가지지 않는다)

예를 들어 홈 화면에서 이메일 앱을 열면 이메일 목록이 표시될 수 있습니다. 이에 반대로 소셜 미디어 앱을 사용하고 있는 상태에서 이메일 앱을 실행하면 이메일을 작성하기 위한 이메일 앱 화면으로 바로 이동할 수 있습니다.

 

앱이 다른 앱을 호출할 때 호출 앱은 다른 앱을 전체적으로 호출하는 것이 아니라 다른 앱의 활동을 호출합니다. 이런 방식으로 활동은 앱과 사용자의 상호작용을 위한 진입점 역할을 합니다

 

앱이 UI를 그리는 창을 제공합니다 일반적으로 한 활동은 앱에서 하나의 화면을 구현합니다. 

 

앱에는 여러 화면이 포함되어 있습니다. 즉, 대부분의 앱은 여러 Activity로 구성됩니다. 일반적으로 앱에서 하나의 Activity 기본 활동으로 지정되며 이 기본 활동은 사용자가 앱을 실행할 때 표시되는 첫 번째 화면입니다. 각 Activity는

다른 Activity을 시작할 수 있습니다.

 

Activity는 앱의 일관된 사용자 환경을 형성하기 위해 함께 작동하지만 각 Activity는 다른 Activity에 단지 느슨하게 결합됩니다. 일반적으로 앱의 Activity 간에는 최소한의 종속성만 있습니다.

manifest 선언

manifest 파일을 열고 <activity> 요소를 <application> 요소의 하위 요소로 추가한다.

    <manifest ... >
      <application ... >
          <activity android:name=".ExampleActivity" />
          ...
      </application ... >
      ...
    </manifest >
    

유일한 필수 속성은 활동의 클래스 이름을 지정하는 android:name입니다. 또한 라벨, 아이콘 또는 UI 테마와 같은 활동 특성을 정의하는 속성도 추가할 수 있습니다. 이러한 속성 및 기타 속성에 관한 자세한 내용은 <activity> 요소 참조 문서에서 확인할 수 있습니다.

인텐트 필터 선언

인텐트 필터는 Android 플랫폼의 매우 강력한 기능입니다. 인텐트 필터는 명시적 요청뿐만 아니라 암시적 요청을 기반으로도 활동을 실행하는 기능을 제공합니다.

예를 들어 명시적 요청은 'Gmail 앱에서 이메일 보내기 Activity를 시작'하도록 시스템에 지시할 수 있습니다. 이와 반대로 암시적 요청은 '작업을 할 수 있는 Activity로 이메일 보내기 화면을 시작'하도록 시스템에 지시합니다. 시스템 UI에서 사용자에게 작업을 실행할 때 어떤 앱을 사용할지 묻는 메시지가 표시되면 바로 인텐트 필터가 작동한 것입니다.

 

 <intent-filter>하위에는 

 <action> 요소와 선택적으로 <category> 요소 또는 <data> 요소가 포함됩니다. 이러한 요소를 결합하여 활동이 응답할 수 있는 인텐트 유형을 지정할 수 있습니다. 예를 들어 다음 코드 스니펫은 텍스트 데이터를 전송하고 다른 활동들의 요청을 수신하는 Activity을 구성하는 방법을 보여줍니다.

 

    <activity android:name=".ExampleActivity" android:icon="@drawable/app_icon">
        <intent-filter>
            <action android:name="android.intent.action.SEND" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity>
    

<action> 요소는 이 Activity이 데이터를 전송하는 역할을 하도록 합니다. <category> 요소를 DEFAULT로 선언하면 Activity가 실행 요청을 수신할 수 있습니다. <data> 요소는 이 Activity 전송할 수 있는 데이터 유형을 지정(사용할 수 있는)합니다. 다음 코드 스니펫에서는 위에 설명된 활동을 호출하는 방법을 보여줍니다.

 

권한 선언

manifest의 <activity> 태그를 사용하여 특정 Activity를 시작할 수 있는 앱을 제어할 수 있습니다.

 

상위 Activity와 하위 Activity이 모두 각 manifest에서 동일한 권한을 가지고 있지 않다면 상위 Activity이 하위 Activity을 실행할 수 없습니다.

 

예를 들어 앱에서 SocialApp이라는 가상의 앱을 사용하여 소셜 미디어의 게시물을 공유하려면

게시물을 호출하는 앱이 보유해야 하는 권한을 SocialApp 자체에서 정의해야 합니다.

 

Activity Life Cycle

 왜 라이프사이클을 고려해야 하는가?

 

아주 간단한 앱이라면 라이프사이클을 그다지 고려를 안 해도 될 것이다. 하지만 이렇게 앱이 멈추거나 다른 상태로 들어가는 경우는 수시로 발생하게 되며, 사용자를 위해 앱을 최적화하는 것이 필수가 된 요즘, 이러한 라이프사이클을 고려하는 것을 기본이 될 것이다. 라이프사이클을 활용하면 좋은 예를 몇 가지 알아보면,

 

    • 앱을 사용하는 중에 전화를 받았을 경우 앱에서 충돌이 일어나지 않게 방지한다.
    •  앱을 사용하다가 다른 앱에 들어갔을 때 충돌이 일어나지 않게 방지한다.
    •  앱을 사용하고 있지 않을 때 다양한 리소스들을 낭비하지 않게 방지한다.
    •  앱을 사용하다가 떠났다가 다시 들어왔을 때 이전에 하고 있던 프로세스를 이어서 할 수 있도록 지원한다.
    • 화면이 가로나 세로로 돌릴 때 사용자의 프로세스를 이어서 해주도록 해 주고 충돌이 일어나지 않게 해 준다.

다양한 상황에서도 사용자 경험 측면에서 앱의 진행을 끊기지 않게 제공해주는 것은 앱의 개발자가 얼마나 Activity의 라이프사이클을 이해하고 있느냐에 달려있다.

OnCreate()

 

- 구현 시 Activity 필수 구성요소를 초기화해야 합니다.

예를 들어 앱은 여기에서 뷰를 생성하고 데이터를 목록에 결합해야 합니다. 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Activity 의 전체 수명이 시작된다.
        // Activity 초기화 하고, UI Inflate 한다.
        // 단, 한번만 호출된다 (매우 중요)
          Log.d(ACTIVITY_IIFE_CYCLE, 
          "onCreate 전체 수명의 시작 - Activity 초기화 UI Inflate (단, 한번만 실행)");
    }

OnRestart()

    @Override
    protected void onRestart() {
        super.onRestart();
        // Activity 의 최초 이후 가시수명이 시작될때 호출된다.
        // Activity 가시상태가 변경된 것이 있다면 로드한다.
        Log.d(ACTIVITY_IIFE_CYCLE, 
                "onRestart 최초 이후 가시수명이 시작 전 - Activity 가시상태 변경사항 로드");
    }

OnStart()

- onCreate()가 종료되면 Activity 'OnStart()' 상태로 전환되고 Activity가 사용자에게 보이기 시작.

이 콜백에는 Activity이 포그라운드로 나와서 대화형이 되기 위한 최종 준비에 준하는 작업이 포함됩니다.

    @Override
    protected void onStart() {
        super.onStart();
        // Activity 의 가시 수명이 시작된다.
        // 액티비티가 화면에 보임, 필요한 모든 UI 변경 사항을 적용(로드 아님)한다.
        // UI가 적절 하게 배치되고 업데이트되는데 필요한 프로세스가 시작하는 전형적인 장소이다.
        Log.d(ACTIVITY_IIFE_CYCLE, 
        "onStart 가시 수명의 시작 - 액티비티가 화면에 보임, 필요한 모든 UI 변경 사항을 적용");
    }

OnResume()

- Activity가 사용자와 상호작용을 시작하기 직전에 시스템은 이 콜백을 호출합니다.

이 시점에서 Activity스택의 맨 위에 있으며 모든 사용자 입력을 캡처합니다.

앱의 핵심 기능은 대부분 onResume() 메서드로 구현됩니다.

    @Override
    protected void onResume() {
        super.onResume();
        // Activity 의 활성 수명이 시작된다.
        // Activity 에 필요하지만 비활성화 상태여서 정지된 UI 업데이트 스레드, 프로세스를 "재개" 한다.
        // 사용자 액션으로부터 입력을 받을수 있다.
        Log.d(ACTIVITY_IIFE_CYCLE, 
        "onResume 활성 수명의 시작 - 사용자입력을 받음, 
        비활성화 상태여서 정지된 UI 업데이트 스레드, 프로세스를 \"재개\" ");
    }

OnPuase()

 

Activity가 포커스를 잃고 '일시 중지됨' 상태로 전환될 때 시스템은 onPause()를 호출합니다.

예를 들어 이 상태는 사용자가 뒤로 또는 최근 버튼을 택할 때 발생합니다.

 

시스템이 활동에서 onPause()를 호출할 때 이는 엄밀히 말하면 활동이 여전히 부분적으로 표시되지만 대체로 사용자가 Activity을 떠나고 있으며 활동이 조만간 'OnStop' 또는 'OnResume()' 상태로 전환됨을 나타냅니다.

 

사용자가 UI 업데이트를 기다리고 있다면 'OnPuase()' 상태의 Activity은 계속 UI를 업데이트할 수 있습니다.

이러한 Activity의 예에는 내비게이션 지도 화면 또는 미디어 플레이어 재생을 표시하는 Activity이 포함됩니다.

이러한 Activity이 포커스를 잃더라도 사용자는 UI가 계속 업데이트될 것으로 예상합니다.

 

애플리케이션 또는 사용자 데이터를 저장하거나 네트워크를 호출하거나 데이터베이스 트랜잭션을 실행하는 데 onPause()를 사용해서는 안됩니다.

 

 

- 사용자와 상호작용 할 때 필요한 리소스들을 반납한다. 가벼운 리소스들을 반납

 

    @Override
    protected void onPause() {
        super.onPause();
        // Activity 의 활성 수명이 종료된다.
        // UI Thread(main Thread) 와 CPU 과다 사용 프로세스를 종료한다.
        // (foreground 상태가 아닐때 대기중인 스레드 프로세스 브로드 캐스트 리시버)
        // 단 다중 윈도우 모드에서 일시 정지된 Activity 들은 여전히 사용자에게 보여줘야 되기 때문에
        // 이때 필요한 UI 업데이트 를 계속 수행되어야 한다.
        Log.d(ACTIVITY_IIFE_CYCLE, 
        "onPause 활성 수명의 종료 - UI Thread(main Thread) 와 CPU 과다 사용 프로세스를 종료한다.");

    }

onStop()

 

Activity이 사용자에게 더 이상 표시되지 않을 때 시스템은 onStop()을 호출합니다.

이 모든 상황에서 중지된 Activity는 더 이상 화면에 보이지 않습니다.

 

시스템이 호출하는 다음 콜백은 Activity이 사용자와 상호작용하기 위해 다시 시작되면 onRestart()이며 이 Activity 완전히 종료되면 onDestroy()입니다.

    @Override
    protected void onStop() {
        super.onStop();
        // Activity 의 가시 수명이 종료된다.
        // Activity 가 보이지 않을 떄 필요없는 UI 업데이트 스레드 프로세스를 중지한다.
        // onStop 의 실행이 끝난 후 Activity 는 언제든 종료될 수 있기에
        // 모든 수정 데이터나 상태 변경 데이터를 저장한다. (데이터)
        // 애니메이션 스레드, 센서 리스너, GPS 조회, 타이머 서비스등 UI 업데이트 사용되는 프로세스 종료 및 저장.
        // 화면이 보이지 않을때 도 리소스를 필요로 하는 프로세스는 종료하지 않는다.
        Log.d(ACTIVITY_IIFE_CYCLE, 
        "onStop 가시 수명의 종료 - Activity 가 보이지 않을 떄 필요없는 UI 업데이트 스레드 프로세스를 중지한다. 
        모든 수정데이터나 상태 변경 데이터를 저장한다. (데이터)");
    }

OnDestory()

 

시스템은 Activity이 제거되기 전에 이 콜백을 호출합니다.

 

이 콜백은 Activity이 수신하는 마지막 콜백입니다. 

onDestroy()는 일반적으로 Activity 또는 Activity가 포함된 프로세스가 제거될 때 Activity의 모든 리소스를 해제하도록 구현됩니다.

    @Override
    protected void onDestroy() {
        super.onDestroy();
        // Activity 의 전체 수명이 종료된다.
        // 종료 스레드를 비롯하여 모든 리소스를 클린업 하고 데이터베이스 연결등을 닫아야된다.
        Log.d(ACTIVITY_IIFE_CYCLE,
        "onDestroy 전체 수명의 종료 -종료 스레드를 비롯하여 모든 리소스를 해제 
        하고 데이터베이스 연결등을 닫아야된다.");
    }