[Android] 안드로이드 기초 - Intent를 이용해 화면 전환하기


 


로그인 화면에서 게임 플레이 화면으로 넘어가거나, 상품 구매 화면에서 결제 화면으로 넘어가는 등 화면을 전환시키는 것은 당연하지만 앱에서 필수적인 요소입니다. 어떤 화면에서 다른 화면으로 넘어가는 것을 구현하기 위해 Intent라는 것을 사용하는데요, 오늘은 Intent를 이용해 어떻게 화면 전환을 하는 것인지 알아보도록 하겠습니다.

 



Intent란?

Intent라는 단어의 뜻을 아시나요? Intent는 의지, 의도, 몰두하는... 이라는 뜻을 가지고 있습니다. 안드로이드에서의 Intent도 원래의 뜻을 생각한다면 비슷한 역할을 한다고 볼 수 있는데요, Intent는 특정 컴포넌트가 어떠한 작업을 수행하는 지를 담는 클래스입니다. 이를 위해 컴포넌트 간 의사소통을 하기 위한 메세지를 담을 수 있습니다. 여기서 컴포넌트에 대해서 얘기하자면, 안드로이드는 4가지의 대표적인 컴포넌트가 존재합니다. 보통 4대 컴포넌트라고 부르곤 합니다.

1. 액티비티 (Activity)

2. 서비스 (Service)

3. 브로드캐스트 리시버 (Broadcast Receiver)

4. 콘텐트 프로바이더 (Content Provider)

액티비티는 우리가 이전에 배웠던 그 액티비티가 맞습니다. 나머지 컴포넌트 이 외에도 Fragment 같은 유용한 컴포넌트도 추가되었지만, 지금은 컴포넌트에 대해서 구체적인 설명을 하고자 하는 것은 아니므로 넘어가겠습니다. 어쨌든 위의 4가지 컴포넌트가 서로 의사소통을 하기 위해 Intent가 중간에서 메세지를 전달해주는 매개체의 역할을 합니다. 그나마 알고 있는 액티비티로 예를 든다면 액티비티에서 다른 액티비티로 이동할 때 Intent에 메세지를 담아서 이동한 후 다음 액티비티에 메세지를 넘기는 것이죠.

Intent에는 2가지 형태가 있습니다. 명시적인 인텐트와 암시적인 인텐트가 있는데, 명시적인 인텐트는 인텐트로 정보를 주고 받을 컴포넌트를 명확하게 알 수 있는 경우 사용하는 것이며, 암시적인 인텐트는 컴포넌트를 명확하게 알 수 없는 경우에 사용합니다. 아래에서 조금 자세하게 설명하겠습니다.





명시적 인텐트

가령 게임 앱 내에서 로그인 화면에서 로그인을 한 후에는 어디로 넘어갈까요? 당연히 게임 플레이 화면이나 튜토리얼 화면 등으로 넘어 가겠죠. 개발자가 로그인을 하면 이 곳으로 넘어가게끔 의도를 정하여 만들었을 것입니다. 사실 상 앱 내에서 화면 전환을 하거나 사용자의 어떤 활동으로 인한 결과를 확실히 알 수 있다고 한다면 명시적 인텐트라고 할 수 있습니다. 사실 이 글을 보게 되는 이유도 이런 명시적 인텐트인 화면 전환을 어떻게 하는 지 알고 싶기 때문일 것입니다. 그럼 밑에 코드를 보면서 어떻게 화면 전환을 하는지 알아봅시다. 그 전에 일단 activity_sub 레이아웃에 버튼을 하나 만들고 id를 intent_test_button라고 짓고, activity_main에 간단한 TextView를 만들고 intent_test_textview라고 짓겠습니다.

activity_sub.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <Button
            android:id="@+id/intent_test"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="Button" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <TextView
            android:id="@+id/textView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="hello world!" />
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

현재 시작 화면은 SubActivity이며, SubActivity 클래스에서 MainActivity로 전환하는 것을 해보겠습니다. SubActivity에 다음의 코드를 입력해보세요.

