Intent_4대 구성요소&Intent

소정·2023년 2월 23일
0

Android_with_Java

목록 보기
15/33

★★★ Android Application 의 4대 구성요소

[Component] - AndroidManifest.xml(목차)의 <application.> 태그안에 반드시 등록해야만 사용할 수 있는 주요 클래스들

  • Activity / BroadcastReceiver / Service 의 동작을 할때는 무조건 Intent가 실행시키는 것

1. Activity

화면 담당 클래스

2. BroadcastReceiver

디바이스의 특정 상태/ 시그널[문자수신, 배터리부족, 부팅완료, gps 상태정보 등등..]를 OS 에서 방송해주면 이를 수신할 때 사용

3. Service

백그라운드(앱은 실행 중- 화면에서 안보이는)에서 코드를 동작하게 하고 싶을 때 사용. [ex. 뮤직플레이어 앱]

4. Contents Provider

다른앱에게 나의 DB 정보를 제공할 때 사용 [ex. 사진앱 or 연락처앱 ]
기본적으로 앱은 샌드박싱기술로 되어있어서 다른 앱이 접근 불가능 근데 내 데이터베이스를 다른앱이 쓰게하고 싶을때(남이 접근하는게 아니고 내가 열어주는것!) Contents Provider 통해 열어줌
가져다 쓸때 Contents Resolver를 통해 가져옴



[1] 화면전환

핸드폰은 하나의 스크린안에 하나의 창만 보여주도록 막아둠 한번에 하나의 화면만 보여주자고 약속

액티비티간 화면전환 사용방법

  1. java폴더에 new java class 생성 & 호환성을 가진 AppCompatActivity 를 상속

  2. 액티비티가 보여줄 view를 설정하기 위해 자동으로 실행되는 콜백메소드 protected void onCreate()

  3. secondActivity용 레이아웃(xml) 생성

  4. Activity는 4대 컴포넌트중 하나이기 때문에 AndroidManifest에 등록해줘야함!!

    💡 android:exported="true"
    안쓰면 에러, 안드로이드(운영체제)는 화면 단위로 앱이라고 생각함 앱을 시작점을 거쳐가기 싫어해서 단위단위로 본다(화면끼리 서로 참조할 수 없다) -> 이것이 메인함수가 없는 이유
    외부에서 직접 이 화면을 부를것인지 아닌건지 선택하는 부분

  1. 메인화면에서 세컨드화면으로 전환
    안드로이드는 화면을 각각보기 때문에 화면끼리 서로 참조할 수 없다 그래서 대리인(택배기사) 같은 걸 만듦 Intent 얘가 운영체제한테 얘기해서 동작하게 만든다

Main.java

package com.bsj0420.ex42activity;

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {

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

        goBtn = findViewById(R.id.go_btn);

        goBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //두번째 화면(SecondActivity)으로 이동
                
                //SecondActivity를 실핼시켜줄 택배기사 객체 생성
                Intent intent = new Intent(MainActivity.this,SecondActivity.class);
                //Intent(보내는 사람-context, 받는사람-설계도면 );
                
                //택배기사를 통해 새로운 액티비티 실행
                startActivity(intent);
                
                //현재 액티비티를 종료
                finish();
            }
        });

    }
}

앱의 화면은 다른 화면이 열리면 알아서 꺼지는 것이 아니고 현재 화면을 덮고 그 위에 화면이 겹쳐져서 나온다
가려진 화면은 백스택(stack)으로 이동

때문에 현재화면을 다른 화면을 열때 현재 화면을 백스택으로 넣지 않으려면 finish(); 를 쓴다

💡 Stack & queue
stack : FILO
queue : FIFO ex) 키보드



[2] 람다식표기

익명 클래스의 축약표현
리스너 안의 메소드가 한개일때만 쓸 수 있음

🔨 람다식 표기법
thirdBtn.setOnClickListener( view -> {
할 행동
} );
(매개변수 -> {할 행동});

