[Android] Activity

neoneoneo·2024년 3월 25일
0

android

목록 보기
8/16

Android Developers 공식 문서 읽어보기

'Application의 기본 항목' 시리즈

Activity 공식 문서 링크

  1. Activity <- Here!
  2. Service
  3. Broadcast receiver
  4. Content provider

Activity란?

액티비티는 사용자와 상호작용하는 진입점으로 UI가 있는 단일 화면을 나타낸다.

이메일 앱을 예시로 보자,

이메일 앱에는 새 이메일 목록을 표시하는 활동, 이메일을 작성하는 활동, 이메일 읽기를 위한 활동이 하나씩 있을 수 있다. 이 여러 개의 활동들이 함께 작동하여 이메일 앱에서 일관된 환경을 형성하지만, 각 활동은 서로 독립적이다.

이메일 앱에서 놀다가 다른 앱을 시작할 수도 있잖아?

이메일 앱에서 허용하면 얼마든지 가능하다.

만약 이메일 앱에서 사용자가 사진을 첨부할 수 있도록 하고 싶다면? 카메라 앱을 시작해야한다. 이때 이메일 앱은 카메라 앱이 이메일 앱에서 시작되어 사진을 찍는다던가, 사진을 첨부한다던가와 같은 행위를 할 수 있도록 허용할 수 있다.

이렇게 액티비티는 시스템과 앱의 주요 상호작용을 돕는다.

  • 현재 포커스 된 건(화면에 표시된 내용)을 추적하여 시스템이 활동을 호스팅하는 프로세스를 계속 실행하도록 한다.
  • 사용자가 돌아갈 수 있는 중지된 활동이 있다면, 이전에 사용된 프로세스를 파악하고 우선순위를 더 높여 프로세스의 가용성을 유지한다.
  • 앱이 프로세스를 종료 처리하도록 지원하여 사용자가 이전의 복원된 상태의 활동으로 돌아갈 수 있도록 한다.
  • 앱이 사용자 흐름을 구현하고 시스템에서 그 흐름을 조정할 수 있는 방법을 제공한다(eg. 공유하기).

여기까지는 서론이었다... 서론이 길었다^^..


자, 그럼 본격적으로 액티비티라는 것이 무엇인지 공식 문서를 계속 읽어나가보자.

Activity 클래스는 안드로이드 앱에서 중요한 구성요소이며, 액티비티가 시작되어 조합되는 방식은 플랫폼 애플리케이션 모델의 기본적인 부분이다.

다른 앱이 main() 메서드로 실행되는 프로그래밍 패러다임과 달리, 안드로이드 시스템은 수명 주기의 특정 단계에 상응하는 특정 콜백 메서드를 호출하여 Activity 인스턴스의 코드를 시작한다.

Activity의 개념

모바일 앱은 항상 동일한 지점에서 사용자와 앱의 상호작용이 시작되지는 않는다.

  1. 홈 화면에서 이메일 앱을 연다 -> 이메일 목록이 표시된다
  2. SNS 앱을 사용하고 있다 -> SNS 앱에서 이메일 앱 실행으로 이어준다 -> 이메일 앱 화면으로 이동한다 -> 이메일 작성 화면이 표시된다

1, 2와 같은 경우를 상상해보면,
둘 다 똑같이 이메일 앱을 실행하지만 그 과정에 있어서 다른 앱이 먼저 실행될 수 있다는 점과 이메일 앱을 실행하여 다른 액티비티를 바로 실행하는 점을 이해할 수 있겠다.

하나의 앱(SNS)이 다른 앱(이메일)을 호출하는 경우, 호출하는 앱(SNS)은 하나의 전체 액티비티가 아니라 다른 앱의 액티비티(이메일 쓰기)를 호출한다.

Activity 클래스는 이러한 상황에 잘 대응할 수 있도록 설계되었다.

액티비티는 앱이 UI를 그릴 수 있는 window를 제공한다.

