본문 바로가기

수업 정리

82일차 수업정리(Android - ActionBar, 데이터 전송)

**Action Bar

    => API Level 11에서 추가된 상단의 TitleBar

    => 기본적으로는 타이틀로 설정한 문자열이 출력되지만 App Icon 이나 View Control, Action Button, Overflow Menu등의 출력 가능

    => 테마설정을 이용해서 보이지 않도록 설정하는 것이 가능

    => ActionBar를 보이게하고, 보이지 않게 하기

        - Activity에서 getSupportActionBar를 호출하여 ActionBar 객체를 얻어내고 Show, hide 메소드를 호출하여 동적으로 보이기 가능

    => 테마 설정에서 windowActionBarOverlay를 이용시 액션바를 투명하게 만들어 ContentView에 떠 있도록 하는 것이 가능

    => ActionBar에 보여지는 문자열을 설정

        - Androidmanifest.xml 파일의 Activity등록 태그에서 android:label="문자열" 추가시 Activity마다 보여지는 문자열을 별도 설정

        - 이미지 뷰 위에 ActionBar를 출력하고, 액션바에 이미지를 출력하고 텍스트를 변경

1. Android Application 생성

 

2. img.png, icon.png 파일을 drawable 디렉토리에 복사

 

3. 메인화면 레이아웃 수정

    => 전체에 Image를 출력할 ImageView 추가

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    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"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/img"/>

</LinearLayout>

 

4. ActionBardp 적용할 style 생성 - res/values/styles.xml

    <style name="MainTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">#00000000</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="windowActionBarOverlay">true</item>
    </style>

 

5. AndroidManifest.xml 파일의 Activity를 등록하는 옵션 수정

        <activity android:name=".MainActivity"
            android:label="액션바와 메뉴 및 커스텀 뷰"
            android:theme="@style/MainTheme">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

 

6. mainActivity.java 파일의 onCreate 메소드에 ActionBar를 동적으로 변경하는 코드 작성

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //액션바를 가져오기
        ActionBar actionBar = getSupportActionBar();
        actionBar.setDisplayHomeAsUpEnabled(true);
        actionBar.setDisplayShowHomeEnabled(true);
        actionBar.setIcon(R.drawable.icon);
    }

    => 애플리케이션 구현 후, 각 Activity에 맞게 구성을 다시하는 것을 권장

 

**Menu

    => PC용 애플리케이션에서 상단에 배치하여 사용자의 명령을 받아들이는 인터페이스

1. 안드로이드에서의 메뉴

  1) Option Menu

    => 안드로이드 기기 하단의 메뉴 버튼을 누르면 보이던 것이었는데, 현재는 상단으로 이동

    => 이 메뉴는 최대 6개까지의 항목 소유 가능, 6개 초과시 6번째 메뉴가 more가 되고, more클릭시 나머지 메뉴 출력

    => 이미지 출력은 가능하지만 체크박스, 라디오버튼은 배치 불가

    => Activity에 boolean onCreateOptionsMenu(Menu menu)메소드를 재정의 하여 menu에 항목들을 add하여 배치

    => 이전에는 Activity제작시 위의 메소드가 구현된 상태였으나 최근에는 구현되어있지 않음

        - 이전 기기들에는 기기하단 오른쪽에 메뉴버튼이 있었으나 현재는 없음

        - 메뉴명 설정이 불가능하여 화면에서는 메뉴에 어떤 항목이 있는지 알수 없어 설명이 필요(모바일에서는 잘 사용하지 않음)

 

2. Context Menu

    => View를 길게 누르면 보여지는 메뉴

    => iOS는 이 메뉴에 이벤트 설정이 가능한데 안드로이드는 LongClick으로만 사용

 

3. Popup Menu

    => 특정 이벤트가 발생했을 때 보여지는 메뉴

 

**Custom View

    => 사용자 정의 뷰라고 하는데 직접 View클래스를 만드는 것

