본문 바로가기

개발 이야기/Android

[안드로이드/개발] Intent, Activity, ACTION, OnActivityResult() 총정리

안드로이드 프로그래밍에서 중요한 개념 'Intent'

보고있는 책보다도 잘 정리를 해 놓았다.....

[원문] http://gtko.springnote.com/pages/5254593?edit=1

인텐트를 통한 액티비티를 명시적으로 시작하는 방법, 암시적인 인텐트로 데이터의 한 부분에 대해 수행되는 액션을 요청하는 방법, 안드로이드가 그 요청을 서비스할 수 있는 애플리케이션 콤포넌트를 결정하도록 하는 방법을 설명한다.

브로드캐스트 인텐트는 시스템 전역에 이벤트를 알린다. 즉, 브로드캐스트로 전송하고 브로드캐스트 수신자로 이를 받아 처리한다.

어댑터는 데이터 소스와 프리젠테이션(view 들)과 연결하는 방법.

 

인텐트 소개

어 떤 액션이 수행되는데 특정 데이터의 특정 부분을 가지고 수행하라는 선언으로 메시지를 전달하는 메커니즘이다. 즉, activity, native 장치 등 상호간의 작용을 지원한다. 독립적인 콤포넌트들의 컬렉션을 서로 연결된 단일 시스템으로 변경하는 역할이기도 하다.

 

인텐트 역할

액티비티를 명시적( 클래스 지정) 혹은 암시적(데이터의 어느 한 부분에 대해 수행되는 액션을 요청)으로 시작하는 것.

브로드캐스트 인텐트로 이벤트 중심 애플리케이션을 구성할 수 있다

 

인테트로 activity 시작

인텐트는 애플리케이션 내에 있는 activity 간의 시작, 중지, 전이에 사용된다.

 

현재 activity에서 다른 activity 화면을 열려면, startActivity() 를 사용한다. 이 액티비티는 부모 액티비티와 독립적이다.

  1. startActivty(a_intent)
  • Intent a_intent 는 대상 클래스를 명시적으로 지정하거나, 수행할 액션일 수 있다. 액션을 지정하면 런타임은 intent resolution 이라는 과정을 거쳐 acitivity를 선택한다.

 

명시적 activity start

AndroidMenifest에 선언된 activity 를 명시적으로 지정해 시작할 수 있다.

  1. Intent intent = new Intent(MyActivity.this, MyOtherActivity.class);
  2. sgtartActivity(intent);
  • startActivity()가 수행되면 현재 MyActivity는 onPause() 상태로 가고, MyOtherAcitivity 가 활성상태로 스택의 맨 위로 갈 것이다.
  • 새로운 acitivity에서 finish()를 호출하면 MyActivity는 종료되어 스택에서 제거된다.
  • 그렇지 않다면 MyOtherActivity에서 back button을 누르면 MyActivity로 돌아 올 수 있다.

 

  1. Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setClassName(this, MyActivity.class.getName());
    startActivity(intent);

 

암시적 activity start

수행할 액션과 요구되는 데이터로 acitvity를 시작할 수 있다.

 

