에몽이

명시적 intent와 암시적 intent - intent와 activity 1부 본문

android

명시적 intent와 암시적 intent - intent와 activity 1부

ian_hodge 2018. 3. 7. 16:21

안드로이드를 개발하면서 화면전환시 intent 항상 사용해왔을겁니다. 하지만 과연 intent가 어떤용도로 사용되는지 한번쯤은 생각해보셔야 할 필요가 있습니다. 

아래 글에는 모든 코드를 공개하지않고 핵심적인것만을 작성하니까, 일단 2개의 안드로이드 프로젝트를 받아 설치하고 테스팅하면서 예제를 이해하는편이 쉬울겁니다. 

<압축을 해제하시면 example , example2의 프로젝트 2개가 있습니다. import 시켜주세요>

 example.zip

보편적으로 intent는 액티비티를 전환할때 어떤 액티비티로 전환할지.. 또는 어떤 내용을 담아서 전달할지.. 에 중점적으로 사용하였습니다. 하지만 이런 intent에게도 사용하는 용도에 따른 명칭이 있습니다.  제목에서 보듯이 명시적 intent와 암시적 intent가 되겠습니다. 

명시적 intent는 말그대로 intent를 받는 대상을 콕찝어 지정해주는 용도입니다. 암시적 intent도 intent받는 대상을 지정해주는 용도입니다. 하지만 이 둘은 차이점이 있습니다. 먼저 명시적 intent는 같은 프로젝트 내부에 있는 액티비티만을 지정할수있습니다. 또한 단 하나의 액티비티만을 호출 할 수 있습니다. 반면 암시적 intent는 intent를 받는 대상이 복수개가 되며 intent-filter에 의해 intent의 요청이 취소될 수도 있습니다. 좀더 명확한 설명을 위해 각각의 차이점을 그림이나 코드로 설명드려보겠습니다.


■ 명시적 intent

명시적 intent는 androidmanifest.xml 에 정의된 intent-filter를 무시하고 원하는 액티비티로 intent를 건내주는게 가능합니다.


단! 반드시 intent를 건내주고자 하는 액티비티가 명확할때 그리고 그 액티비티가 같은 프로젝트 내에 있을때에 또는 해당 액티비티의 패키지와 클래스네임을 알고있어야 가능합니다. 

명시적intent를 사용하는 함수와 파라미터는 다음과 같습니다.

>> 동일한 프로젝트 내에서의 호출

Intent intentC = new Intent(this , ActivityC.class);


>> 서로 다른 프로젝트 내에서의 호출

//intent.setClassName("com.example.example2", "com.example.example2.MainActivity");

startActivity(intent);

위 그림과 같이 프로젝트 A 에서 프로젝트 B의 액티비티F 를 호출하는 intentF 는 해당 액티비티가 갖는 패키지명과 클래스네임을 알고있어야 intent를 건낼 수 있습니다.


■ 암시적 intent

암시적 intent에 관해서 설명이 조금 길어지니 의지를 갖고 보셔야 모두 이해가 될겁니다.

암시적 intent는 androidmanifest.xml에 정의된 intent-fliter의 action과 category에 의해 intent를 필터하고, 필터된 intent만을 건내주는 방법입니다. 

서로 다른 프로젝트끼리도 intent를 건내주어 액티비티를 시작할 수 있는 이점이 있습니다. 

암시적 intent 를 사용하는 함수와 파라미터는 다음과 같습니다.

Intent intent = new Intent("com.example2.other");

startActivity(intent);

명시적 intent와 다르게 생성자에 문자열을 삽입하는데 저 문자열이 바로 action이 되겠습니다. action으로 지정된 문자열을 갖는 액티비티에게 intent를 건내주겠다는 의미입니다. 근데 막연하게 아무 action이나 집어넣으면 큰일나겠죠? 그래서 intent를 건내고자 하는 액티비티의 action를 알고 추가적으로 category의 개방도를 알아야합니다. 이 action과 category는 androidmanifest.xml에 정의되어 있고 또 개발자가 액티비티를 추가하면서 지정이 가능합니다.

보통 intent를 생성하면 기본적으로 category는 default로 잡힙니다.

먼저 action과 category에 대하여 알아봅시다. action은 개발자가 지정하는 문자열 또는 안드로이드 시스템적으로 미리 존재하는 상수가 되겠습니다. category도 안드로이드 시스템적으로 미리 존재하는 상수가 되겠습니다. 말로 설명하면 이해가 잘 안될것 같아서 몇가지 예제를 들어보겠습니다.