1. 목적

    => Drawing을 하기 위해(그리기를 하기 위한 것)

    => 제공되는 뷰 클래스의 모양을 변경하기 위해서 

 

2. 하는 방법

    => 필요한 View 클래스를 extend하여 구현

    => 제공되는 클래스를 상속받아 필요 기능 구현하는 것을 subclassing이라고 함

    => 대부분의경우 Activity안에 내부 클래스로 만드는 경우가 많음

    => 하나의 Activity안에서만 사용될 가능성이 높고, 명칭 충돌 발생 가능성을 배제하기 위해 Java에서는 GUI이벤트 처리를 위한 클래스나 인터페이스를 별도의 클래스나 인터페이스로 제공

    => 이름들은 대부분 Camel표기법을 사용하고 클래스 이름에 기능을 명시하는 경우가 많아 이름충돌이 많이 발생

    => Android에서의 이벤트 처리 인터페이스나 클래스들을 내부 인터페이스나 클래스로 제작

 

3. Custom View에 그리기

    => Canvas를 이용해서 그림

        - 다른 프로그래밍에서는 대부분 Context라고 함

        - 안드로이드에서는 Context라는 클래스가 존재하므로 Canvas라고 이름 붙인 것

  1) Canvas(Context)

    => 화면에 그림을 그리기 위해서는 여러가지 정보가 필요

        - 선 색상, 면 색상, 선 두께 등이 필요

        - 그림을 그릴 때마다 위의 정보를 매번 설정시 그리는 코드가 너무 복잡해짐

        - 기본적인 그림 정보를 객체에 저장해두고 그림을 그리는 메소드호출시 그 정보를 이용하여 그림

        - 이러한 그리기 정보를 가진 객체를 일반적으로 Context라고 함

  2) 기존 View 클래스를 상속받아 그리는 이유

    => GUI 프로그래밍에서는 Canvas를 직접 생성하는 것을 허용하지 않음

    => View 클래스 안의 onDraw 메소드의 매개변수로 전달

        - onDraw 메소드는 View가 화면에 그리기 직전에 호출되어 View를 화면에 그려주는 메소드

        - View가 처음 보여질 때나 가려졌다가 다시 나타날때 호출되는 메소드

  3) Canvas 클래스의 그리는 메소드

    - void drawPoint(float x, float y, Paint paint)

    - void drawLine(float cx, float cy, float stopX, float stopY, Paint paint)

    - void drawRect(float cx, float cy, float right, float bottom, Paint paint)

    - void drawLine(float cx, float cy, float radius, Paint paint)

    - void drawLine(String text, float cx, float cy, Paint paint)

 

4. Custom View를 Activity에 출력하기

    => 전체 화면으로 만드는 경우 setContentView(View view)를 호출, 현재 화면위에 출력하는 경우 addContentView(View view) 호출

 

5. Custom View를 Activity에 출력하고 그리기

  1) 실행가능한 Activity 추가 - CustomActivity.java

 

  2) Activity 클래스 내부에 View클래스를 상속받는 클래스를 생성

    //view 클래스로부터 상속받는 CustomView
    class MyView extends View{
        //기본 생성자가 없으므로 생성자를 만들어 상위 클래스의 생성자를 호출
        public MyView(Context context) {
            super(context);
        }
        
        //View가 화면에 표시될 때 호출되는 메소드
        @Override
        public void onDraw(Canvas canvas){
            //그리기 정보를 저장할 객체를 생성
            Paint paint = new Paint();
            paint.setColor(Color.RED);
            canvas.drawColor(Color.TRANSPARENT);
            canvas.drawCircle(100, 100, 100, paint);
        }
    }

 

  3) Activity의 onCreate 메소드 앞에서 만든 뷰를 화면에 출력하는 코드를 작성

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_custom);
        setContentView(new MyView(this));
    }

 