예를 들어 dialer를 통해 전화걸기를 하려며 새로운 dialer를 구현하기 보다 기존 dialer와 전화목록을 이용하면 될 것이다.

  1. Intent new_intent = new Intent( Intent.ACTION_DIAL, Uri.parse("tel:555-2368")
  2. startAcitivity(new_intent)
  • runtime은 new_intent를 분석해 전화번호에 대한 전화걸기 action을 제공하는 acitivity를 시작한다.
  • 여러 native application은 이런 액션에 대한 콤포넌트를 제공하고, 사용자도 새로운 액션을 지원하거나
  • 네이티브 액션의 대체 공극바를 제공하기 위해 등록될 수 있다.

 

Linkity 로 시작

정 규식 패턴 매칭을 통해 TextView 에 하이퍼링크를 자동으로 생성해 주는 helper class잉다. 즉 패턴에 일치하는 텍스트는 그것을 대상 URI로 사용해 암시적으로 startAcitivity( new Intent(Intent.ACTION_VIEW, uri)) 를 호출하는 하이퍼 링크로 변환된다.

Linkify 클래스는 대표적으로 TextView와 Spinnerable UI 를 사용할 수 있다.

 

코드에서 Likify 사용
  • 텍스트에 있는 http url, email 주소를 likify 한다.
  1. TextView myTextView = (TextView)findViewById(R.id.myTextView);
    Linkify.addLinks(myTextView, Linkify.WEB_URLS|Linkify.EMAIL_ADDRESSES);
  • url 을 클릭하면 웹브라우저가 열리고, email 주소를 클릭하면 email client가 호출된다.

 

view 선언에서 linkify 사용

android:autoLink 속성에 none, web, email, phone, all 에 self-describing-values로 '|'로 구분해 사용할 수 있다.

  1.   <TextView
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/linkify_me"
        android:autoLink="phone|email"
      />

 

사용자 정의 linkify 문자열 만들기

사용자 RegExp 를 만들어 linkify 문자열로 사용할 수 있다.

  1.    int flags = Pattern.CASE_INSENSITIVE;
        Pattern pattern = Pattern.compile("\\bquake[0-9]*\\b", flags);
        Linkify.addLinks(myTextView, pattern, "content://com.pad.earthquake/earthquakes/");
  • quake로 시작하고 그 뒤에 숫자가 나오는 모든 문자열 찾아 content://.. URI에 붙여준다.

 

TransformFilter, MatchFilter 인터페이스 이용한 문자열 사용

RegExp 패턴 매치에 추가적인 조건을 더할 수 있다.

  1. MatchFilter matchfilter = new MatchFilter() {
         public boolean acceptMatch(CharSequence s, int start, int end) {
               return (start == 0 || s.charAt(start-1) != '!'); }
     };
    TransformFilter transformfilter =  new TransformFilter() {
           public String  transformUrl(Matcher match, String url) {
               return url.toLowerCase(); }
     };

    String prefixWith = "http://www.";       
    pattern = Pattern.compile("\\bTEST.COM\\b");
    Linkify.addLinks(myTextView, pattern, prefixWith, matchfilter, transformfilter );

  • 문자열 앞에 !가 있는 것은 취소하는 필터 구현.

 

 

액티비티 결과

서 브액티비티를 시작하면 서브 액티비티가 종료할 때 부모의 이벤트 핸들러(onActivityResult())를 호출한다. startActivityForResult() 는 시작할 intent 와 request code 를 사용해서 activity의 결과를 request code로 식별한다.

 

 

명시적으로 서브 액티비티 시작
  1. private static final int SHOW_SUBACTIVITY = 1;
  2. Intent intent = new Intent(getApplicationContext(), MyOtherActivity.class);
    startActivityForResult(intent, SHOW_SUBACTIVITY);

 

암시적 서브 액티비티 시작
  1. private static final int PICK_CONTACT_SUBACTIVITY = 2;
  2. Uri uri = Uri.parse("content://contacts/people");
    Intent intent = new Intent(Intent.ACTION_PICK, uri);
                    // Result resturned in onActivityResult
    startActivityForResult(intent, PICK_CONTACT_SUBACTIVITY);

 

서브액티비티에 데이터 전달하기

Intent intent = new Intent();
Bundle bun = new Bundle();

bun.putString(”param_string”, “the actual string”); // add two parameters: a string and a boolean
bun.putBoolean(”param_bool”, true);

intent.setClass(this, SecondaryActivity.class);
intent.putExtras(bun);
startActivity(intent);

 

서브액티비티에서 전달된 데이터 처리...

Bundle bun = getIntent().getExtras();
String param1 = bun.getString(”param_string”);
boolean param2 = bun.getBoolean(”param_bool”);

 

서브 액티비티 / 인텐트 필터 호출에 응답

암시적으로 호출된 서브액티비티에서 수행할 액션, 데이터를 통해 요청된 작업을 진행한다.

  1. @Override
  2. public void onCreate(Bundle bundle) {
  3.     ...
  4.     Intent intent = getIntent(); // 수행할 action, date 를 얻기 위해.
  5.     String action = intent.getAction();
  6.     Uri data = intent.getData();
  7. ...
  8. }

또한 다음과 같이 startNextMatchingActivity() 메서드로 액션의 처리 책임을 가장 잘 일치하는 컴포넌트로 넘길수 있다. 

즉, 야밤에 다른 intent 로 처리를 넘겨버리는 예이다.

 

  1.     Intent intent = getIntent(); // 수행할 action, date 를 얻기 위해.
  2.     if( isAfterMidnight)
  3.        startNextMatchingActivity(intent);

 

 

서브 액티비티 / 결과 돌려주기

finish()를 호출하기 전에 setResult() 로 결과를 저장한다. 결과 코드와 Intent로 표현된 result payload 로 제공된다.

Activity.RESULT_OK, Activity.RESULT_CANCELED 를 결과로 많이 사용하고, 사용자 정의 결과값을 줄 수 있다. 결과 인텐트에 연락처, 전화번호, 미디어 파일에 대한 URI 정보를 가질 수 도 있다.

  1.         Uri data = Uri.parse("content://horses/" + selected_horse_id);  
            Intent result = new Intent(null, data);
            result.putExtra(IS_INPUT_CORRECT, inputCorrect);
            result.putExtra(SELECTED_PISTOL, selectedPistol);
            setResult(RESULT_OK, result);   
            finish();

 

 

결과 받기

부모 액티비티에서 onActivityresult() 메소드는 서브액티비티의 결과를 받는다.

  • Request code: 서브 액티비티를 시작하는데 사용되었던 요청 코드
  • Result code: 서브 액티비티가 자신의 결과를 나타내기 위해 설정한 코드 예) Activity.RESULT_OK, Activity.RESULT_CANCELED

    • 서브 액티비티가 비정상 종료되거나 결과코드가 지정 안되면 Activity.RESULT_CANCELED 이 결과 코드이다.
  • data: 모든 결과를 담은 인텐트.

 

  1.  @Override
      public void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
      
        switch(requestCode) {
          case (SHOW_SUBACTIVITY) :
            if (resultCode == Activity.RESULT_OK) {
              Uri horse = data.getData();
                boolean inputCorrect = data.getBooleanExtra(IS_INPUT_CORRECT, false);
                String selectedPistol = data.getStringExtra(SELECTED_PISTOL);
              Toast.makeText(this, "Pistol Selected: " + selectedPistol, Toast.LENGTH_SHORT).show();               
            }
            break;       
           
          case (PICK_CONTACT_SUBACTIVITY) :
            if (resultCode == Activity.RESULT_OK) {
              Toast.makeText(this, "CONTACT SELECTED", Toast.LENGTH_SHORT).show();
              // TODO Handle contact selection.
            }
            break;      
        }

 

 

