저번 포스팅에서 Intent 객체에 대해서 알아보았습니다.
Intent 객체에 대하여 기억이 나지 않는다면, 해당 포스팅을 확인해보세요.

Activity??

Activity전환에 대한 이야기를 시작하기에 앞서,
안드로이드를 처음 접하시는 분이라면 Activity가 무엇인지 잘 모를 수도 있습니다. 당연하거지요.
그렇다면 Activity란 무엇일까요??
간단히 말해서, Activity란 하나의 화면을 구성하고 있는 안드로이드 시스템에서의 화면의 단위정도로 생각하시면 됩니다.
웹에 대해 지식이 있는 분이라면 여러개의 html파일이 모여 하나의 웹사이트를 이루듯,
안드로이드는 여러개의 Activity가 모여 하나의 어플리케이션을 이루는 것이죠.

물론, 실질적으로 안드로이드 어플리케이션을 개발하다보면, Activity뿐만 아니라,
Fragment라는 녀석도 필요한 경우가 존재하는데, 이 녀석은 오늘의 주제가 아니니 건너가죠!

단순하게 화면만 전환하기

Intent 객체에 대한 포스팅을 읽어보신 분이라면, 이미 화면을 전환할 수 있습니다! (어떻게…?)
Intent 객체 포스팅에서 잠깐 언급했던 말이지만,
안드로이드 시스템에게 나 지금 어디로 이동할꺼야!라고 전달하기 위해서는 안드로이드 시스템이 알아 들을 수 있는 언어(?)인 Intent 객체를 이용하여야 된다고 말씀드렸는데요.
그럼 실질적인 예제코드부터 확인해보시죠.

1
2
3
// MainActivity.java
Intent intent = new Intent(this, SecondActivity.class);
startActivity(intent);

어디서 많이 본 코드 같지 않나요??
눈썰미가 좋으신 분은 눈치 채셨겟지만, 이미 Intent 객체에 대한 포스팅에서 나온 코드입니다.

이 코드는, 안드로이드 프레임워크에서 제공해주는 기본 method인 startActivity()를 이용하여,
생성된 Intent 객체를 기반으로 화면을 이동시키는 코드입니다.

화면을 이동하기 위해서는 Intent 객체에 2개의 Parameter가 필요합니다.
간단하게 이해를 돕자면, 현재 어디의 화면에 머물러 있는데 어떤 화면으로 이동을 할것이다!라는 정보이죠.

즉, 한번 더 풀어쓰면, 현재 MainActivity에 머물러 있는데, SecondActivity라는 화면으로 이동을 할 것이다! 라고 알려주는 것입니다. 우리는 이러한 Intent객체를 명시적 Intent라고 알고있죠. 이것이 끝입니다. 쉽죠?

전환되는 화면으로 데이터 전달하기

화면만 간단히 전달할 줄 알면 참 좋겠습니다만…프로그램의 생태계란 것이 그렇지 않은 경우가 태반이더라구요…
실제 어플리케이션을 개발하다보면 특정한 데이터를 받아서 처리를 해야되는 Activity가 존재하기 마련입니다.
하지만 그렇게 걱정하지 않으셔도 되요. 이미 Intent 객체는 그것을 알기라도 했다는 듯이 필요하면 써!라고 말하듯이 method를 제공하고 있기 때문이죠.

1
2
3
4
5
// MainActivity.java
Intent intent = new Intent(this, SecondActivity.class);
intent.putExtra("user_name", "cro, developer");
intent.putExtra("user_age", 28);
startActivity(intent);

위의 코드를 이용하여 사용자의 이름과 나이를 함께 전달해주는 코드를 보강해보았습니다.
다음화면으로 데이터를 전달해주기 위해서는 putExtra(key, value) 메서드를 사용하시면 됩니다. 이것 또한 간단하죠?
putExtra()메서드의 두번째 Parameter에는 여러가지의 데이터타입을 전달할 수 있도록 제공하고 있으니, 우리의 똑똑한 IDE인 Android Studio의 어시스트 기능을 이용하여 어떠한 데이터타입을 전달 할 수 있는지 한번 확인해보세요!

전달받은 데이터 획득하기

위에서 전환되는 화면으로 데이터를 전달해주는 방법은 알아보았는데, 단순히 전달만 한다고 사용할 수 있지는 않습니다.
전달은 받았지만 전달받은 데이터를 획득하지 않으면 단순히 쓸모없는 데이터일 뿐입니다.
그렇다면 힘들게 넘겨준 데이터를 쓸모있는데이터로 만들기 위해, 데이터를 획득하는 방법을 한번 알아볼까요??