6. CustomView의 이벤트 처리

    => View의 클래스이므로 Touch이벤트 처리시 onTouch메소드를 소유하고 있고, View의 터치 이벤트나 클릭이벤트 사용 가능

    => 터치를 처리하는 메소드

        - public boolean onTouchEvent(motionEvent event)

        - return 타입이 boolean인 경우 기본적으로 제공하면 기능의 수행여부를 리턴

        - event는 터치 처리를 위한 부가 정보가 전달

        - getAction()은 MothioEvent의 상수로, 터치의 동작상태 리턴

        - 좌표는 getX(), getY() 리턴

    => 터치를 이용하여 선을 그리고자 하는 경우 터치가 시작되는 시점의 좌표를 출발점으로 하고, 움직임이 있을 때마다 그 좌표를 기억하여 좌표까지 선을 그려주면 됨

        - 펜의 움직임도 터치로 감지

  1) Activity 클래스에 터치정보를 저장할 class를 생성

    => x, y좌표 그리고 그릴 것인지 여부를 지정

    //터치 정보를 저장할 클래스
    class Vertex{
        //점의 좌표를 저장
        float x, y;
        //그리기 여부를 저장
        boolean isDraw;

        //3개의 매개변수를 받아서 초기화 하는 생성자
        public Vertex(float x, float y, boolean isDraw){
            this.x = x;
            this.y = y;
            this.isDraw = isDraw;
        }
    }

 

  2) 클래스에 터치 정보를 저장할 변수를 선언

    //터치 정보를 저장할 list 변수 선언
    ArrayList<Vertex> arrayList;

 

  3) MyView 클래스를 수정(없으면 생성)

    //view 클래스로부터 상속받는 CustomView
    class MyView extends View{
        Paint paint;
        //기본 생성자가 없으므로 생성자를 만들어 상위 클래스의 생성자를 호출
        //생성자의 목적 : 초기화
        //자신의 인스턴스 변수들을 초기화 - 외부로 주입받기도 함
        public MyView(Context context) {
            super(context);
            //paint 생성
            paint = new Paint();
            //색상 설정과 선 두께 설정
            paint.setColor(Color.BLACK);
            paint.setStrokeWidth(3);
            paint.setAntiAlias(true);
                    
        }

        //View가 화면에 표시될 때 호출되는 메소드
        @Override
        public void onDraw(Canvas canvas){
            //arVertext의 내용을 가지고 선을 그리기
            for(int i=0; i<arVertext.size(); i+=1){
                if(arVertext.get(i).isDraw == true){
                    canvas.drawLine(
                            arVertext.get(i-1).x, 
                            arVertext.get(i-1).y,
                            arVertext.get(i).x,
                            arVertext.get(i).y, paint);
                }
            }
        }
        //터치 이벤트 처리를 위한 메소드
        @Override
        public boolean onTouchEvent(MotionEvent event){
            //터치가 처음 시작되는 경우 선을 그릴 필요는 없고 좌표만 저장
            if(event.getAction() == MotionEvent.ACTION_DOWN){
                arVertext.add(new Vertex(event.getX(), event.getY(), false));
                return true;
            }
            //터치가 움직이는 경우 onDraw를 호출하여 현재위치까지 선을 그림
            if(event.getAction() == MotionEvent.ACTION_MOVE){
                arVertext.add(new Vertex(event.getX(), event.getY(), true));
                //전체 화면을 전부 삭제하고 다시 그려달라고 요청
                invalidate();
                return true;
            }
            //기본적으로 제공되는 기능을 사용하지 않음
            return false;
        }
    }

 

  4) Activity.java 파일의 onCreate 메소드 수정

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //새로운 뷰를 화면 전체로 설정
        setContentView(new MyView(this));
        arVertext = new ArrayList<>();

        //새로운 뷰를 현재 화면에 출력
        //setContentView(R.layout.activity_custom);
        //addContentView(new MyView(this), new LinearLayout.LayoutParams(500, 500));
    }

 