<application

    android:icon="@drawable/ic_launcher"

    android:label="@string/app_name"

    android:theme="@style/AppTheme" >

    <activity

        android:name=".MainActivity"

        android:label="@string/title_activity_main" >

        <intent-filter>

            <action android:name="android.intent.action.MAIN" />

    <action android:name="com.example2.other" />

            <category android:name="android.intent.category.DEFAULT" />

        </intent-filter>

    </activity>

</application>

이 xml 코드는 제가 미리 제작한 androidmanifest.xml 에서 가져온겁니다. intent-filter 태그 내부에 action 2개와 category 1개가 있습니다. 각 의미를 하나하나 뜯어보며 설명해드리겠습니다.

<action android:name="android.intent.action.MAIN" />

이녀석 action은 "앱의 메인이 되는 액티비티가 되어라" 라는 의미입니다. 필수적인 요소이며 만일 제가 activity 태그를 하나 더 추가했을경우에는 해당 activity내부에는 이 action을 지워버리겠죠? 아무튼 이녀석은 크게 중요한게 아니고, activity 태그중에 시작 액티비티에 포함만 시켜주면 될 뿐입니다.


<action android:name="com.example2.other" />

이녀석이 핵심입니다. intent가 들어왔을때 해당 intent가 갖는 action 명이 "com.example2.other"와 같을때만 액티비티를 실행하라는 의미가 되겠습니다. 그 외에 intent의 요청은 모두 필터됩니다.


<category android:name="android.intent.category.DEFAULT" />

이녀석은 intent의 category를 필터합니다. 보통 intent를 생성할경우 defalut로 잡혀서 생성되므로 category를 DEFAULT로 지정하면 되겠습니다. xml상에서 지정된 category와 intent 생성후 지정된 category가 다를경우 intent-filter에 의해 걸러지게 되므로 유의해주세요.


위 설명이 전부이며 다음은 다른 프로젝트에서 위에 지정한 액티비티를 호출하는 코드를 보겠습니다.

btn3.setOnClickListener(new OnClickListener() {

public void onClick(View v) {

// TODO Auto-generated method stub

Intent intent = new Intent("com.example2.other");

intent.putExtra("string", "intent에 첨가한 값입니다. 친환경!");

try{

startActivity(intent);

}catch(Exception e){

Toast.makeText(mContext , "com.example2.other action을 갖는 액티비티가 없습니다.", Toast.LENGTH_SHORT).show();

}

}

});

intent를 생서할때 생성자로 호출하고자 하는 액티비티의 action명을 지정했고, category는 생성시 default로 지정되있으므로 건들지 않았으며 외부 프로젝트의 액티비티에게 데이터를 넘기기위해 puExtra함수를 사용했습니다. 추가적으로 try/catch를 사용하여 액티비티가 존재하지 않을경우 또는 필터됬을 경우에 대비했습니다. 


아래 사진은 같은 프로젝트 내에서 intent를 건내어 액티비티를 호출하거나 다른 액티비티에게 action을 보내 호출하는 모습입니다.


같은 프로젝트 내부의 암시적 호출의경우 액티비티를 선택하는 화면이 뜨는 이유는 action명을 동일하게 지정할 경우입니다.

이런식으로 개발자가 공개한 action에 맞춰 intent를 건내주면 되겠습니다. 


암시적 intent를 이렇게 길게 설명하는 이유는 안드로이드 내부적으로 구동하는 call 이나 sms 또는 contact등의 어플리케이션도 위와 비슷하게 action명과 그에 따른 uri를 필요에 의해 덧붙여 호출할 수 있기 때문입니다. 

■ 전화 걸기

Intent callntent = new Intent(Intent.ACTION_CALL);

callntent.setData(Uri.parse("tel:"+phone));


■ sms 전송하기

Intent smsIntent = new Intent(Intent.ACTION_SENDTO);

smsIntent.setData(Uri.parse("sms:"+phone));


■ 주소록에 저장하기

Intent contactIntent = new Intent(Intent.ACTION_INSERT);

contactIntent.setType(ContactsContract.Contacts.CONTENT_TYPE);

contactIntent.putExtra(ContactsContract.Intents.Insert.NAME, name);

contactIntent.putExtra(ContactsContract.Intents.Insert.PHONE, phone);


등등이 있습니다.

이상으로 명시적 intent와 암시적 intent에대한 설명을 마치겠습니다. 평소에 intent를 사용했던것보다 아주 조금 더 알아가는 느낌으로 이 글을 읽고 가셨으면 좋겠습니다.



출처: http://cusmaker.tistory.com/119 [Custum + Maker]

Comments