1
2
3
4
5
6
7
8
9
10
// SecondActivity.java
@Override
protected void onCreate(Bundle savedInstanceState) {
// ... 생략
Intent intent = getIntent();
if (intent != null) {
String userName = intent.getStringExtra("user_name");
int userAge = intent.getIntExtra("user_age", 0);
}
}

특별한 경우가 아니라면 보통은 안드로이드의 생명주기 중, onCreate() 메서드 안에서 데이터를 획득해오는 방식을 많이 사용하는 것 같습니다.
데이터를 획득하는 방법 역시 간단합니다. getIntent()메서드를 통해 전달받은 Intent 객체를 획득합니다.
그런 다음, 획은한 Intent 객체에서 각각의 데이터 타입에 받는 getXxxExtra()메서드에 전달할 때 사용되었던 KEY값을 이용하여 뽑아오면 그만이죠!
하지만 두번째 경우인 사용자의 나이에 대한 데이터를 획득하는 메서드에는 뭔가 하나의 Parameter가 더 있는 것을 볼 수 있는데요.
두번째에 넘어가는 데이터는 Default값입니다. 즉, KEY에 해당하는 데이터를 획득하지 못하였을 때, 기본값으로 무엇을 사용할 것이냐는 것이죠.
Default값을 정할 수 있는 데이터타입은 몇가지가 있는데, 어떻게 구별할 지 궁금 할 수도 있겟네요.
Java의 데이터타입에 대해서 생각해보면 편하실 듯 합니다. null로 초기화를 할 수 없는 데이터타입은 모두 Default값을 지정하여 데이터를 전달받지 못한 경우, Default값으로 초기화(?)할 수 있도록 지정해주어야 합니다.

데이터를 이전화면으로 전달하기

위에서 우리는 화면도 전환하고, 데이터도 넘겨주고, 심지어 데이터를 획득하는 방법에 대해 알아보았습니다.
이정도만 있어도 기본적인 어플리케이션을 개발하기에는 충분합니다. 하지만 조금 특별한 경우가 있을 수 있어요..
화면을 이동한 후, 이동된 화면에서 어떠한 처리를 하고, 처리된 결과값을 다시 이전화면으로 돌려줘야되는 경우가 있을 수 있죠.
조금은 실용적이지 못한 어플리케이션이겠지만, 숫자 2개를 넘겨받아 합산을 한 후, 이전화면으로 다시 돌려주는 어플리케이션이 있다고 가정해봅시다.

1
2
3
4
5
// MainActivity.java
Intent intent = new Intent(this, CalculatorActivity.class);
intent.putIntent("first", 100);
intent.putIntent("second", 200);
startActivityForResult(intent, 3641);

위에서 화면을 전환할 때와는 조금은 다른 코드가 나왔습니다. startActivityForResult()인데요.
대충 느낌적으로 봤을때 메서드명에서부터 알 수 있듯, Activity를 시작하긴 할껀데 결과값을 뭔가 어떻게 하겠다는 그런 메서드같네요?
그리고, 단순히 startActivity()를 할 때와는 다르게, Intent 객체 이외에도 뭐가 숫자코드가 같이 주어지고 있습니다.
이 숫자코드는 REQUEST_CODE라는 것인데, 임의로 아무숫자나 정해주셔도 됩니다.
하지만 나중에 결과값을 받을 때 중요한 역할을 하므로 기억하고 있어야 합니다.
그럼 다시 코드로 돌아가서 CalculatorActivity의 코드를 확인해보죠.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// CalculatorActivity.java
protected void onCreate(Bundle savedInstanceState) {
// ... 생략
Intent intent = getIntent();
if (intent != null) {
int first = intent.getIntExtra("first", 0);
int second = intent.getIntExtra("second", 0);
int sum = first + second;
Intent resultIntent = new Intent();
resultIntent.putExtra("sum", sum);
setResult(RESULT_OK, resultIntent);
finish();
}
}

참, 쓸모없는 어플리케이션 인 듯 합니다…
우리는 전달받은 데이터를 획득하는 방법은 이미 알기에 위의 코드를 대충은 이해할 수 있습니다.
우선은 firstsecond라는 KEY값을 이용하여 전달받은 Integer데이터를 획득하고,
새로운 sum이라는 변수를 선언하여 두 값의 합을 구해주고 있지요. 그 뒤에 나오는 코드가 핵심코드가 되겠습니다.