**Bitmap

    => bitmap은 2가지 의미로 사용됨

        - 윈도우즈 그림판의 기본확장자인 bmp를 의미

        - 프로그래밍에서는 그림파일의 내용을 메모리에 저장한 것을 bitmap이라고 함

    => 이미지 출력시 ImageView를 이용하게되면 이미지의 확대 및 축소가 가능하지만 해상도에 문제가 생길 수 있음

    => Bitmap의 내용을 조작해서 이미지를 확대나 축소하여 출력 가능

1. Image 출력

    - Canvas.drawBitmap(Bitmap bitmap, x좌표, y좌표, null) : 좌표에 원본 크기 그대로 출력

    - Canvas.drawBitmap(Bitmap bitmap, Rect rect, null) : 확대나 축소하여 출력

    - Canvas.drawBitmap(Bitmap bitmap, Rect rect, Rect rect, null) : 원본이미지에서 첫번째 크기만큼 잘라서 두번째만큼 출력

 

2. Matrix를 이용하여 크기나 위치 및 각도를 조절하여 출력할 수 있음

 

3. Sprite Image

    => 이미지 파일은 기본적으로 보조기억장치에 저장, 이 이미지를 호출하여 화면에 그릴때 보조기억장치에서 로드시 속도가 느려짐

    => 위 문제 해결방법은 리소스에 저장하여 사용하거나 하나의 이미지에 여러개의 이미지를 그리고 잘라서 출력하는 방법 존재

    => 게임의 경우 이미지가 너무 많아 리소스에 저장하는 방법은 사용 불가

  1) 이미지 파일을 drawable 디렉토리에 복사

  2) 실행가능한 Activity 추가(SpliteActivity)

  3) SpliteActivity.java에 CustomView생성

    class MyView extends View {
        public MyView(Context context) {
            super(context);
        }

        @Override
        public void onDraw(Canvas canvas){
            Paint paint = new Paint();
            //리소스로부터 Bitmap을 생성
            Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.img);
            //bitmap에서 앞의 Rect만큼 가져와서 뒤의 Rect 만큼으로 그리기
            canvas.drawBitmap(bitmap,
                    new Rect(0,0,350, 350),
                    new Rect(0,0,700,700),
                    paint);
        }
    }

 

  4) SpliteActivity.java 파일의 onCreate메소드 수정

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        //setContentView(R.layout.activity_splite);
        //setContentView(new MyView(this));
        setContentView(R.layout.activity_splite);
        setContentView(new MyView(this), new LinearLayout.LayoutParams(700, 700));
    }

 

**Intent

    => 컴포넌트를 실행하기 위해서 시스템에 넘기는 정보

    => 컴포넌트 : Activity(화면 출력), Service(백 그라운드 작업), Content Provider(데이터 공유), Broadcast Receiver(알림)

    => 개발자가 작성은 했으나 개발자가 작성하는 자바코드를 이용해 결합없이 수명주기를 관리하는 프레임워크나 라이브러리가 결합(IOC)

        - 안드로이드에서는 Component, Spring에서는 bean이라고 함

    => 제어의 역전이 적용되는 코드가 직접 결합하지 않으므로 모듈간의 결합도가 약해서 의존성이 낮아짐

1. 다른 Activity 호출

    => startActivity(Intent intent)

 

2. Intent의 종류

  1) Explicit Intent(명시적 인텐트)

    => 호출할 대상을 명시(클래스명 명시)

    => 동일한 애플리케이션에 존재하는 컴포넌트를 이용할 때 사용

  2) Implicit Intent(암시적 인텐트)

    => 호출할 대상을 직접 명시하지 않는 인텐트

    => 클래스 이름대신에 별명을 사용하는 인텐트

    => 다른 애플리케이션의 컴포넌트를 이용할 때 사용

    => 안드로이드는 다른 애플리케이션을 실행하는 것 뿐 아니라 다른 애플리케이션의 자원 공유가능

 

