Le_Penseur

[안드로이드 스튜디오] Ch12. 다이얼로그 & 인텐트 (Dialog & Intent) 본문

개인(Personal)/안드로이드 (Andorid Studio)

[안드로이드 스튜디오] Ch12. 다이얼로그 & 인텐트 (Dialog & Intent)

LePenseur 2019. 8. 30. 13:03
반응형

2019년 8월30일 (금)

 

 

 

창업의 길로 가기 위한 두번째 걸음, [안드로이드 스튜디오]로 향해보자!

 

*질적으로 많이 부족한 글입니다. 지적 및 조언 환영합니다.

*이 글에선 "안드로이드 스튜디오"를 줄여서 "안스" 라고 표현합니다. 참고 바랍니다.

 

우선, 본인은 학원에서 'JAVA' 기초 수업을 선수강했다. 안드로이드 스튜디오를 배우기 위해선 피할 수 없는 언어이기 때문이다.

(그런데 Ch11까지 배운 현재, JAVA에 대한 공부가 더 필요하다고 느껴진다...)

 


잡담: 블로그 포스팅을 다 맞추면 늘 오후 1시가 넘어가는것같다. 이제 밥먹으러 가야지!


 

이번글에서는 바로 이전에서 배운 다이얼로그(dialog)에 대해 좀더 다양하게 알아보며, 

어플제작에 있어서 '핵심' 중 하나라고 할 수 있는 인텐트(intent)가 무엇인지, 또 그 로직은 무엇인지에 대해 이해하는시간을 갖도록한다.

 

 

 


<차례>

1. MyAlertDialog

2. MyImageDialog

3. MyChangeActivity


 

1. MyAlertDialog
1.1 결과

사진1

설명: 이번에 만들어볼 알림창(Dialog)는 안드로이드의 '뒤로가기' 버튼을 눌렀을때 그냥 뒤로가지는게 아니라, 사진1처럼 알림창을 띄워주어 재차 확인하는 Dialog를 만들어본다. activity_main에는 건들 디자인이 따로 없다. 그말은 멤버변수화 시킬 클래스도 없다는것.

왜냐? '뒤로가기'버튼과 '은 이미 안스에 내장 되어있기 때문이다.

 

(ps. 개인적으로는 이 AlertDialog가 이전에 배운 Dialog보다 훨씬 효율적이고 편리하다고 느꼈다. 그 이유는 이전의 Dialog같은 경우 모델생성, 스타일 생성(물론 옵션이지만), 인플레이터 등 거쳐야할 과정이 많은데,

반면, 이 AlertDialog같은 경우 코드와 로직만 숙지하고 있다면 제한된 프레임안에서 다양한 기능을 넣어줄 수 있고 무엇보다 여러 파일을 이용하지 않아도 되기 때문이다.) 

 

한 java에서 모두 해결하기에 코드가 조금은 어려울수 있다.

집중하자!

**activity_main 코드는 일절 사용하지 않았으므로 첨부하지않았다.

 

1.2 코드 
1.2.1 MainActivity.java
package com.example.myalertdialog;

import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;

import android.content.DialogInterface;
import android.os.Bundle;
import android.view.KeyEvent;

