1. 인텐트(Intent)란?
인텐트(Intent)는 간단히 말하면 명령 또는 데이터 전달수단 이다. 정확히는 애플리케이션 구성요소 간에 작업 수행을 위한 정보를 전달하는 역할을 한다. 그러면 시스템이 인텐트의 내용을 확인하고 실행한다. 인텐트를 사용하면 다른 애플리케이션의 액티비티를 띄우거나 기능을 호출할 수도 있다.
인텐트를 전달하는 대표적인 메소드들에는 다음의 것들이 있다.
- startActivity() , startActivityForResult()
- startService() , bindService()
- broadcastIntent()
인텐트의 기본 구성요소
액션(Action) : 수행할 기능
데이터(Data) : 액션이 수행 될 대상 데이터
액션과 데이터 쌍의 예시로는 전화걸기 화면 띄우기(ACTION_DIAL)와 전화번호(tel:01012344885)가 있다. 전화번호 화면을 띄우는 기능이 액션이고 전화걸기 액션이 수행 될 대상 데이터가 전화번호이다.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="010-1234-1234로 전화걸기"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
버튼을 하나 만들었다.
package io.swnomad.sampleintent;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
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) {
//액션 : Intent.ACTION_DIAL, 데이터 : tel:01012341234
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:01012341234"));
startActivity(intent); //인텐트를 전달하여 액티비티 띄우기
}
});
}
}
버튼을 누르면 인텐트 객체를 생성하는데, 액션으로는 전화걸기 화면을, 데이터로는 전화번호를 넣어주었다. 단, Uri.parse() 메소드를 사용해서 파싱을 해주어야 시스템이 데이터가 전화번호 타입이라는 것을 인지할 수 있다.
대충 랜덤으로 정한 전화번호인데 대출권유로 신고가 많은 전화번호다;;
이외에도 ACTION_VIEW 액션에 데이터로 인터넷 url을 넣어주어 웹 프라우저를 띄우거나 pdf 확장자명의 파일 경로를 넣어주어 pdf뷰어를 띄울수가 있다.
2. 명시적 인텐트 vs. 암시적 인텐트
명시적 인텐트는 특정 액티비티의 클래스 객체나 컴포넌트 이름을 지정하여 호출할 대상이 정확히 명시된 경우에 사용한다. 주로 하나의 애플리케이션 내부에서 사용한다. 예를 들어 하나의 애플리케이션 내에서 특정 액티비티가 다른 액티비티 클래스를 띄우는 경우가 될 수 있다.
암시적 인텐트는 액션과 데이터를 지정했지만 데이터를 실행할 컴포넌트가 달라질 수가 있는 경우이다. 예를 들면 ACTION_VIEW를 통해 데이터로 "http://"로 시작하는 문자열을 전달하였는데, 이를 실행할 컴포넌트(웹 브라우저)가 여러 개 있는 경우이다. 시스템이 암시적 인텐트를 받으면 데이터의 포맷을 확인한 후 적절한 컴포넌트를 찾아 실행해준다.
암시적 인텐트를 사용할 때 데이터의 포맷에 따라 안드로이드가 적절한 컴포넌트를 찾는다는 것을 알았다. 안드로이드에서는 등록된 MIME 타입에 따라 적절한 컴포넌트가 설정되어 있다. 예를 들어 "http://"로 시작되는 문자열이 들어오면 인터넷 URL로 인식을 하여 인터넷 웹브라우저를 띄우고, "tel:"로 시작하는 문자열이 들어오면 전화번호로 인식하여 전화걸기 화면 등을 띄우도록 되어있는 것이다.
암시적 인텐트를 사용할 때, 액션을 실행할 특정 컴포넌트를 직접 지정할 수도 있다.
ComponentName name = new ComponentName(Context context, Data data); //context라는 컴포넌트를 사용하여 data를 실행
intent.setComponent(name);
위와 같이 하면 액션을 실행할 특정 컴포넌트를 인텐트에 직접 지정할 수 있다.
그렇다면 어떻게 시스템은 특정 컴포넌트가 지정되지 않은 암시적 인텐트를 전달해줄 특정 컴포넌트를 찾을 수 있는 것일까?
※시스템이 암시적 인텐트를 실행할 컴포넌트를 찾는 메커니즘
시스템이 암시적 인텐트를 받으면 디바이스에 설치된 모든 컴포넌트(애플리케이션)들의 인텐트 필터(intent-filter)를 살펴본다. 인텐트 필터는 앱의 AndroidManifest.xml 파일에 정의되어 있으며, 어떠한 종류의 인텐트를 받을 것인지를 명시해놓은 것이다. 안드로이드가 모든 앱의 인텐트 필터를 살피면서 암시적 인텐트를 받아들일 수 있도록 되어있는 앱이 있으면 이 앱을 통해 인텐트의 액션을 실행하는 것이다. 여러개의 앱이 암시적 인텐트를 받아들이는 경우 사용자에게 결과를 보여주면서 사용할 앱을 고를 수 있도록 띄워준다.
인텐트 필터는 <category\>, <action\>, <data\>를 기준으로 받아들일 인텐트를 결정한다. 인텐트 필터의 예시를 한 번 보자.
<activity android:name="ShareActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/plain"/>
</intent-filter>
</activity>
안드로이드 개발자 공식 커뮤니티의 가이드에 다음과 같은 설명이 나와있다.
자세한 내용은 필요할 때 찾아서 쓰면 된다. 지금은 모든 앱은 인텐트 필터라는 것이 있고, 이를 근거로 인텐트를 받아들일지 말지 결정한다는 것이다. 또한 시스템은 AndroidManifest.xml 파일을 통해 모든 앱의 정보에 관해 알고있으며, 여기서 <intent-filter\> 태그를 통해서 인텐트를 실행할 컴포넌트를 추린다는 것이 중요하다.
예제를 통해서 시스템이 암시적 인텐트를 받았을 때 어떻게 행동하는지 보자.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/editText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24dp"
android:hint="URL을 입력하세요."/>
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="열기"/>
</LinearLayout>
입력상자와 버튼을 하나 만든다. 입력상자에 URL을 입력하고 버튼을 누르면 URL을 데이터로 가지는 인텐트를 시스템으로 보낼 것이다.
package io.swnomad.sampleintent;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
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) {
EditText editText = findViewById(R.id.editText);
String url = editText.getText().toString(); // 입력상자의 url 읽어와서 문자열로 만들기
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url)); // 액션: ACTION_VIEW, 데이터: url
startActivity(intent); // 액티비티 띄우기
}
});
}
}
시스템이 암시적 인텐트를 받아들일 수 있는 앱을 찾아서 사용자에게 고를 수 있도록 결과를 보여준다.
'안드로이드' 카테고리의 다른 글
(안드로이드) 18 - 액티비티의 수명주기(LifeCycle) (0) | 2020.05.18 |
---|---|
(안드로이드) 17 - 부가 데이터 (0) | 2020.05.18 |
(안드로이드) 15 - 액티비티(Activity) (0) | 2020.05.18 |
(안드로이드) 14 - 인플레이션(Inflation) (0) | 2020.05.18 |
(안드로이드) 13 - 기본 위젯(3) - 입력상자(EditText) (0) | 2020.05.18 |