thirdBtn = findViewById(R.id.third_btn);
thirdBtn.setOnClickListener( view -> {
	//서드액티비티를 실행시켜줄 택배기사 객체 생성
    Intent intent = new Intent(this, ThirdActivity.class);
    //람다식으로인해 익명클래스가 사라져서 그냥 this써도 됨!!

    startActivity(intent);

} ); //리스너 안의 메소드가 한개일때만 쓸 수 있음



[3] 바뀐 액티비티 화면에 제목줄 바꾸기

main.java에서 화면 third 화면으로 전환

package com.bsj0420.ex42activity;

import androidx.appcompat.app.AppCompatActivity;

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

public class MainActivity extends AppCompatActivity {

    Button goBtn;
    Button thirdBtn;

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

        //클릭 리스너 짧게 줄여보기
        thirdBtn = findViewById(R.id.third_btn);
        thirdBtn.setOnClickListener( view -> {
            //서드액티비티를 실행시켜줄 택배기사 객체 생성
            Intent intent = new Intent(this, ThirdActivity.class);
            //람다식으로인해 익명클래스가 사라져서 그냥 this써도 됨!!

            startActivity(intent);

        } ); //리스너 안의 메소드가 한개일때만 쓸 수 있음

    }
}

third.java

  1. 제목 왼쪽에 돌아가는 버튼(업버튼) 보이도록
  2. [ <- ]보이도록했지만 움직이지 않음 -> 움직이게 만들기
  3. [업버튼]이 클릭됐을 때 자동으로 발동하는 콜백메소드
  4. 핸드폰 뒤로가기 버튼 능력 상속
package com.bsj0420.ex42activity;

import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

public class ThirdActivity extends AppCompatActivity {

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

        //나도 화면전환시 제목줄 글씨도 내거 보여주기
        getSupportActionBar().setTitle("세번째 화면");
        
        //1. 제목 왼쪽에 돌아가는 버튼(업버튼) 보이도록
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        
        //2. 보이도록했지만 움직이지 않음 -> 움직이게 만들기
        
    }
    
    //3. [업버튼]이 클릭됐을 때 자동으로 발동하는 콜백메소드
    @Override
    public boolean onSupportNavigateUp() {
        super.onBackPressed(); //4. 핸드폰 뒤로가기 버튼 능력 상속

        return super.onSupportNavigateUp();
    }
}



[4] Intent한테 데이터 보내기

  • 액티비티간의 데이터 전달은 Intent밖에 못한다!!!!!★★★★
  • intent는 액스트라통을 가지고 다님 그 안에 A화면에서 보낼 데이터를 들고 B화면으로 감

1. .startActivity()

A화면에서 B화면로 데이터 가져다줘 할때 (A -> B)

main.java

  1. Intent생성
  2. intent.putExtra("이름표/식별자",값 들어간 변수);데이터 들고 가도록함
  3. startActivity(intent); //다른 화면으로 go
package com.bsj0420.ex43activity2;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;

public class MainActivity extends AppCompatActivity {

    EditText etName, etAge;

    Button btn;

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

        etName = findViewById(R.id.et_name);
        etAge = findViewById(R.id.et_age);
        btn = findViewById(R.id.btn);

        btn.setOnClickListener(view -> {
            //세컨드 액티비티로 보낼 데이터
            String name = etName.getText().toString();
            int age = Integer.parseInt(etAge.getText().toString());

            //새러운 액티비티를 실행 시켜줄 택배기사님 생성
            Intent intent = new Intent(this, SecondActivity.class);

            //새로운 액티비티에 보낼 데이터를 택배기사(intent)한테 넣기
            intent.putExtra("name",name); // .putExtra("이름표/식별자",값 들어간 변수);
            intent.putExtra("age",age); // .putExtra("이름표",값 들어간 변수);

            startActivity(intent);
        });

    }
}

second.java

  1. main에서 보낸 인텐트 받기 Intent intent = getIntent();
  2. 전달된 Extra 데이터 있으면 받기
    intent.get자료형Extra("식별자");