Native android action

네이티브 안드로이드 애플리케이션도 역시 인텐트를 사용해 액티비티와 서브 액티비티를 시작한다. Intent 에서 제공하는 네이티브 액션을 살펴보자. 아래 static 문자열은 암시적으로 인테트를 사용할 때 유용하다.

 

상수타겟 컴포넌트액션
ACTION_CALL activity 전화를 걸어라.
ACTION_EDIT activity 사용자에게 편집할 데이터를 표시하라.
ACTION_MAIN activity 데이터 입력과 반환 결과 없이 태스크의 최초의 액티비티로써 액티비티를 실행하라.
ACTION_SYNC activity 모바일 디바이스의 데이터와 서버의 데이터를 동기화하라.
ACTION_BATTERY_LOW broadcast receiver 배터리가 부족하다는 경고.
ACTION_HEADSET_PLUG broadcast receiver 헤드셋이 디바이스에 연결 또는 분리되었다는 것.
ACTION_SCREEN_ON broadcast receiver 스크린이 켜졌다는 것.
ACTION_TIMEZONE_CHANGED broadcast receiver 타임존 설정이 바뀌었다는 것.

ACTION_INSERT : 지정된 커서로 새로운 항목을 삽입할 수 있는 액티비티를 연다. 서브 액티비티느 새로 삽입된 항목에 대한 URI를 리턴해야 한다.

ACTION_PICK: URI 로 부터 데이터 항목 하나를 고를 수 있는 서브 액티비티를 듸운다. 예) content://contacts/people 전달되면 네이티브 연락처 목록이 뜬다.

ACTION_SEARCH; 검색, SearchManager.QUERY 키를 사용하는 인텐트의 엑스트라 문자열 형태.

ACTION_SENDTO: uri에 지정된 사람에게 보내는 액티비티.

ACTION_SEND: 지정된 데이터를 전송하는 액티비티 시작. 인텐트 타입은 setType을 사용해 전송되는 데이터의mime타입으로 설정

ACTION_VIEW: URI가 합리적으로 보여지게 요청. http: 는 브라우져, tel: 다이얼러, geo: 구글맵