//목표: 뒤로가기 버튼을 누르면 다이얼로그가 호출되도록 할것임.
//XML파일을 건들필요는 없음.
public class MainActivity extends AppCompatActivity {

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

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {
        //키가 눌러졌을 때 실행되는 메소드 (keyCode: 키값, KeyEvent: 이벤트)
        // onKeyDown이라는 메소드를 재정의한것이다. (준비동작 정도)
        // keyCode와 keyEvent 를 처리할 논리형 변수다. ('눌렀을때', '안눌렀을때' 이렇게 두가지니까 당연하다)


        //조건문을 이용한 "키가 눌러 졌을때 x를 할것"의 준비 동작이다. (이런 로직은 외우자)
        if(event.getAction() == KeyEvent.ACTION_DOWN){
        
            //또다른 조건문을 이용한 "뒤로가기 버튼이 눌러 졌을때~"의 로직이다.
            //KEYCODE_BACK은 키값이 "뒤로가기"로 되어있다. 명심하자.
            if(keyCode == KeyEvent.KEYCODE_BACK){

                //alertDialog 객체를 생성하기에 앞서,
                //alertDialog 구성을 먼저 해야하기에 -> alertDialog.Builder을 사용한다.
                final AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this);

                //AlertDialog의 버튼 종류 3가지:
                //(1) PositiveButton - 확인
                //(2) NegativeButton - 취소
                //(3) NeutralButton - 중립 -> 중립이라는 기능은 프로그래머가 어떤 기능을 추가하느냐에 따라 달라질수있다.

                //버튼은 각각 재정의하는것을 권장한다.
                //두개이상 중복되면 마지막으로 등록한 버튼으로 갱신된다.

                dialog.setPositiveButton("ok", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //어플리케이션 종료

                        //엑티비티를 숨기고(hide),멈추고(stop),소멸(destroy)
                        //을 하지만 프로세스 자체는 살아있다.
                        //어플리케이션 실행 중에 액티비티
                        finish();

                        //프로세스를 종료하고 모든 리소스를 반환한다.
                        //System.exit(0);
                        //하지만 어플에서는 사용안함. 왜냐하면 어플에서는 프로세스 종료개념 아니고
                        //멈추고 숨기는 개념이기 때문에.
                        //현재 System.exit()로 앱이 종료 될떄 프로세스들이 완전히
                        //종료하지 못한다는 의견이 분분하다.
                        //그래서
                        android.os.Process.killProcess(android.os.Process.myPid());
                        //를 사용하는 사람들도 있다.


                    }
                });


                dialog.setNegativeButton("cancel", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {
                        //'취소' 기능을 넣어주자.
                        //dialog.dismiss(); -> 없어도 되는 로직이다. 그냥 위에 입력한 Negative 재정의 만으로도 Cancel 기능이 추가된다.
                    }
                });
                dialog.setNeutralButton("now", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialogInterface, int i) {

                    }
                });
                dialog.setTitle("Exit?");
                dialog.show();
            }

        }

        return super.onKeyDown(keyCode, event);
    }
}

 

설명: 위 로직에서의 큰그림을 우선적으로 살펴보자. 

순서는 이러하다:

(0) public boolean onKeyDown(int keyCode, KeyEvent event) 이 로직을 가슴속에 넣어두고 밑의 절차를 살피자.

 

(1) '버튼'이 아닌 '키'가 눌러졌을때 (ACTION_DOWN)의 '동작'에 대한 객체 생성 (동작 = event.Action // 키값 = keyCode)

 

(2) 그 '동작'(ACTION_DOWN)객체안에 '뒤로가기'라는 키값을 입력

 

(3) 이제부터는 '키가 눌러졌을때(ACTION_DOWN)' 에서 '뒤로가기가 눌러졌을때(KEYCODE_BACK, ACTION_DOWN)'로 인식!

 

(4) 잠깐! (KEYCODE_BACK, ACTION_DOWN) 이거 어디서 많이 보지않았는가? 맞다. 위 (int keyCode, KeyEvent event) 와 동일하다.

.

(5) 다음으로는 final AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); 로직을 통해 알림창을 생성한다.

 

(6) 생성된 alertDialog 안에서 각각의 버튼만을 생성해주면 끝이다.

 

 

2. MyImageDialog
2.1 결과

사진2

설명: 이번 알림창(Dialog)은 본인이 직접 디자인하는 알림창이다. 그래서 imageDialog라고 불린다.

이러한 그림 파일로 무언가를 만들기 위해선 역시 xml파일을 만들어줘야한다.