package com.bsj0420.ex43activity2;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;

public class SecondActivity extends AppCompatActivity {

    TextView tv;

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

        //이 액티비티를 실행시켜준 Intent(택배기사) 소환
        Intent intent = getIntent();

        //택배기사를 통해 전달된 Extra 데이터 있으면 받기
        String name = intent.getStringExtra("name");
        int age = intent.getIntExtra("age",0); // defaltValue : 혹시 값으면 써라
        //defaltValue 는 기본형 자료형을 없어올때 쓰라고 나옴 , 참조형은 null값으로 알아서 오기때문에 쓸 필요 없음

		//받은 데이터 확인
        //제목줄에 확인해보기
        getSupportActionBar().setTitle(name);

		//TextView에 확이해보기
        tv = findViewById(R.id.tv);
        tv.setText(age + "");

    }
}

2. ActivityResultLauncher<Intent'>

B화면에서 A화면의 데이터 갖다주세요 할때 (B ->A ->B)
(ex. 사진 등록)
.startActivityForResult() 였는데 변경됨 intent가 어디서 갔다왔는지 확인이 불편해서 바뀜
메인액티비티가 전부처리하기 싫어서 하청업체 만듦 : ActivityResultLauncher

사용방법

두번째 화면 글자를 첫번째 화면으로 가져오기

main.java

1. 버튼 클릭 안에서 결과를 받기위한 secontActivity을 띄울 intent 객체 생성

2. 멤버변수로 ActivityResultLauncher<Intent'> 만들기

  • 결과를 받기위한 액티비티를 대신 실행시켜 주기위한 대행사(하청업체) 객체 생성
  • 꼭 멤버변수로 만들어야함 (지역변수로 생성 x)

매개변수 2개
1. 어떤 계약 객체를 만들건지 (현재한 계약은ActivityResultContracts.StartActivityForResult( ))
2. 갔다가 돌아왔을 때 자동으로 실행되는 메소드
(new ActivityResultCallback<ActivityResult'>( ))

  • ActivityResultLauncher가 제대로 값을 가져왔을때와 뒬가기버튼으로 종료됐을때의 상황을 나눔
  1. 클릭버튼 안에서 만든 대행사(ActivityResultLauncher)에게 intent보내기

main.java

위 3번까지의 코드

package com.bsj0420.ex44activitystartactivityforresult;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Button btn;
    TextView tv;

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

        btn = findViewById(R.id.btn);
        tv = findViewById(R.id.tv);


        btn.setOnClickListener(view -> {
            //1.결과를 받기위해 secontActivity실행
            Intent intent = new Intent(this, SecondActivity.class);

            //3.만든 대행사에게 intent 보내기
            resultLauncher.launch(intent);

        });

    }

    //2.
    // 결과를 받기위한 액티비티를 대신 실행시켜 주기위한 대행사(하청업체) 객체 생성 및 등록
    // 꼭 멤버변수로 만들어야함 (지역변수로 생성 x)
    ActivityResultLauncher<Intent> resultLauncher
            = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            //혹시 실행시켰던 액티비티에서 [뒤로가기 버튼]으로 취소했을 수도 있어서 if문으로 예외상황 막아둠
            if(result.getResultCode() == RESULT_OK) {
                //4. 돌아온 인텐트 객체 소환
               

            } else if (result.getResultCode() == RESULT_CANCELED) {
                Toast.makeText(MainActivity.this, "취소 했습니다", Toast.LENGTH_SHORT).show();
            }

        }
    });
    
}

second.java

1. EditText에 입력한 데이터들을 결과값으로 설정
2. 다시 돌아갈 택배기사(intent)에게 결과 데이터를 넣기위해
intent 소환 : getIntent()
3. 인텐트한테 값 줌
.putExtra() 를 통해
4. 값을 제대로 전달해서 간다는 뜻의 시그널을 줌
RESULT_OK 라고 말해줌! (if문에 쓴 시그널 맞추기)
5. 현재 화면을 꺼주기 : finish();
버튼을 눌렀다고 화면이 꺼지지 않으니 내가 꺼줘야함!