안드로이드에서 Activity를 종료하기 위해서는 finish()메서드를 이용합니다.
하지만 화면을 종료하기 전에, 우리는 이전화면으로 결과를 전달해주기 위해 다시 Intent 객체를 생성하였고,
해당객체에 두 수의 합이 담겨있는 sum을 데이터로 담아주었습니다.
그리고 제일 중요한 setResult()메서드를 이용하여 RESPONSE_CODEIntent 객체를 지정해주었습니다.

이름에서부터 알 수 있듯 setResult()메서드는 결과를 전달해주는 메서드 입니다.
해당 메서드에는 2개의 Parameter를 전달 할 수 있는데,
첫번째가 RESPONSE_CODE 즉, 처리된 결과가 성공이냐, 또는 실패냐, 아니면 어떠한 다른 상태이냐를 나타내는 상태코드입니다. 이것을 잘 사용하면, 성공 / 실패 / 취소 등등 여러가지의 원하는 결과코드를 보낼 수 있죠.
두번째는 우리가 계속 사용해오던 일반적인 Intent 객체입니다. 단순히 결과코드에 대해서만 알려줄 필요가 있다면 Intent 객체는 생략 될 수 있으며, 필요에 따라 데이터를 전달해줘야 된다면 지금까지 사용해온 방식대로 Intent 객체에 데이터를 실어서 전달해주시면 됩니다.

참, 긴 여정이였습니다. 이제 마지막 단계만 남겨두었어요! 전달받은 결과값을 처리해야겠죠?
그럼 다시 전달받은 값을 처리해야되니 MainActivity코드를 확인해봅시다.

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode != RESULT_OK) {
return;
}
if (requestCode == 3641) {
//... 처리코드
} else if (requestCode == 2172) {
//... 처리코드
}
}

드디어 끝이 보입니다. 이번 코드는 조금 짧게 썻는데요… 귀찮아서 절대아님..~
결과를 받아올 경우에는 onActivityResult()라는 특별한 메서드를 이용합니다.
해당 메서드가 조금은 복잡해 보일지 모르겠지만, 이미 우리는 지금까지 모두 사용했던 것이므로 굉장히 간답합니다.

우선은 인자값들부터 하나하나 확인해보죠.

  • int requestCode: startActivityForResult()메서드를 실행할 때, 두번째 인자값으로 넘겨준 REQUEST_CODE
  • int resultCode: setResult()메서드를 실행할 때, 첫번째 인자값으로 넘겨준 RESPONSE_CODE
  • Intent data: setResult()메서드를 실행할 때, 두번째 인자값으로 넘겨준 데이터가 담겨있는 Intent 객체

어때요? 하나하나 살펴보니 되게 쉽지요?
저것들만 이해하면 이제 코드를 나머지 코드는 식은 죽 먹기입니다.

우선은, 응답코드를 확인하여 RESULT_OK가 아니라면 해당 메서드를 종료해버리는 코드가 작성되어 있습니다.
이외의 응답코드에 대한 코드가 더 필요하다면 조건절로 작성해주시면 되겠죠?

그런 다음, 응답코드가 RESULT_OK라면 REQUEST_CODE에 따라서 해당하는 처리로직을 작성해주시면 됩니다.
굳이 양념을 첨가하여 예제코드에 있는 3641에 해당하는 처리코드만 작성해보자면…

1
2
int sum = data.getIntExtra("sum", 0);
Log.d("MainActivity", sum);

뭐… 이정도가 되겠네요… 굳이 작성하지 않은 이유를 아시겠죠?

위에서 잠깐 언급했지만, REQUEST_CODE는 기억을 하고 있어야 된다고 이야기 했었습니다. 그 이유가 바로 결과를 받는 곳에서 나타납니다.
현재 예제코드에는 한 화면에서 호출하고 다시 전달받는 코드가 한번만 사용되었기에 굳이 외우고 있을 필요는 없지만, 실제 어플리케이션을 개발하다보면 한 화면에서 여러 Activity로부터 결과값을 전달받는 경우가 발생합니다. 하지만 REQUEST_CODE를 기억하고 있지 못하다면, 각각에 기능에 맞는 처리로직을 작성할 수 없을 뿐더러, 여러개로 작성하더라도 REQUEST_CODE가 엉뚱하다면 전혀 생각지도 못하게 어플리케이션이 기능이 꼬이게 되겠죠? 그래서 REQUEST_CODE를 기억하고 있으셔야 된다고 한 것 입니다.

약간의 TIP?

여기까지 보셨다면 이미 이번 포스팅에서 원하고자하는 목적은 도달하였으니 제 블로그를 끄셔도 됩니다. 하지만 안보면 후회할껄?
여기서부터는 실제 개발하면서 조금은 이렇게 개발하면 관리하기 편하더라(?)하는 정보를 적어볼까 합니다. 특별한건 없으니 그렇게 큰 기대는…
솔직히 Intent와 관련하여 특별한 TIP은 없습니다. 아마 개발자라고 하시면 모든분들이 이렇게 하고 계실수도 있어요…