SubActivity.java

package com.example.test;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

public class SubActivity extends AppCompatActivity {

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

        Button testButton = findViewById(R.id.intent_test_button);
        testButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(SubActivity.this, MainActivity.class);
                startActivity(intent);
            }
        });
    }
}

activity_sub에서 만든 intent_test_button을 testButton으로 선언하고 클릭 메서드를 붙였습니다. onClick 메서드를 보면 Intent 객체를 선언하고 매개변수로 SubActivity.this와 MainActivity.class를 값으로 넣었습니다. 그런데 각각의 매개변수는 무엇을 넣어야 할까요?

첫번째 매개변수에는 SubActivity.this가 들어가 있습니다. SubActivity의 무언가를 가져오는 것인데, 그게 뭘까요? 안드로이드에는 Context라는 개념이 있습니다. 앱의 액티비티와 같은 컴포넌트 등에서의 정보를 저장하는 것인데, 생성된 객체가 뭘 하고 있는지를 알 수 있다고 보면 됩니다. 가령 어떤 리소스에 접근을 하려고 한다던지, API를 호출하는 등 앱이 현재 시점의 어느 지점에서 무엇을 하는지를 가져오는, 굉장히 추상적인 클래스입니다. (네, Context는 그래서 추상 클래스입니다.) 그래서 Intent로 현재 상태를 기점으로 어떤 작업을 처리하기 위해선 현재 상태를 알 수 있는 Context를 매개변수로 가져와야하며, 보통 Activity이름.this와 같은 형태가 이런 Context를 가져오는 것입니다. 또는 Activity.getApplicationContext() 등으로도 Context를 불러올 수 있죠.

두번째 인자로는 MainActivity.class가 들어갑니다. 예상하셨다시피, 다음으로 넘어갈 Activity의 클래스를 넣어주시면 됩니다. 그래서 startActivity로 intent를 넣어서 화면 전환을 시작하는 것이죠. 코드는 꽤나 간단하지만, 내용이 조금 쉽지 않을 수 있습니다. (특히 저 Context라는 추상 클래스 때문에 말이죠.)

실행을 한번 해보세요. 아래와 같이 화면이 전환되는 것을 볼 수 있습니다. 



이번엔 전환될 다음 화면에 어떤 값을 넣어주고 전환하고, 전환 된 다음 화면에서 그 값을 출력해 볼까요? 다음 화면으로 어떤 값을 보내기 위해선 putExtra라는 것을 사용합니다. 코드로 한번 알아봅시다. 위와는 다르게 이번에는 MainActivity에서도 어떤 작업을 해주어야 합니다. 

SubActivity.java

package com.example.test;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

public class SubActivity extends AppCompatActivity {

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

        Button testButton = findViewById(R.id.intent_test_button);
        testButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(SubActivity.this, MainActivity.class);
                intent.putExtra("testString", "MainActivity에 있는 TextView를 이 문자열로 바꿔봅시다.");
                startActivity(intent);
            }
        });
    }
}

일단 intent.putExtra라는 것이 생겼습니다. 매개변수엔 2가지의 String이 담겨있네요. 첫번째 String은 두번째 String의 key 또는 id와 같은 것입니다. 즉 "MainActivity에 있는 TextView를..."라는 String을 불러오기 위해 testString이라는 key가 필요한 것이죠. 두번째 String은 당연히 MainActivity로 전달하고자 하는 문자열이구요. 이번에는 MainActivity로 넘어갑시다.

MainActivity.java

package com.example.test;

import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    String getStringFromSubActivity;
    TextView testView;

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

        Intent intent = getIntent();
        getStringFromSubActivity = intent.getStringExtra("testString");

        testView = findViewById(R.id.intent_test_textview);
        testView.setText(getStringFromSubActivity);
    }
}