ACTION_WEB_SEARCH: uri에 웹검색을 수행하는 액티비티를 연다

Intent intent = new Intent(Intent.ACTION_WEB_SEARCH );
intent.putExtra(SearchManager.QUERY, “검색어”);
startActivity(intent);

참조

http://www.itwizard.ro/how-to-create-a-new-android-activity-82.html

 

 

인텐트 필터를 이용한 암시적 인텐트 서비스

인텐트가 데이터 집합에 대해 수행되는 액션을 위한 요청으로 보면 인텐트 필터는 액티비티, 서비스, 브로드캐스트 수신자를 특정한 종류의 데이터에 대한 액션을 수행하는 존재로 등록하는데 사용.

  1.       <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
          </intent-filter>

        <activity android:name=".EarthquakeDamageViewer" android:label="View Damage">
          <intent-filter>
            <action android:name="com.paad.earthquake.intent.action.SHOW_DAMAGE"/>
            <category android:name="android.intent.category.DEFAULT"/>
            <category android:name="android.intent.category.ALTERNATIVE_SELECTED"/>
            <data android:mimeType="vnd.earthquake.cursor.item/*"/>
          </intent-filter>
        </activity>

  • action: 서비스 되는 액션의 이름. 액션은 유일한 문자열이어야 하므로 자바 패키지 이름 규약을 사용한다.
  • category: 액션이 서비스 되어야 하는 상황을 지정. 여러개의 category 가능.

    • 안드로이드 기본 cagegory

      • android.intent.category.ALTERNATIVE: 기본 액션에 대한 대안 액션임을 선언.
      • android.intent.category.SELECTED_ALTERNATIVE: 대안으로 선택 가능한 것들에 대한 선언.
      • android.intent.category.BROWSABLE: 브라우져 안에서 사용 가능한 액션 지정.
      • android.intent.category.DEFAULT : 데이터 값에 대한 기본 액션으로 지정.
      • android.intent.category.GARGET : 이 액티비티가 다른 액티비티 내부에 포함되어 동작 할 수 있도록 지정.
      • android.intent.category.HOME: 네이티브 홈 스크린의 대안.
      • android.intent.category.LAUNCHER: 애플리케이션 런처.
  • data: 실행 할 수 있는 데이터에 대한 명세. 여러개 지정 가능.

    • android:host: 유효한 호스트 이름
    • android:mimetype: 데이터 형식. 예) <data android:mimeType="vnd.moonbase.cursor.item/*"/> 는 ㅁ든 안드로이드 커서
    • android:path: URI에 대한 유효한 경로 값 예) /transport/boarts/
    • android:port 지정된 호스트에 대한 유효한 포트
    • android:scheme 특정한 스킴. 예) contnet, http
  •  

 

안드로이드가 인텐트 필터를 찾는 방법

인테트 URI 실행시 실행 할 수 있는 액티비티가 여러개 존재하면 그중 가장 좋은 것이 시작될 것이다. 이런 과정을 Intent resolution 이라 한다.

  1. 설치된 패키지로 부터 사용 가능한 모든 인텐트 필터들의 리스트를 구성
  2. action이나 cagegory에 맞지 않는 필터는 제외

    1. 필터가 지정된 액션을 포함하거나 아무런 액션도 지정되지 않은 경우 action matches 가 이루어 진다.
      정의된 action이 있지만 지정된 액션과 일치않으면 실패
    2. category matching: 인텐트 필터는 인텐트에 정의된 모든 category 를 반드시 포함해야 한다. catregory가 지정되지 않은 인텐트 필터는 category가 없는 인텐트하고만 일치된다.
  3. 인텐트에 있는 data uril 의 각 부분이, scheme, permissionk path, mime 등 정의하고 있다면, 인텐트 필터의 data 태그와 비교 된다.

    1. MIME: 와일드카드를 이용해 하위 타입을 일치할 수 있다.
    2. scheme: URI의 프로토코 부분. http, ftp...
    3. host name, URI에서 경로 사이에 있는 부분 www.google.com
    4. 경로
  4. 이 과정에서 하나 이상의 컴포넌트가 확인되면 인턴트 필터 노드에 추가될 수 있는 선택적 태그와 함께 우선순위에 따라 순서가 매겨진다. 그런다음 가장 높은 순위의 컴포넌트가 리턴된다.