REQUEST_CODE는 상수를 활용하라.

이부분은 REQUEST_CODE에만 국한되지는 않습니다
변하지 않는 데이터라면 목적에 맞게 상수로 정의해두면 시간이 흐른 뒤, 어떤 목적으로 사용되었는지 기억하기도, 관리하기도 쉽습니다.
사람의 기억력은 그렇게 좋지 않기에, 시간이 많이 흐른 뒤 소스코드를 다시 열어 3641이라는 리터럴 데이터가 들어가 있으면 혼동스러을 수 있습니다.
이런 리터럴 데이터보다는 이해하기 쉽고 직관적인 상수명으로 사용이 되어 있다면, 시간이 흐른 뒤 열어보더라도 아! 이 코드는 내가 뭘 원했기 떄문에 사용했지!하며 기억하기에 좋습니다.

1
2
3
private static final REQUEST_CODE_SUM = 3641;
private static final REQUEST_CODE_CAMERA = 2172;
//... 등등등

putExtra / getExtra에 사용되는 KEY 역시도 상수로 활용하라.

실제 개발을 하다보면 혼자서 모든 개발을 맡아 작업하시는 분은 거의 없으시리라 봅니다. 특히 우리는 안드로이드 개발자이므로 서버개발자와 협업하는 일이 빈번하게 일어나죠.
이런 경우, 협업을 하다보면 서버와 통신시에 필요한 데이터의 경우 커뮤니케이션 향상과 협업을 위해 서버와 클라이언트가 명칭을 통일하게 되는 경우도 발생합니다. 저희는 그렇게 하고있…
그리고 대체적으로 이런 일은 서버 통신 시에 필요한 최소한의 KEY값에 해당하는 경우가 많습니다.
특히 이러한 KEY값에 해당하는 명칭들은 여러 Activity에 걸쳐 사용되기도 하죠.
그러다 개발 도중 잦은 기획의 변경이나 특정 목적에 따라 명칭이 변경된다면? 상상만해도 머리가 지끈거리기 시작합니다.
모든 Activity를 찾아다니며 명칭을 변경해줘야되는 불상사가 생기기 떄문이죠…
이러한 불상사를 미연에 방시할 수 있도록 되도록이면, EXTRA의 KEY로 사용되는 리터럴 데이터는 하나의 Class로 따로 분리하여 관리포인트를 최소화 시키는 것도 좋습니다.

1
2
3
4
5
6
7
8
9
10
// Class 선언
public class Constants {
public static final String EXTRA_SERVER_KEY = "serverKey";
public static final String EXTRA_CLIENT_KEY = "clientKey";
public static final String EXTRA_BOARD_ID = "boardId";
}
// Activity등에서 실 사용.
Intent intent = new Intent();
intent.putExtra(Constants.EXTRA_SERVER_KEY, "xxxxxx");

끝맺으며..

이번 포스팅에서는 Intent 객체를 이용하여 여러방법으로 화면을 전환하고, 다시 돌아오는 등의 내용을 작성해보았습니다.
그리고 추가적으로, 크게 도움이 되지 않는 TIP일 수 있겠지만, 현업을 하다 생기는 문제를 조금은 해소하고자 나름의 TIP도 몇자 적어보았습니다.
이미 능력이 좋으신 개발자분들은 저게 무슨 TIP이야?라고 할 수 있는 소소한 정보이지만,
저는 선임자 없이 혼자서 모든걸 해결해오던 스타트업의 개발자이므로…ㅜㅜㅜㅜㅜㅜ
저런 사소한 부분때문에 골치가 아프기도, 그리고 불필요한 시간허비도 했었던 것 같습니다.
그래서, 혹시 제 포스팅을 보고 계신 여러분이 개발을 시작하시는 분이라면 이러한 삽질을 조금이라도 덜 하시길 원하는 마음에 몇자 적어보았습니다!

물론, 개인 프로젝트로 개발을 진행한다면 문제가 없겠지만,
이러한 사소한 코드 작성법과 습관이 실제 현업에서 협업하는 개발자라면, 혹은 이직을 고민하는 개발자라면!
회사에 남아있는 사람 또는, 내 뒤를 이어줄 후임자를 위해서라도 좋은 습관이 될 것 같습니다!

그럼 이만 길어진 오늘의 포스팅은 여기서 마무리 하도록 하겠습니다! 안녕!