onStart 메서드를 보면 getIntent로 Intent를 가져오고 있습니다. 즉 이 화면이 등장하게 만들어 준 Intent를 가져오는 것입니다. 이 앱에선 SubActivity에서 만들었던 intent가 MainAcitivty를 불러왔기 때문에 SubActivity의 intent가 MainActivity를 등장하게 만든 녀석이겠죠? 그렇기 때문에 getIntent를 하면 SubActivity의 intent를 가져오게 되는 것입니다. 사용자가 2개의 화면을 한번에 실행하지는 않을 테니까요.

다음으로는 getStringExtra("testString")으로 SubActivity에서 putExtra로 넣었던 문자열을 key로 받아와서 불러오고 있네요. 이제 getStringFromSubActivity에는 위의 "MainActivity에 있는 ..." 이 들어갈 것입니다. 그리고 이 문자열을 testView에 넣었구요. 이렇게 실행하면 버튼을 눌러 MainActivity로 전환할 때 문자열이 바뀌는 것을 확인할 수 있을 것입니다.








암시적 인텐트

위와 같이 화면 전환 등 어떤 액션이 일어날지 확실하게 Intent를 전달하는 것을 명시적 인텐트라고 한다면, 암시적 인텐트는 명확하게 알지 못할 경우를 암시적 인텐트라고 합니다. 가령 여러분이 공유 기능을 이용하여 사진을 공유하려고 한다면, 무엇을 이용해서 공유를 할 것인가요? 카카오톡? 지메일? 혹은 문자? 요즘 데이터를 전송하는 앱이 무척 많기 때문에, 공유 기능을 눌렀을 때 어떤 방식으로 공유를 할 것인지 안드로이드에서 추천하는 것을 본 적이 있을 것입니다. 아래와 같이 말이죠.


이렇게 Intent의 행동에 대해 어떤 결과가 뒤따라올지 명확하지 않을 경우, (지메일을 선택할지 카카오톡을 선택할지 블루투스를 선택할지) 이렇게 적합한 행동을 할 수 있도록 도와줍니다. 이런 것을 암시적 인텐트라고 하죠. 저런 추천은 여러 앱을 사용하다 보면 많이 볼 수 있습니다. 어떤 브라우저로 열 것인지, 어떤 전화 앱으로 통화를 할 것인지... 한번 이메일 전송 인텐트를 사용해 봅시다. SubActivity를 조금 바꿔볼까요?

SubActivity.java
package com.example.test;

import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import androidx.appcompat.app.AppCompatActivity;

public class SubActivity extends AppCompatActivity {

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

        Button testButton = findViewById(R.id.intent_test_button);
        testButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(Intent.ACTION_SEND);
                intent.setType("text/plain");
                intent.putExtra(Intent.EXTRA_EMAIL, "koin12000@naver.com");
                intent.putExtra(Intent.EXTRA_SUBJECT, "전달할 이메일 제목");
                intent.putExtra(Intent.EXTRA_TEXT, "전달할 내용");
                startActivity(Intent.createChooser(intent, "Choose Email"));
            }
        });
    }
}

Intent.ACTION_SEND로 이메일 인텐트를 사용할 것이라고 알려주고, putExtra에 보낼 사람, 제목, 내용 등을 넣어주면 됩니다. 실행해서 버튼을 눌러보면 큰 문제 없이 될 것이라고 하고 싶은데... 이상하게 지메일에서 제목과 내용은 잘 들어가는데 보내는 사람이 제대로 안 들어 가더군요. 에뮬레이터 문제인지... 어쨌든 정상적으로 암시적 인텐트를 체험해볼 수 있을 것입니다.





마치며..

컴포넌트로 앱이 작동하고 다른 앱과 통신을 하는 안드로이드의 특성 상 인텐트는 무척 중요한 클래스입니다. 매우 빈번하게 사용되기 때문에 잊을 수가 없지만 잘 공부해주세요. 위에서 설명 안했던 Intent에 Bundle이란 객체를 넣어서 보낸다던지, 갤러리에 접근해서 썸네일을 따온다던지, 활용 방법이 무궁무진하고 공부할 것도 엄청나게 많습니다. 이 기초를 잘 습득하고 조금씩 배워나가시길 바랍니다.









댓글