2.2 코드 
2.2.1 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="40dp"
        android:text="Show Dialog"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

</androidx.constraintlayout.widget.ConstraintLayout>

 

설명: 우선 알림창을 어떤 '동작'을 취했을 띄울것이느냐가 관건이기에, 초기화면에는 알림창을 띄울수있는 버튼을 하나 만들자.

 

2.2.2 dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">


        <FrameLayout
            android:id="@+id/frame"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:visibility="gone">

        </FrameLayout>



</LinearLayout>

 

설명: 다음으로는 다이얼로그의 '프레임'을 만들어 주기 위해 layout폴더에서 xml파일을 생성한다.

(ps. framelayout으로 다이얼로그의 프레임을 만들어준다라... 이거 지금 처음 배운느낌인데..

하지만! 상식적으로 생각해봤을때, 이 안에 들어갈 (버튼과 같은) 구성요소들을 인플레이터 해주면 당연히 그 구성요소들은 이 프레임안에서 다시 재구성이 되므로 framelayout 사용에 일리는 있다.) 

 

2.2.3 inner_dialog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/exit_menu"
    android:gravity="center"
    >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="EXIT???"
        android:textSize="30dp"
        />
<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:orientation="horizontal">

    <Button
        android:id="@+id/btn_cancel"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/exit_cancel"/>

    <Button
        android:id="@+id/btn_ok"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="@drawable/exit_ok"/>

</LinearLayout>

</LinearLayout>

 

설명: 방금 위에서 만든 framelayout안에 들어갈 다이얼로그의 내부 모습을 jpg파일들을 통해 구성한다.

 

2.2.4 MainActivity.java
package com.example.myimagedialog;

import androidx.appcompat.app.AppCompatActivity;

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.text.Layout;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.Button;
import android.widget.FrameLayout;

public class MainActivity extends AppCompatActivity {
    private FrameLayout frameLayout;
    private View view;
    private Button btn_cancel,btn_ok,button;
    private Dialog dialog;

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

        button = (Button)findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog = new Dialog(MainActivity.this);

                //dialog 인플레이션을 진행한다.
                dialog.setContentView(R.layout.dialog);

                frameLayout = dialog.findViewById(R.id.frame);
                frameLayout.setVisibility(FrameLayout.VISIBLE);

                //inner_dialog.xml 인플레이션
                LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);


                view = layoutInflater.inflate(R.layout.inner_dialog, frameLayout);

                //버튼 객체화
                btn_cancel = view.findViewById(R.id.btn_cancel);
                btn_ok = view.findViewById(R.id.btn_ok);

                //리스너 설정
                btn_ok.setOnClickListener(click);
                btn_cancel.setOnClickListener(click);

                //타이틀 설정
                dialog.setTitle("My Dialog");

                dialog.show();


            }
        });


    }


    private View.OnClickListener click = new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch (view.getId()) {
                case R.id.btn_cancel:
                    frameLayout.setVisibility(FrameLayout.GONE);
                   dialog.dismiss();
                    break;

                case R.id.btn_ok:
                    finish();
                    break;
            }
        }

    };

    @Override
    public boolean onKeyDown(int keyCode, KeyEvent event) {

        if(event.getAction() == KeyEvent.ACTION_DOWN){
            if(keyCode == KeyEvent.KEYCODE_BACK){
                frameLayout.setVisibility(FrameLayout.VISIBLE);
                dialog.show();
            }
        }

        return true;
    }
}

 

 설명: 로직 자체는 앞에서 말한것과 동일하므로 유심히 살펴보길 바란다.

 

위 코드에서 가장 중요한점은 뭐니뭐니 해도 인플레이터 파트다. 

 