package com.bsj0420.ex44activitystartactivityforresult;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.EditText;

public class SecondActivity extends AppCompatActivity {

    EditText etName, etAge;
    Button btn;

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

        etName = findViewById(R.id.et_name);
        etAge = findViewById(R.id.et_age);
        btn = findViewById(R.id.btn);

        btn.setOnClickListener(view -> {
            //EditText에 입력한 데이터들을 결과로 설정
            String name= etName.getText().toString();
            int age = Integer.parseInt(etAge.getText().toString());

            //위에 값을 결과값이라고 설정
            //다시 돌아갈 택배기사(intent)에게 결과 데이터를 넣기
            //즉,액티비티간의 데이터 전달은 Intent밖에 못한다!!!!!★★★★
            Intent intent = getIntent();

            //인텐트한테 값 줌
            intent.putExtra("name", name);
            intent.putExtra("age", age);

            //버튼을 클릭하면 RESULT_OK 라고 말해줌! 시그널 맞추기
            setResult(RESULT_OK, intent);

            //버튼을 눌렀다고 화면이 꺼지지 않으니 내가 꺼줘야함!
            finish();

        });


    }
}

main.java

RESULT_OK 일때 상황 설정을 위해 다시 main.java로 가자
if(result.getResultCode() == RESULT_OK) {}
안에서 second화면의 값 받아오기

  1. 돌아온 인텐트 객체 소환
  2. intent에 넣었던 Extra 데이터 빼오기
  3. 화면에 확인
package com.bsj0420.ex44activitystartactivityforresult;

import androidx.activity.result.ActivityResult;
import androidx.activity.result.ActivityResultCallback;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    Button btn;
    TextView tv;

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

        btn = findViewById(R.id.btn);
        tv = findViewById(R.id.tv);


        btn.setOnClickListener(view -> {
            //1.결과를 받기위해 secontActivity실행
            Intent intent = new Intent(this, SecondActivity.class);

            //3.만든 대행사에게 intent 보내기
            resultLauncher.launch(intent);

        });

    }

    //2.
    // 결과를 받기위한 액티비티를 대신 실행시켜 주기위한 대행사(하청업체) 객체 생성 및 등록
    // 꼭 멤버변수로 만들어야함 (지역변수로 생성 x)
    ActivityResultLauncher<Intent> resultLauncher
            = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), new ActivityResultCallback<ActivityResult>() {
        @Override
        public void onActivityResult(ActivityResult result) {
            //혹시 실행시켰던 액티비티에서 [뒤로가기 버튼]으로 취소했을 수도 있어서 if문으로 예외상황 막아둠
            if(result.getResultCode() == RESULT_OK) {
                //4. 돌아온 인텐트 객체 소환
                Intent intent = result.getData();

                //intent에 넣었던 Extra 데이터 빼오기
                String name = intent.getStringExtra("name");
                int age = intent.getIntExtra("age",0);

                //화면에 확인
                tv.setText(name + " : " + age);

            } else if (result.getResultCode() == RESULT_CANCELED) {
                Toast.makeText(MainActivity.this, "취소 했습니다", Toast.LENGTH_SHORT).show();
            }

        }
    });
    
}

[5] Intent 매개변수 중 class를 모를때 : 묵시적 Intent

인텐트를 실행시키려면 Intent intent = new Intent(this, SecondActivity.class); 매개변수에 class이름이 있어야한다

그러나 클래스이름을 모를 때 쓸수 있는 방법이 있다 이 방법을 쓰기 위해 매니페스트에 액티비티에 필터를 등록해야됨

  • action으로 별칭 지어줌 (액션은 여러개 등록할 수 있음)
  • category도 꼭 등록해야됨 안하면 실행 안됨

(단, API 30버전 이상부터는 묵시적 Intent로 실행하는 엑티비티는 exported가 true여야됨)