3. Intent의 Constructor

    => Intent() : 매개변수가 없는 생성자 - Default Constructor

    => Intent(Intent intent) : 다른 Intent를 매개변수로 받아서 생성 - 복사 생성자 

        -> 복사 생성자를 이용하는 이유는 Clone을 위해서

    => Intent(String action[Uri uri) : 기본 제공되는 애플리케이션의 Activity를 호출할 때 사용하는 생성자

    => Intent(Context context, Class <?> cls) :  두번째 제공되는 컴포넌트 클래스를 이용해 명시적 인탠트를 만드는 생성자(주로 사용)

    => Intent(String action, Uri uri, Context context, Class <?> cls : 기본 제공되는 애플리케이션 Activity에 직접 생성한 Activity 추가

 

4. 기본적인 화면 전환

  1) 하나의 Activity에서 다른 Activity를 호출

    => Intent intent = new Intent(자신의 Activity 참조, 다른 Activity.class);

         startActivity(intent);

  2) 현재 Activity 종료

    => finish();

 

5. 스마트 폰 Application의 화면 관리

    => Stack(LIFO - Last In First Out 구조 : 마지막에 삽입한 데이터가 첫번째에 위치하는 자료구조) 을 이용해서 관리

    => 이전 화면으로 돌아갈 때는 이전 화면을 새로 출력하지 않고 자신을 제거

    => Main에서 Sub 출력시 Sub를 생성해서 출력하지만 Sub에서 Main으로 돌아갈시 Main이 생성되는 것이 아니라 재출력됨

    => onCreate(생성될 때 호출되는 메소드), onResume(다시 활성화 될 때 호출되는 메소드) 

 

6. RootActivity와 SubActivity사이의 화면 전환

  1) 실행 가능한 Activity를 추가 : RootAcitivity

 

  2) 화면 디자인: TextView 1개와 Button 1개 배치

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".RootActivity"
    android:orientation="vertical">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="RootActivity"
        android:id="@+id/lblroot"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="하위 액티비티 호출"
        android:id="@+id/subcall"/>

</LinearLayout>

 

  3) 일반 Activity를 추가 : SubActivity 

 

  4) 화면 디자인: TextView 1개와 Button 1개 배치

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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=".SubActivity"
    android:orientation="vertical">
    
    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="하위 액티비티"
        android:id="@+id/lblsub"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="뒤로"
        android:id="@+id/rootcall"/>
   
</LinearLayout>

 

  5) RootActivity에서 Button을 누르면 SubActivity를 출력하도록 작성

    =>인스턴스 변수 선언

    TextView lblroot;
    Button subcall;

    => onCreate 메소드에 버튼 클릭 이벤트 작성

lblroot = (TextView)findViewById(R.id.lblroot);
        subcall = (Button)findViewById(R.id.subcall);

        subcall.setOnClickListener(
                new Button.OnClickListener(){
            public void onClick(View view){
                //SubActivity를 이용한 Intent 생성
                Intent intent = new Intent(
                        RootActivity.this,
                        SubActivity.class);
                //Activity 호출
                startActivity(intent);
            }
        });

 

  6) SubActivity에서 Button을 누르면 RootActivity를 출력하도록 작성

    => 인스턴스 변수 선언

TextView lblsub;
Button maincall;

 

    => onCreate 메소드에 버튼 클릭 이벤트 작성

lblsub = (TextView)findViewById(R.id.lblsub);
maincall = (Button)findViewById(R.id.rootcall);

maincall.setOnClickListener(new Button.OnClickListener(){
            public void onClick(View view){
                //자신의 Activity 종료
                finish();
            }
});

 

 