밑의 코드는 위에서 가져온 필자가 중요하다고 생각한 부분이다.

 

 button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                dialog = new Dialog(MainActivity.this);

                //dialog 인플레이션을 진행한다.
                dialog.setContentView(R.layout.dialog);

                frameLayout = dialog.findViewById(R.id.frame);
                frameLayout.setVisibility(FrameLayout.VISIBLE);

                //inner_dialog.xml 인플레이션
                LayoutInflater layoutInflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);


                view = layoutInflater.inflate(R.layout.inner_dialog, frameLayout);

 

설명: 다이얼로그 객체화를 진행후에 framelayout을 기존에 만들어둔 dialog.xml을 인플레이터 해주고, view를 위한 구성요소로는 inner_dialog를 인플레이터 해준것을 볼수있다.

(파일이름을 dialog.xml로 해서 잠시 해맸다. 이름은 좀 특성에 맞게 만들어야겠다.)

 

 

 

1. MyChangeActivity
1.1 결과

 

사진3 - 초기화면
사진4 - NEXT 버튼 클릭시 화면

 

사진5 - LINK 버튼 클릭시 화면

 

설명: 이번 프로젝트는 매우 설레는 (또 가장 기다리던!) 화면 전환 프로젝트다. 화면구성 자체는 심플하다.

java의 로직에 더 신경써야 하는 프로젝트고, 집중해야할 키포인트가 3가지 있다.


- 키포인트 3가지 -

  1.  Intent
  2.  manifests
  3.  startActivity

Q. Intent는 무엇인가?

안드로이드 화면 간의 이동을 위해 사용하는 객체. Bundle 과 비슷하여 화면을 이동하면서 데이터도 가져갈수있고 모든 설정도 취할수있다.

 

Q. manifests는 무엇인가?

어플리케이션 제작의 '총책임자', '총괄자' 정도 되겠다. 이 파일에서 허가를 받지 못하면 activity 구현이 불가능하니 꼭! 염두해두자.

어려운건 절대아니고, 자세한 설명은 밑의 manifests 코드를 참고하자.

 

Q. startActivity는 무엇인가?

위 Intent의 메소드중 하나인데, 이렇게 독립적으로 빼둔이유는 ...... 잘 까먹어서 그렇다. 로직 다 잘~ 써놓고 이 startActivity(intent);를 까먹어서 당황할수있기때문이다. (*늘 마무리가 중요하다)

 

1.2 코드 
1.2.1 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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=".MainActivity">


    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        app:layout_constraintGuide_end="206dp" />

    <androidx.constraintlayout.widget.Guideline
        android:id="@+id/guideline2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="horizontal"
        app:layout_constraintGuide_begin="365dp" />

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginBottom="8dp"
        android:text="Next"
        android:textSize="25dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/guideline"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginBottom="8dp"
        android:text="Link"
        android:textSize="25dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="@+id/guideline"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

 

1.2.2 activity_sub.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="Previous"
        android:textSize="30dp"
        />

</LinearLayout>

 

1.2.3 SubActivity.java
package com.example.mychangeactivity;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

public class SubActivity extends Activity {

    private Button button3;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_sub);

        button3 = (Button)findViewById(R.id.button3);

        //intent? 안드로이드 화면 간의 이동을 위해 사용하는 객체.
        //Bundle 과 비슷하게 화면을 이동하면서 데이터도 가져갈수있고 모든 설정도 취할수있다.

        button3.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //intent 객체 생성 로직
                Intent intent = new Intent(getApplicationContext(),MainActivity.class);

                //intent 이동 로직.
                startActivity(intent);

                //"현재 Activity 가 모두 끝이 났다."라는 로직.
                finish();

            }
        });


    }
}

 

1.2.4 MainActivity.java
package com.example.mychangeactivity;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;

import java.net.URI;

public class MainActivity extends AppCompatActivity {

    private Button button,button2;

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

        button = (Button)findViewById(R.id.button);
        button2 = (Button)findViewById(R.id.button2);