이 window는 화면에 꽉 차 있는 것처럼 보이지만, 실제로는 화면보다 작을 수 있고 다른 창 위에 떠 있는 상태일 수도 있다.

일반적으로 하나의 액티비티는 하나의 화면을 구현한다

서론에서 언급한 이메일 사례를 다시 생각해보면 되는데, 대부분의 앱에는 여러 화면이 표함되어 있다.

이말인 즉슨, 앱은 여러 개의 액티비티로 구성된다는 것이다!

앱에서 액티비티를 사용하려면 앱의 매니페스트에 액티비티에 관한 정보를 등록하고, 그 수명 주기를 적절하게 관리해야 한다.

manifest 구성

매니페스트에는 사용할 액티비티와 해당 액티비티의 특정 속성을 선언해두어야 한다.

액티비티 선언

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

안드로이드 스튜디오를 열면 manifest 파일이 있을 것이다. 이를 열고, <activity> 요소를 <application> 요소의 하위 요소로 추가하면 해당 액티비티가 선언이 된다고 볼 수 있겠다.

android:name은 액티비티 클래스의 이름을 지정하는 속성으로,<activity> 요소의 유일한 필수 속성이다.

<activity>의 다른 속성들은 여기에서 자세히 볼 수 있다.

인텐트 필터 선언

인텐트 필터는 또 뭐니..

인텐트 : 메시지 객체. 앱 구성요소에 작업을 요청하는 데에 사용된다.
인텐트 필터 : 인텐트를 이용한 명시적, 암시적 요청을 기반으로 액티비티를 시작할 수 있는 기능을 제공한다.

(또)이메일 앱을 예시로 생각해보자

  • 이메일 앱에서 이메일 보내기 액티비티를 시작하라고 지시한다 <= 명시적 요청
  • 작업을 할 수 있는 액티비티에서 이메일 보내기 화면을 시작하라고 시스템한테 알려준다 <= 암시적 요청

인텐트 필터가 작동 중인 상황

시스템 UI에서 사용자에게 다른 앱 켜서 ~한 작업을 실행해볼것이여? 라고 사용할 앱을 묻는 메시지가 표시된다면? 그럼 인텐트 필터가 작동 중인 상태인 것이다.

<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> 요소 안에 <intent-filter> 속성이 선언된 것을 볼 수 있다.
  • <category> 요소가 DEFAULT로 선언되어 있는데, 이는 액티비티가 실행 요청을 수신할 수 있는 상태라는 것이다.
  • <data> 요소에는 이 액티비티가 전송할 수 있는 데이터 유형을 지정해둔 것이다.

위 코드에서 선언해둔 액티비티를 호출하려면 아래와 같이 코드를 짜면 된다.

val sendIntent = Intent().apply {
    action = Intent.ACTION_SEND
    type = "text/plain"
    putExtra(Intent.EXTRA_TEXT, textMessage)
}
startActivity(sendIntent)

인텐트를 다룰 때 요긴하게 쓰일 것 같은 패턴이니, 잘 숙지해두면 좋겠다.

권한 선언

매니페스트의 <activity> 태그를 사용하면 특정 액티비티를 시작할 수 있는 앱을 제어할 수 있다.

내가 만들고 잇는 앱에서 SocialApp이라는 가상의 앱을 사용하여 소셜 미디어의 게시물을 공유하는 상황을 상상해보자.

1) 먼저, 내 앱에서 권한을 정의해야 한다.

정의해야 하는 권한은 com.google.socialapp.permission.SHARE_POST이라고 가정하자.

<manifest>
    <activity android:name="...."
        android:permission="com.google.socialapp.permission.SHARE_POST" />
</manifest>

이렇게 android:permission 속성에 해당 권한을 정의해준다. 이는 내 앱이 SocialApp의 저 기능을 사용할 권한을 가지고 있다는 것이다.