7. 데이터 공유

    => 관계형 데이터베이스에서 테이블간의 데이터 공유는 Foreign Key이용

    => 동일한 클래스로부터 만들어진 인스턴스간의 데이터 공유는 Static변수를 이용

    => 서로 다른 클래스로부터 만들어진 인스턴스 간의 데이터 공유

        - 하나의 인스턴스 안에서 다른 인스턴스 생성시 생성자를 이용한 주입이나, setter메소드를 이용한 주입 이용

    => 전혀 관계가 없는 인스턴스간의 데이터 공유 시, 공유 변수 영역을 만들어야 함

        - public class를 만들어서 static 변수, singleton 패턴의 클래스를 만들고 인스턴스 변수를 만들어도 됨

    => 안드로이드는 위의 방법중 공유변수 영역을 만드는 것만 가능

        - 안드로이드의 Component는 인스턴스를 직접 생성하지 않기 때문에 생성자나 setter를 이용하는 방법은 불가

    => 객체 지향 언어에서는 공유 영역을 만드는 것을 금기시

    => 안드로이드에서는 Intent에 데이터 저장 영역을 추가해 줌

        - 데이터 저장 영역을 용어로 표현시 Bundle이라고 함

        - Intent에는 Bundle 자료형으로 Extras가 존재

        - Bundle은 Map처럼 사용

        - 저장시 putExtra(String name, 데이터)

    => 저장 할 수 있는 데이터는 Serializable 인터페이스를 implements 객체만 가능

        - 기본형, String, Date, 자료구조 클래스들은 모두 Serializable인터페이스가 구현되어 있음

        - 개발자가 만드는 데이터 클래스(DTO-VO)를 전송하려는 경우 Serializable 인터페이스를 implements 해야 함

    => 데이터를 읽어내기

        - getIntent 라는 메소드로 자신을 호출한 Intent를 찾아 옴

        - get 자료형 Extra(String name)을 호출하면 됨

        - 없는 자료형인 경우 getSerializableExtra를 호출하고 강제 형 변환을 하여 사용

    => Map의 key와 Value는 모든 자료형이 가능하지만 Key에는 String만 사용 

 

8. startActivityResult(Intent intent, int requestCode)

    => Intent를 화면에 출력하는 메소드

        - requestCode는 호출하는 Intent를 구분하기 위한 식별값

    => 호출당한 Intent에서 resultCode를 만들수 있음

        - setResult(int resultCode, Intent intent)를 호출하면 intent에서 호출된 경우 결과값으로 resultCode를 리턴

    => 호출하는 Activity에서는 추가된 Activity 제거시 아래 메소드가 호출

        - void onActivityResult(int requestCode, int resultCode, Intent intent)

        - 2개의 코드를 이용해서 자신이 호출한 Intent를 알수 있고, 그때 intent의 Extra를 꺼내서 데이터를 확인 가능

    => Main -> Sub로의 데이터 전송은 쉽지만, Sub -> Main로의 데이터 전송은 어려움

 

9. Web Programming에서의 데이터 공유

    => request 객체 : forwarding 할때 데이터 공유

    => session 객체 : 하나의 브라우저 안에서의 데이터 공유

    => application 객체 : 전체 애플리케이션 내에서의 데이터 공유

 

