들어가기 전에
화면을 실행할 때 인텐트가 사용된다는 것을 알게 되었습니다.
시스템에서 이해할 수 있는 객체로 만든 것이 인텐트인데, 이 인텐트 안에는 여러 가지 정보가 들어갈 수 있습니다.
어떤 정보를 넣느냐에 따라 시스템이 해석하는 방법이 달라질 수도 있고요.
만약 다른 화면으로 데이터를 전달하고 싶다면 인텐트 안에 넣어서 전달할 수도 있습니다.
자주 사용되는 인텐트를 잘 알아야 화면을 실행하거나 다른 화면으로 데이터를 전달하는 일이 쉬워집니다.
인텐트에 대해 살펴보고 데이터를 넣어 전달하는 방법도 알아봅시다.
학습 목표
- 인텐트를 어떻게 사용하는지 좀 더 알아봅시다.
- 한 화면에서 다른 화면으로 데이터를 전달할 때 어떻게 해야 하는지 설명해봅시다.
핵심 단어
학습하기
인텐트
화면을 실행하는 일은 안드로이드 시스템에서 담당합니다.
그리고 인텐트는 시스템으로 전달되는 일종의 명령을 담고 있는 객체입니다.
시스템이 이해할 수 있는 객체를 하나 만들어둔 거죠.
이 인텐트 안에 들어있는 명령이나 데이터를 시스템에서 이해한 후에 시스템이 어떤 일을 해주게 되는데, 애플리케이션 구성요소들은 시스템에서 관리하므로 화면뿐만 아니라 나중에 배우게 될 서비스나 브로드캐스트 리시버의 경우에도 인텐트를 이용해 정보를 주고 받게 됩니다.
인텐트 안에 들어가는 정보 중에서 가장 중요한 것은 액션 정보입니다.
전화걸기를 시스템에 요청할 때는 ACTION_VIEW나 ACTION_DIAL 액션을 넣어줄 수 있는데 이렇게 하면 시스템에서 어떤 동작을 원하는지 이해할 수 있습니다.
전화걸기를 원하는 인텐트는 다음과 같이 사용됩니다.
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse("tel:01010001000"));
startActivity(intent);
이전 시간에 만들었던 메뉴 액티비티를 띄우고 싶다면 MenuActivity.class 라는 클래스 인스턴스를 인텐트의 파라미터로 넘겨주는 방법과 그 외에도 ComponentName 객체를 만들어 설정하는 방법이 있습니다.
Intent intent = new Intent();
ComponentName name = new ComponentName("org.techtown.intent",
"org.techtown.intent.MenuActivity");
intent.setComponent(name);
startActivityForResult(intent, 101);
패키지의 이름까지 넣어주어야 하니 좀 더 복잡해 보이지만 실행하고 싶은 액티비티를 문자열로만 지정할 수 있어서 동적으로 액티비티를 지정해주고 싶을 때 사용할 수 있습니다.
액티비티를 위한 플래그
메인 액티비티에서 메뉴 액티비티를 실행하는 경우 액티비티에서 시스템을 통해 다른 액티비티를 실행하는 형태가 됩니다.
그런데 화면이 없는 서비스라는 것에서 액티비티를 실행하는 경우도 있습니다.
이 때는 액티비티를 새로 만들어 실행할 수도 있지만 이미 사용자가 보고 있는 액티비티 위에 액티비티를 실행하게 되는 경우가 생길 수도 있습니다.
결국 동일한 액티비티인데 두 개가 만들어지게 되고 가장 위에 있는 것만 보이는 상황이 만들어지는 거죠.
이 때 맨 위에 있는 액티비티를 finish 메소드로 없애더라도 사용자에게는 동일한 모양의 화면이 다시 보이게 되는 문제가 발생합니다.
이런 경우에 플래그를 사용하면 동일한 액티비티인 경우 이미 화면에 보이는 액티비티를 그대로 사용할 수 있도록 해 줍니다.
대표적으로 사용되는 플래그 중의 하나가 FLAG_ACTIVITY_SINGLE_TOP 인데 다음과 같이 플래그를 사용할 때와 사용하지 않을 때를 비교해볼 수 있습니다.
새로 실행하려는 액티비티와 화면에 보이는 액티비티가 동일한 액티비티인 경우 메모리에 새로 만들지 않고 화면에 보이는 액티비티를 그대로 보여줍니다.
그런데 이미 만들어져서 화면에 보이고 있는 액티비티를 그대로 사용므로 onCreate 메소드가 호출되지 않습니다.
onCreate 메소드는 액티비티가 메모리에 처음 만들어질 때 자동으로 호출되는데 화면이 이미 만들어져 있으니 호출되지 않는 거죠.
이때는 onNewIntent 라는 메소드가 호출됩니다.
이 메소드가 별도로 호출되는 이유는 인텐트를 전달받기 위해서입니다.
onCreate가 호출되는 경우에는 그 안에서 getIntent 메소드를 이용해 전달받은 인텐트 객체를 확인할 수 있지만 onCreate 메소드가 호출되지 않는 경우에는 onNewIntent 메소드 안에서 인텐트 객체를 확인할 수 있도록 합니다.
comment
⭐️생각해보기⭐️
1. 페이지 수, 시스템을 사용하는 기능들 (전화걸기, 연락처, 갤러리 등)을 많이 사용하는 앱일수록 인텐트를 많이 사용할 것 같습니다.
2. requsetCode나 resultCode값 그리고 extra 값으로 구분할 수 있지 않을까 생각합니다.
3. 아니요 시스템으로 전달되는 데이터이니 가급적 적게해야 단말기에 부하를 줄일 수 있다고 생각합니다. 또한 CPU나 메모리를 많이 사용하는 앱은 안드로이드 OS내에서 경고 알림이 뜨는 걸로 알고 있습니다. 이러한 경고를 받게되면 사용자의 UX경험도 저하될 것 같아요! 그러므로 시스템으로 전달되는 데이터는 크기를 제한해서 너무 큰 데이터가 시스템을 중지시키지 않도록 주의해야하지 않을까요?
Main에서 상속되는 자바파일로 데이터 전송도 intent로 가능한가요?
Intent intent = new Intent(getApplication(), CommentWriteActivity.class);
이것을
Intent intent = new Intent(MainActivity. this, CommentWriteActivity.class);
라고 바꿔도 되나요??
말씀해주신 사항 중 매니페스트에 uses-permission 읽고 쓰기 권한을 추가하는 것과 gradle에서 target버전을 22로 낮추는 것은 이미 했습니다. 그렇다면 남은 건 경로가 다를 수 있다는 건데 말씀하신 로그를 확인해보니
책에 나와있는 소스 코드를 작성했을 경우 /storage/emulated/0 이 경로로 지정이 되는데 찾아보니 이건 내부 경로를 지정하는 거라고 하더라구요... 그래서 pdf 파일을 내부 저장소로 넣고 실행해보니 드디어 되네요. 책에서는 분명 sd카드를 지정하는 경로라고 했는데 왜 내부저장소가 지정되는 건가요;; 외부저장소를 지정하기 위해서는 어떻게 해야 하죠?
책에 나와있는 PDF파일 앱 예제를 그대로 따라했는데요. PDF파일을 SD카드에 넣고 앱을 실행시켜서 파일명을 입력하면 파일을 찾을 수 없다고만 나옵니다. 예제소스를 다운받아서 그걸 그대로 실행시켜도 마찬가지 현상이 나오구요. 원인이 뭔가요 대체... 답답해 죽겠습니다.
인텐트의 재 사용에대해 질문하겠습니다. 인텐트의 재사용이라는 말은 처음 실행된 엑티비티보다 두 번째 실행되는 엑티비티인가요? ex) 메인엑티비티->1번엑티비티(처음 생성) 2번엑티비티->1번엑티비티(재사용????)
질문: 엑티비티의 재사용이라는 것은 정확히 무엇을 지칭하는 말인 가요?
처음부터 자료형을 클래스에 선언해주면 코드작성시 편리한거 아닌가요? 왜 먼저 찾아주는거에 전체 글 다쓰고 하는지 궁금합니다 :)
궁금한게 있는데요. 받은 부가데이터정보도 다른 액티비티에 전달할수있나요?
생각해보기
1. 시스템으로의 정보전달이 필요한 모든 행위에 인텐트가 필요하다고 생각하면 정말 많이 쓰일 것 같습니다.
2. 네. intent 객체 생성을 할때 지정한 이름으로 intent들을 구분 할 수 있지 않을까요?
3. 잘은 모르겠지만 시스템이 받아들일 수 있는 범위까지 제한될 필요가 있을 것 같습니다.