나는 권한이 있는데, SocialApp에 권한이 없다면? 말짱 꽝이다. 만약 내가 중국 여행에 가기 위해 비자를 받았다고 치자. 나는 여권에는 A라는 비자를 받았지만, 막상 중국에서 관리하는 비자 리스트에 A라는 비자가 없다면? 공항에서 노숙만 하다 한국으로 돌아와야 할 것이다.

이를 위해,

2) SocialApp에서는 타 앱에서 해당 권한을 사용할 수 있도록 매니페스트에 해당 권한을 선언해줘야 한다.

<manifest>
    <uses-permission android:name="com.google.socialapp.permission.SHARE_POST" />
</manifest>

이렇게하면, SocialApp은 내 앱으로부터 저 권한을 가지고 있는지 확인하고 관련 기능을 수행할 수 있는지 판단한다.

공식 문서에서 정말 정말 쉽게 설명하려고 노력한 것 같다. 더 필요한 내용은 보안 가이드라인 문서에서 (나중에) 더 찾아보자.

액티비티 수명 주기 관리

액티비티 수명 주기 관리는 이전에 다른 글에서 심도있게 다룬 바 있다.

간단하게 살펴 보자면,

onCreate()

  • 시스템에서 액티비티를 생성할 때 실행된다.
  • onCreate()가 완료되면 다음 단계의 콜백은 항상 onStart()이다.

onStart()

  • onCreate()가 종료되면 액티비티가 시작됨 상태로 전환되고 액티비티의 화면이 사용자에게 표시된다.
  • 액티비티가 포그라운드로 이동하여 사용자와 상호작용 하기 위한 최종 준비를 한다.

onResume()

  • 액티비티가 사용자와 상호작용을 시작하기 직전에 이 콜백을 호출한다.
  • 이 시점에서 액티비티는 액티비티 스택의 맨 위에 위치하여 있으며 모든 사용자 입력을 탐지한다.
  • 앱의 핵심 기능은 대부분 onResume() 메서드에서 구현된다.
  • onPause() 콜백은 항상 onResume()를 따른다.

onPause()

  • 액티비티가 포커스를 잃고 일시중지됨 상태로 전환될 때 onPause()를 호출한다.
  • 예를 들어 사용자가 뒤로 버튼을 누른다면? onPause() 가 호출된다.
  • 시스템에서 onPause()를 호출하면 화면은 여전히 부분적으로나마 표시된다.
  • 일시중지는 해놨지만, 액티비티가 UI를 계속 업데이트할 수도 있다.
    • 사례로, 내비게이션 화면이나 재생 중인 미디어 플레이어를 표시하는 액티비티가 있겠다.
      • 저런 앱을 사용할 때에는 액티비티가 포커스를 잃더라도 사용자는 UI가 계속 업데이트될 것으로 예상할 것이다.
  • onPause() 실행이 완료되면 다음 콜백은 onStop() 또는 onResume()이다.

주의사항

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

  • 데이터가 손실된다..!! 데이터 손실 방지를 위해 별도로 데이터를 저장해두거나 해야한다.

onStop()

  • 액티비티가 사용자에게 더 이상 표시되지 않는 상태로 시스템이 onStop()를 호출한 상태이기도 하다.
  • 중지된 활동은 더 이상 화면에 표시되지 않는다.
  • 다음 콜백은 onRestart() 또는 onDestroy()이다.

onRestart()

  • 시스템은 Stop 상태의 액티비티를 다시 시작하려고 할 때 이 콜백을 호출한다.
  • 액티비티가 중지된 시점부터의 액티비티의 상태를 복원한다.
  • 이 콜백 뒤에는 항상 onStart()가 온다.

onDestroy()

  • 액티비티가 소멸되기 전에 이 콜백이 호출된다.
  • 이 콜백은 액티비티가 수명 주기에서 수신하는 마지막 콜백이다.
  • 일반적으로 액티비티 또는 액티비티를 포함하는 프로세스가 소멸될 때 해당 액티비티의 모든 리소스가 해제되도록 구현된다.

[TIL-240326]

0개의 댓글