04-1 레이아웃 인플레이션 이해하기
- 이제까지 하나의 화면에 대하여 화면을 어떻게 보여줄지 결정하는 XML 레이아웃을 정의했다.
- 구조를 나타내는 XML과 화면의 기능을 담당하는 java 파일을 연결해줘야 한다.
- 화면의 기능을 담당하는 소스 파일에는 AppCompatActivity를 상속하는 MainActivitiy 클래스가 자동으로 만들어진다. - 여기서 R은 프로젝트 창에 보이는 res 폴더를 의미한다.
- 앱이 실행될 때 XML 레이아웃의 내용이 메모리에 객체화되고 객체화된 XML 레이아웃을 소스 파일엥서 사용
- 이렇게 XML 레이아웃의 내용이 메모리에 객체화되는 과정을 인플레이션이라고 한다.
- 메모리에 객체화되지 않은 버튼 객체를 참조하려고 했기 때문에 심각한 오류로 앱 자체를 멈추게 만들었다.
- 오류 코드 : Caused by: java.lang.NullPointerException: Attempt to invoke virtual method
-> 소스 코드에서 레이아웃을 객체화하기 전에 레이아웃의 버튼을 참조했기 때문에 발생하는 문제
- setContentView() 메서드가 매우 중요하다는 것을 알 수 있다.
- 이 메서드는 화면에 표시할 XML 레이아웃을 지정하거나 화면에 표시할 뷰 객체를 지정하는 역할
- 즉 이 메서드로 전달할 수 있는 파라미터는 뷰 객체 또는 XML 레이아웃이 정의된 리소스가 될 수 있다.
- 화면 전체에 보여줄 XML 레이아웃이 아니라 별도의 XML 레이아웃 파일로 만든 부분 레이아웃을 소스 파일에 ㅗ딩하여 보여줄 수 었을까? OK
- 부분 화면도 별도의 XML 레이아웃 파일에 정의한 후 불러와 보여줄 수 있다. -> 인플레이터 사용해야함
- 안드로이드는 이를 위햇 시스템 서비스로 LayoutInflater라는 클래스를 제공함
- LayoutInflater 클래스는 시스템 서비스로 제공하는 클래스이므로 다음 getSystemServie() 메서드를 이용하여 LayoutInflater 객체를 참조한 후 사용
- 앱이 실행되었을 때 MainActivity 화면이 아니라 프로젝트에 새로 추가한 00 화면이 나타나도록 매니페스트 파일을 수정해야 한다.
- app/manifests 폴더에 안에 있는 AndroidManifest.xml 파일에서 <activity> 태그 수정
04-2 여러 화면 만들고 화면 간 전환하기
- 대부분 앱은 여러 화면으로 구성되어 있고 호면을 전환하며 실행
- 화면은 액티비티로 구현 즉, 화면을 필요에 따라 띄우거나 닫는 과정은 액티비티를 전환하는 것과 같다.
- 앱을 만들어 단말에 설치했을 때 안드로이드 시스템이 이 요소에 대한 정보를 요구하지 않기 때문ㅇ
- 이 정보는 어디 들어있을까? 프로젝트 만들면 자동으로 만들어지는 Manifest.xml 파일에
- 액티비티를 소스 코드에서 띄울 때는 startActivity()메서드를 사용하면 된다
▼ MainActivity.java코드
package com.ogrg.sampleintent;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
public class MainActivity extends AppCompatActivity {
public static final int REQUEST_CODE_MENU = 101;
TextView textView = findViewById(R.id.textView2);
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE_MENU){
Toast.makeText(getApplicationContext(),
"onActivitiyResult 메서드 호출됨. 요청 코드:" + requestCode+
", 결과 모드 : "+requestCode, Toast.LENGTH_LONG).show();
if(resultCode == RESULT_OK){
String name = data.getStringExtra("name");
Toast.makeText(getApplicationContext(), "응답으로 전달된 name : " + name,
Toast.LENGTH_LONG).show();
}
}
}
@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 v){
Intent intent = new Intent(getApplicationContext(), MenuActivity.class);
startActivityForResult(intent, REQUEST_CODE_MENU);
}
});
}
}
- onActivitiyResult() 메서드는 새로 띄웠던 메뉴 액티비티가 응답을 보내면 그 응답을 처리하는 역할
- 메서드의 첫 번째 파라미터는 액티비티를 띄울 때 전달했던 요청 코드
- 메서드의 두 번재 파라미터는 새 액티비티로부터 전달된 응답 코드(새 액티비티에서 처리한 결과가 정상인지 아닌지 구분)
- 메서드의 세 번째 파라미터는 새 액티비티로부터 전달 받은 인텐트
- 인텐트 객체에 데이터를 넣는 방법은 키와 데이터값을 쌍으로 넣어야 한다.
04-3 인텐트 살펴보기
■ 인텐트의 역할과 사용 방식
- 인텐트를 만든 후 startActivity()나 startActivityForResult() 메서드를 호출하면서 전달하는 방법으로 인텐트를 시스템에 전달
- 그 시스템은 그 인텐트 안에 들어 있는 명령을 확인하고 만들어진 액티비티 또는 이미 단말에 설치되어 있는 다른 앱들의 액티비티를 띄운 것
- 이렇게 인텐트를 앱 구성 요소가 해야 할 일을 지정
startActivity() | 액티비티를 띄울 때 |
startService() | 서비스를 시작할 때 |
broadcastIntent() | 인턴트 객체를 브로드캐스팅 방식으로 전송할 때 |
- 인텐트 기본 구성 요소는 Action(수행할 기능)과 Data(액션이 수행될 대상의 데이터) 이다.
- 인텐트에 포함되어 있는 데이터는 그 포맷이 어떤 것인가를 시스템이 확인한 후 적절한 액티비티를 자동으로 찾아 띄워주기도 한다. 만약 http처럼 특정 포맷을 사용하면 그 포맷은 등록된 MIME 타입으로 구분
- MIME 타입은 일반적을 웹 서버에서 사용하는 MIME 타입과 같다.
- 인텐트 전달 매커니즘도 이렇게 MIME 타입을 구분한 후 설치된 앱들 중에 적절한 것을 찾아 액티비티를 띄워주는 것
- 인텐트의 생성자들을 보면 인텐트 객체는 액션과 데이터를 인수로 하여 만들 수도 있지만 다른 인텐트나 클래스 객체를 인수로 하여 만들기도 함
- 인텐트에 클래스 객체나 컴포넌트 이름을 지정하여 호출할 대상을 확실히 할 수 있는 경우 'Explict Intent'이라고 하고, 액션과 데이터를 지정하긴 했지만 호출할 대상이 달라질 수 있는 경우에는 'Implict Intent'
- 그 밖의 다른 속성들이 있음
범주(Category) |
예) CATEGORY_LAUNCHER는 최상위 앱으로 설치된 앱들의 목록을 보여주는 애플리케이션 런처 하면에 이 앱을 보여주여 한다는 것을 의미 |
타입(Type) | 인텐트에 들어가는 데이터의 MIME 타입을 명시적으로 지정, |
컴포넌트 | 인텐트에 사용될 컴포넌트 클래스 이름을 명시적으로 지정 |
부가 데이터 |
인텐트에 추가적인 정보를 넣을 수 있도록 번들(Bundle) 객체를 담고 있음 |
04-4 플래그와 부가 데이터 사용하기
- 액티비티로 만든 화면이 한 번 메모리에 만들어졌는데도 계속 startActivity()나 startActivityForResult() 메서드를 여러 번 호출하며 동일한 액티비티가 메모리에 여러 개 만들어질 것 why? 시스템이 인텐트 별로 새 액티비티를 띄워주기 때문에
■ 플래그
- 중복된 액티비티를 띄우지 않기 위해
- 액티비티가 처리되는 방식 : 액티비티는 액티비티 매니저(Activitiy Manager)라는 객체에 의해 '액티비티 스택(Activity Stack)' 이라는 것으로 관리
- 대표적인 플래그
FLAG_ACTIVITY_SINGLE_TOP |
- 액티비티를 생성할 때 이미 생성된 액티비티가 있으면 그 액티비티를 그대로 사용하라는 플래그 - 기존에 만든 동일한 액티비티를 그대로 사용 ->화면에 보이는 액티비티가 새로 만들어지지 않고 기존에 있는 것이 보인다면 시스템에서 전달하는 인텐트 객체는 어떻게 전달받을 수 있을까? - 새로운 액티비티를 띄워주는 액티비티를 부모 액티비티라고 부른다면, 부모 액티비티로부터 전달하는 인텐트는 새로 만들어진 인텐트의 onCreate() 메서드 안에서 getIntent() 메서드로 참조할 수 있음 - 그런데 액티비티가 새로 만들어지지 않고 재사용된다면 액티비티의 onCreate() 메서드가 호출되지 않음 - 이 경우에는 새로 띄워지는 액티비티에서 인텐트를 전달 받아 처리하는 방법이 따로 있어야 한다. -> onNewIntent() 메서드 - onNewIntent 메서드를 재정의하면 액티비티가 새로 만들어지지 않았을 때 인텐트의 객체만 전달 받을 수 있다. |
FLAG_ACTIVITY_NO_HISTORY |
- 이 플래그로 설정하면 처음 이후에 실행된 액티비티는 액티비티 스택에 추가되지 않는다.
예) 알림 이벤트 |
FLAG_ACTIVITY_CLEAR_TOP |
- 액티비티 위헤 있는 다른 액티비티를 모두 종료 예) 홈 페이지 |
■ 부가 데이터
- 한 액티비티에서 다른 액티비티를 띄울 때 데이터를 전달해야 하는 경우
- 별도의 클래스를 만든 다음 그 안에 클래스 변수(static 키워드를 이용해 선언한 변수)를 만들어 두 개의 화면에서 도무 그 변수를 참조하게 하는 방법
- 안드로이드는 다른 앱에서 여러분이 만든 화면을 띄울 수도 있기 때문에 변수를 공유하는 방식으로 데이터를 전달하는 것이 불가능할 수도 있다.
- 그래서 기본적으로 액티비티를 띄울 때 전달되는 인테트 안에 부가 데이터(Extra Data)를 넣어 전달하는 방법을 권장
- 인텐트 안에는 번들(Buddle) 객체가 들어 있는데, 번들 객체는 해시테이블과 유사해서 putExtra()와 get000Extra() 메서드로 데이터를 넣거나 빼낼 수 있다. (000은 기본 자료형의 이름, 배열이나 Serializable 객체도 넣었다 뺄 수 있음)
▶ SampleParcelable 프로젝트
- SimpleData 클래스 만들기
- 이 클래스에 Parcelable 인터페이스 구현하기
▼SimpleData.java 코드
package com.ogrg.sampleparcelable;
import android.os.Parcel;
import android.os.Parcelable;
public class SimpleData implements Parcelable {
int number;
String message;
public SimpleData(int num, String msg){
number = num;
message = msg;
}
public SimpleData(Parcel src){
number = src.readInt();
message = src.readString();
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public SimpleData createFromParcel(Parcel in){
return new SimpleData(in);
}
@Override
public Object[] newArray(int size) {
return new Object[0];
}
};
public int describeContents(){
return 0;
}
public void writeToParcel(Parcel dest, int flags){
dest.writeInt(number);
dest.writeString(message);
}
}
- 클래스 안에 정의된 인스턴스 변수는 정수, 문자열 두 개이다.
- writeToParcel() 메서드는 이 SimpleData 객체 안에 있는 데이터를 Parcel 객체로 만드는 역할을 한다.
- CREATOR 객체는 상수로 정의되어 있으며 새로운 객체가 만들어지는 코드가 들어가므로 new SimpleData()와 같이 SimpleData 객체를 만드는 부분을 볼 수 있다.
- 메인 액티비티를 띄우기 위해 만드는 인텐트 객체에는 SimpleData 객체를 부가 데이터로 넣어 전달할 것
- parcelable 인터페이스를 사용하면 객체를 정의해 데이터를 전달할 수 있으므로 코드가 좀 더 단순해짐, 재사용도 높아지고
04-5 태스크 관리 이해하기
- 앱을 실행하면 그 앱은 하나의 프로세스 위에서 동작
- 내가 만든 앱에서 안드로이드의 기본 앱 중 하나인 전화 앱의 화면을 어떻게 띄울까?
앱에서 시스템으로 인텐트를 보내는 방법으로 전화 앱을 띄울 수 있다.
즉 프로세스를 띄울려면 시스템의 도움이 필요하다.
- 프로세스는 독립적인 상자와 같아서 프로세스 간의 정보 공유는 어렵다. 그래서 task라는 것이 만들어짐
- 즉 태스크를 이용하면 프로세스처럼 독립적인 실행 단위와 상관없이 어떤 화면들이 같이 동작해야 하는지 흐름을 관리할 수 있다.
■ 프로세스와 테스크
▶ SampleTask 프로젝트
- 버튼을 클릭했을 때 onClick 메서드가 호출되나
- 화면을 띄울 때는 Intent 객체의 startActivity 메서드를 사용한다
=> 버튼을 누를 때마다 첫 화면이 반복해서 뜨게 된다. 여러 화면이 중첩할 수 있다
▼Manifests.xml
<activity android:name=".MainActivity" android:launchMode="singleTop">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
- 액티비티 태그 안에 launchMode를 singleTop로 설정하면 테스크의 가장 위쪽에 있는 액티비티는 더 이상 새로 생기지 않는다.
04-6 액티비티의 수명주기와 SharedPreferences 이해하기
- 안드로이드 시스템은 실행되는 앱의 상태를 직접 관리
- 액티비티는 처음 실행될 때 메모리에 만들어지는 과정부터 시작해서 실행과 중지, 그리고 메모리에서 해제되는 여러 과정의 상태 정보를 갖고 있으며, 이런 상태 정보는 시스템이 관리하면서 각각의 상태에 해당하는 메서드를 자동으로 호출하게 됨
실행(Running) | 화면상에 액티비티가 보이면서 실행되어 있는 상태, 액티비티 스택의 최상위에 잇으며 포커스를 가지고 있음 |
일시 정지(Paused) | 사용자에게 보이지만 다른 액티비티가 위에 있어 포커스를 받지 못하는 상태, 대화상자가 위에 있어 일부가 가려진 경우에 해당함 |
중지(Stopped) | 다른 액티비티에 의해 완전히 가려져 보이지 않는 상태 |
- 액티비티의 상태 정보가 변화하는 것을 Life Cycle 또는 생명주기라고 함
- 사용자가 게임하다가 중간에 전화를 받고 다시 돌아올 때 사용되는 액티비티의 생명주기 메서드는 onPause()와 onResume()이다.
- 액티비티를 중지시키기 전에 onSaveInstanceState() 메서드를 이용해 데이터를 임시로 저장할 수 있다.
▶ SampleLifeCycle 프로젝트
- 버튼을 눌렀을 때 메뉴 엑티비티를 띄우면 메인 액티비티는 액티비티 스택에 들어가므로 수명주기의 상태 변화가 들어간다.
- 토스트 메세지는 여러 번 실행 될 경우 이전 메시지가 보이지 않을 수도 있다. 따라서 디버깅 목적으로 사용할 때는 Logcat 창에 메시지를 출력하는 것이 좋다.
- Log cat 창에서 특정 단어 검색 가능, 필터에 사용되는 글자를 태그라고 부른다.
- 시스템에서 자동으로 호출하는 메서드는 '콜백 메서드'
- 액티비티 상태 변화 순서
onCreate → onStart → onResume →onPause → onStop → onDestroy
- 화면이 전환 될 때는 onDestory() 메서드가 호출되지 않음.
- 앱 안에는 간단한 데이터를 저장하거나 복원할 때는 SharedPreferences를 사용할 수 있음
- 앱 내부에 파일을 하나 만드는데 이 파일 안에서 데이터를 저장하거나 읽어올 수 있게 한다.
- 개발자는 실제로 파일을 하나 만들 필요없이 SharedPreferenced 의 저장, 복원 메서드를 호출하면 된다.
<코드 결과 안나옴>
도전07
도전08
'컴퓨터 공학 > Android' 카테고리의 다른 글
[Do it 개정6판_안드로이드 스튜디오]둘째마당_10 서버에 데이터 요청하고 응답받기 (0) | 2019.12.03 |
---|---|
[Do it 개정6판_안드로이드 스튜디오]둘째마당_05 프래그먼트 이해하기 (0) | 2019.12.01 |
[Do it 개정6판_안드로이드 스튜디오]둘째마당_03 기본 위젯과 드로어블 사용하기 (0) | 2019.11.28 |
[Do it 개정6판_안드로이드 스튜디오]둘째마당_02 레이아웃 익히기 (0) | 2019.11.27 |
[Do it 개정6판_안드로이드 스튜디오]둘째마당_01 안드로이드 스튜디오 설치 (0) | 2019.11.27 |
댓글