쓰는 이유 : 앱이 다르면 명시적으로 실행하는 건 불가능
다른 앱을 쓰기 위해선 묵시적으로 불러야함

사용방법

  1. 매니페스트에 등록
  2. intent 생성 but 매개변수 없이
  3. 매니패스트에 등록한 액션 이름으로 찾아라

main.java

package com.bsj0420.ex45activityenumintent;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

    Button btn;

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

        btn = findViewById(R.id.btn);

        btn.setOnClickListener(view -> {
            //묵시적인텐트로 즉 SecondActivity.calss 명칭없이 실행해보기
            //1. intent 생성 but 매개변수 없이
            Intent intent = new Intent();

            //2. 매니패스트에 등록한 액션 이름으로 찾아라
            intent.setAction("aaaa");

            startActivity(intent);
        });

    }
}

[5-1] 외부 앱 사용하기

매니패스트에 필터로 액션 네임 등록 한 것은 아예 다른 앱화면에서 부를 수 있다

사용방법은 위랑 같음

package com.bsj0420.ex46activity5;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.os.Bundle;
import android.widget.Button;

public class MainActivity extends AppCompatActivity {

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

        findViewById(R.id.btn).setOnClickListener(view -> {
            Intent intent = new Intent();
            intent.setAction("aaaa");

            startActivity(intent);
        });

    }
}

[5-2] 외부 앱 사용하기 SystemItent

공통인텐트
https://developer.android.com/guide/components/intents-common?hl=ko

  • 핸드폰의 고유기능은 액션이름들이 있음
  • 똑같은 액션 이름이 있으면 고르는 화면 알아서 뜬다

main.java

package com.bsj0420.ex47activitysystemintent;

import androidx.appcompat.app.AppCompatActivity;

import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        
        //전화걸기 화면 켜기
        findViewById(R.id.btn_call).setOnClickListener(view -> {
            //버튼 누르면 다이얼화면(전화앱) 실행
            Intent intent = new Intent();
            intent.setAction(Intent.ACTION_DIAL);

            //미리 전화번호까지 전달하기
            intent.setData(Uri.parse("tel:01011341245")); //tel: 키워드 꼭 써야됨

            startActivity(intent);
        });

        findViewById(R.id.btn_sms).setOnClickListener(view -> {
            //sms문자 화면(메세지 앱)
            //Intent intent = new Intent();
            //intent.setAction(Intent.ACTION_SENDTO);

            Intent intent = new Intent(Intent.ACTION_SENDTO); //생성자로 액션 설정 가능
            intent.setData(Uri.parse("smsto:01012341234,01084568456")); //번호 설정
            
            //문자내용 프로그래밍
            intent.putExtra("sms_body","안뇽~"); // sms_body 이 식별자는 정해져 있음
                    
            startActivity(intent);
        });

        findViewById(R.id.btn_iternet).setOnClickListener(view -> {
            //웹페이지 보는 화면 - 크롬 브라우저
            Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://www.naver.com")); //액션과 데이터 한방에 쓸수 있음

            startActivity(intent);
        });

        findViewById(R.id.btn_camera).setOnClickListener(view -> {
            //카메라 앱
            Intent intent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

            startActivity(intent);
        });

    }
}



참고) 버튼 커스텀

버튼 drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="false">

        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="@color/black"/>
            <solid android:color="@color/white"/>
            <corners android:radius="4dp"/>
        </shape>

    </item>

    <item android:state_pressed="true">

        <shape android:shape="rectangle">
            <stroke android:width="1dp" android:color="@color/black"/>
            <solid android:color="#979797"/>
            <corners android:radius="4dp"/>
        </shape>

    </item>

</selector>

토글 drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_checked="false" android:drawable="@drawable/baseline_favorite_border_24"/>
    <item android:state_checked="true" android:drawable="@drawable/baseline_favorite_24"/>

</selector>
profile
보조기억장치

0개의 댓글