10. 이전 프로젝트의 각 화면에 EditText를 추가하여 EditText에 입력한 내용을 다음 화면에 전송하여 TextView에 출력

    => 보조 입력을 받는 경우 보조화면에 입력한 내용을 메인화면으로 전송해주어야 함

  1) RootActivity 클래스의 레이아웃에 EditText추가

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="RootActivity"
        android:id="@+id/lblroot"/>
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/inputroot"
        android:hint="서브에게 넘기는 데이터"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="하위 액티비티 호출"
        android:id="@+id/subcall"/>

 

  2) SubActivity의 레이아웃에 EditText 추가

    <TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="하위 액티비티"
        android:id="@+id/lblsub"/>
    <EditText
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/inputsub"
        android:hint="메인에게 넘기는 데이터"/>
    <Button
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="뒤로"
        android:id="@+id/maincall"/>

 

  3) Root에서 SubActivity에게 데이터를 넘겨서 출력하기

    => RootActivity의 onCreate 메소드를 수정하여 내용을 전송

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_root);

        lblroot = (TextView)findViewById(R.id.lblroot);
        subcall = (Button)findViewById(R.id.subcall);
        
        //이벤트 핸들러에서 사용하기 위해서 final을 추가
        final EditText inputroot = (EditText)findViewById(R.id.inputroot); 

        subcall.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                //입력한 내용 가져오기
                String content = inputroot.getText().toString();
                        
                //SubActivity를 이용한 Intent 생성
                Intent intent = new Intent(RootActivity.this, SubActivity.class);
                
                //하위 Activity에게 전송할 데이터를 생성
                intent.putExtra("data", content);
                
                //Activity 호출
                startActivity(intent);
            }
        });
    }

 

    => SubActivity의 onCreate 메소드를 수정하여 전송된 내용을 출력

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);

        lblsub = (TextView)findViewById(R.id.lblsub);
        maincall = (Button)findViewById(R.id.maincall);
        
        //자신을 호출한 Intent를 찾아오기
        Intent intent = getIntent();
        //데이터 찾아오기
        String data = intent.getStringExtra("data");
        //데이터 출력
        lblsub.setText(data);
        
        maincall.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                //자신의 Activity 종료
                finish();
            }
        });
    }

 

  4) SubActivity에서 RootActivity에게 데이터 넘기기(전역 공유변수 만들기 - 권장하지 않지만 쉬움)

    => 공유변수를 생성

//모든 곳에서 사용할 수 있는 문자열 변수를 생성
public class ShareData {
    public static String sharedData;
}

 

    => SubActivity에서 finish하기 전에 공유변수에 데이터 삽입

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sub);

        lblsub = (TextView)findViewById(R.id.lblsub);
        maincall = (Button)findViewById(R.id.maincall);

        //자신을 호출한 Intent를 찾아오기
        Intent intent = getIntent();
        //데이터 찾아오기
        String data = intent.getStringExtra("data");
        //데이터 출력
        lblsub.setText(data);

        final EditText inputsub = (EditText)findViewById(R.id.inputsub); 
        maincall.setOnClickListener(new Button.OnClickListener() {
            @Override
            public void onClick(View view) {
                //데이터를 sharedData에 삽입
                ShareData.sharedData = inputsub.getText().toString();
                //자신의 Activity 종료
                finish();
            }
        });
    }

 

    => RootActivity에 onResume을 오버라이딩

    @Override
    public void onResume() {
        super.onResume();
        //공유변수의 내용을 출력
        lblroot.setText(ShareData.sharedData);
    }

 

  5) SubActivity에서 RootActivity에게 데이터 넘기기(안드로이드가 권장하는 방법)

    => RootActivity에서 startActivity 호출 구문을 수정

//Activity 호출
//startActivity(intent);
                
//응답을 받기 위해서 하위 액티비티를 호출할 때
//구분하기 위한 번호와 함께 호출
startActivityForResult(intent, 10);

 

  6) SubActivity에서 finish하기 전에 작성

            @Override
            public void onClick(View view) {
                //데이터를 sharedData에 삽입
                //ShareData.sharedData = inputsub.getText().toString();
                
                //호출한 곳에 데이터를 전송하기 위한 코드
                //requestCode = 10, resultCode = 30
                Intent intent = new Intent();
                intent.putExtra("pass", inputsub.getText().toString());
                setResult(30, intent);
                
                //자신의 Activity 종료
                finish();
            }

 

    => RootActivity 클래스에서 onActivityResult 메소드를 오버라이딩해서 하위 액티비티가 전송한 내용을 출력(onResume은 주석처리)

//    @Override
//    public void onResume() {
//        super.onResume();
//        //공유변수의 내용을 출력
//        lblroot.setText(ShareData.sharedData);
//    }

    //하위 Activity가 소멸될 때 호출되는 메소드
    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent intent) {
        super.onActivityResult(requestCode, resultCode, intent);
        if(requestCode == 10 && resultCode == 30){
            String pass = intent.getStringExtra("pass");
            lblroot.setText(pass);
        }
    }