        //리스너 설정
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //버튼이 눌러졌을때 activity 를 이동시키고자 한다.
                //그럼 Intent 객체를 생성해야 한다. 준비하는것이다.
                Intent intent = new Intent();

                intent.setClass(getApplicationContext(),SubActivity.class);

                //이동을 시켜보자!
                startActivity(intent);
                // 여기까지 작성해서 실행한 결과 오류가 나온다. 왜그럴까?
                // 그 이유는 manifests 파일 안에 클래스 등록을 하지 않았기 때문에 Activity 가 인정되지 않았기 때문이다.

            }
        });

        button2.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {

                //웹화면으로 이동하기 위한 준비로, intent 객체를 우선 생성할것이다.
                //그리고 처리할 녀석은 바로 [Action_View: 사용자에게 데이터를 보여준다.]
                Intent intent = new Intent(Intent.ACTION_VIEW);

                //.setData(): 사용자에게 어떤 데이터를 보여줄지 설정하라
                //uri: 어떠한 데이터의 정보나 위치를 가지고있는 데이터
                //Uri: u가 대문자임을 주의하라. 해당 주소로 표현되는 데이터를 가지고있는 클래스를 의미한다.
                //parse: 직역하면 "분석하다" 이지만 프로그래밍에서는 "변환하다" 라는 의미로 쓰인다.
                //링크입력시 "https://" 를 반드시 적어주자.
                intent.setData(Uri.parse("https://www.naver.com"));

                //<필수>실행로직
                startActivity(intent);
            }
        });
    }
}


//.........하지만 이런식의 이전과 다음의 연속되는 로직은 그 데이터가 계속해서 쌓이기때문에 위험할수있다.

 

설명:

 

(1) 전체정리 - button과 button2를 각각 재정의하면서 그안에서 기능을 추가시켜주는것이다.

 

(2) 재정의 파트 - 그냥 뷰로 이동할것인지, 아니면 URI를 통한 인터넷 웹뷰로 이동한것인지에 따라 intent를 객체화하는 과정에서 처리해줄 요소가 다르다.

예를 들어 그냥 button(NEXT)의 경우 '다음페이지'와 '이전페이지'의 연속이므로 그 안에서는 마땅히 처리할 데이터가 없다.

그래서 intent의 객체 안에는 빈공간이다.

반면, 웹뷰로 이동시켜야하는 button2(LINK)의 경우에는 보여줄 '데이터'가 존재하므로, 괄호안에 ACTION_VIEW를 입력한다.

 

(3) 기능 파트 - 빈 다음 뷰로 이동시킬 버튼의 경우에는 setClass를, 링크로 이동시킬 버튼2는 setData 메소드를 이용한 것을 볼수있는데, 사실 이뿐만이 아니라 다양한 메소드가 존재한다. 자세한 설명과 타입은 밑의 안드로이드 가이드를 통해 참고하길바란다.

 

https://developer.android.com/guide/components/intents-filters?hl=ko

 

인텐트 및 인텐트 필터  |  Android Developers

An Intent is a messaging object you can use to request an action from another app component . Although intents facilitate communication between components in several ways, there are three fundamental use cases: An Activity represents a single screen in…

developer.android.com

 

**마지막의 주석을 잘 보자. "(아무런 장치없이) 이전과 다음의 연속되는 로직은 그 데이터가 쌓여 위험할수있다." 라는 말을 유심히 기억하고 다음 포스팅을 참고하길 바란다. 매우 중요한 내용이기 때문이다.

 

1.2.5 AndroidManifests.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.mychangeactivity">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <!--Activity 등록!-->
        <activity android:name=".SubActivity"/>

    </application>

</manifest>

 

설명: <!--Activity 등록! --> 이 부분을 잘 보길바란다. 위 로직까지는 원래 존재하던, 즉 MainActivity의 허가 코드 이고, 밑의 <!--Activity 등록! --> 이 바로 새롭게 만든 Activity의 허가 부분이다.

반응형
Comments