액티비티를 만들때 보통 Intent를 생성해서 startActivity를 이용해 띄우게 된다.
같은 액티비티가 여러번 띄워지게 되면 중복해서 띄워지게 되는데, 이런 문제는
플래그를 이용하면 해결할 수 있다.
플래그
플래그는 액티비티가 처리되는 방식을 이해해야 이해가 가능하다.
액티비티는 액티비티 매니저라는 객체에 의해 액티비티 스택에서 관리가 된다.
액티비티가 스택에 쌓이고 상위에 있던 액티비티가 사라지면 그 다음 액티비티가 보여지는 방식으로 관리가 된다.
액티비티 매니저가 관리하는 액티비티는 다음 종류와 같다.
- 화면에 띄워지는 액티비티 (현재 실행중인 액티비티)
- 스택에 쌓이는 액티비티 (실행중이였다가 정지되는 액티비티)
동일한 액티비티가 여러 번 생성돼서 스택에 들어가는 것 등을 막는 것이 플래그라는 특성이 있다.
플래그는 대표적으로 다음과 같이 있다.
1. FLAG_ACTIVITY_SINGLE_TOP : 액티비티를 생성할 때, 생성된 액티비티가 있으면 그 액티비티를 사용하는 것.
만일 시스템이 인텐트를 전달하는데, 액티비티가 새로 만들어지지 않는다면 인텐트 객체를 어떻게 전달받을 수 있을까? 보통은 onCreate() 메서드에서 getIntent()를 사용해서 인텐트 객체를 받아온다.
그러나 액티비티가 생성되지않고, 전에 있던 것을 그대로 사용하면 onCreate()메서드가 호출되지 않는다.
이럴 때에는 onNewIntent 메서드를 사용한다. onNewIntent메서드를 오버라이딩하면 액티비티가 새로 생성되지 않아도 인텐트 객체를 전달받을 수 있다.
- public void onNewIntent(Intent intent)
ex.) A-B에서 A를 호출하면 A가 새로 생성되지 않고 원래있던 A가 다시 화면에 띄워진다.
2. FLAG_ACTIVITY_NO_HISTORY : 액티비티를 액티비티 스택에 남기지 않겠다는 특성이다. 보통 Notification에서, 여러번 알림이 와도 화면은 한 번만 보여주면 되므로 여러 번 알람 이벤트가 발생해도 그 화면만 한 번 보여주는 형태로 나타낼 수 있다.
ex.) A-B에서 C를 호출하면 A-C인 형태가 되고, D를 호출하면 A-D인 형태가 된다.
3. FLAG_ACTIVITY_CLEAR_TOP : 이 액티비티 위에 다른 액티비티를 모두 종료시키는 플래그이다. 이 플래그는 홈 화면같은 다른 액티비티보다 우선시 되어야 하는, 항상 하나만 만들어지는 것으로 하고싶을 때 FLAG_ACTIVITY_SINGLE_TOP과같이 설정하면 하나의 객체만 메모리에 존재하고 상위 액티비티들은 모두 종료시킬 수 있다.
ex.) A-B-C에서 A를 다시 호출하면 B와 C가 모두 종료되고 A만 남게된다.
부가 데이터
인텐트에는 번들(Bundle) 객체가 있어서 인텐트 안에 부가 데이터(Extra Data)를 넣어 다른 액티비티에 전달할 수 있다.
번들(Bundle) 객체는 해시테이블과 유사하다.
- putExtra(String name, T value) : name과 value를 파라미터로 넣어서 데이터를 인텐트 객체에 저장한다.
- getExtra(String name, T defaultValue) : name을 파라미터로 넣어서 인텐트 객체에 있는 데이터를 가져온다. 이 때 name에 해당하는 저장되는 데이터가 없다면 defaultValue로 설정한 값을 가져온다.
보통은 기본 자료형(Primitive Data Type)을 넣고 가져오지만, 바이트 배열 혹은 Serializable 객체도 넣고 가져올 수 있다.
번들 객체 안에 넣은 데이터를 부가 데이터라고 하며, 시스템에서는 건드리지 않고 다른 앱의 구성 요소로 전달한다.
만일 전달하고 싶은 데이터가 기본 자료형이 아니라 객체(Object) 자료형이라면 바이트 배열로 변환하거나
Serializable 인터페이스를 구현하는 객체를 만들어서 직렬화한 후 전달해야 한다.
안드로이드에서는 Serializable 인터페이스보다는 Parcelable 인터페이스를 권장한다.
Parcelable 인터페이스는 직렬화했을 때 크기가 작아서 안드로이드 내부 데이터 전달에 유용하게 사용할 수 있다.
이 인터페이스를 사용하려면 두 가지 메서드를 구현해야 한다.
- public abstract int describeContents() : 직렬화하려는 객체의 유형을 구분한다. 그냥 0을 리턴하도록 하면 된다.
- public abstract void writeToParcel(Parcel dest, int flags) : 객체가 가지고 있는 데이터를 Parcel 객체로 만들어준다. Parcel 객체는 Bundle 객체처럼 readOOO(), writeOOO()의 형태를 가지고 있다.
그 후에 CREATOR라는 상수를 만들어야 한다. 이 상수는 Parcel 객체로부터 데이터를 읽어들여서 객체를 생성하는 역할을 한다. 이 객체는 반드시 상수로 정의되고 반드시 static final로 선언이 되어야 한다.
원래는 get&set 메서드가 필요가 없지만, 데이터 바인딩에서 쓸 것이므로 구현해 주었다.
주목할 점은 number에 관련된 메서드인데, 양방향 데이터 바인딩을 할 때 EditText는 String 형만 가능하므로
넘겨주고 받을 때는 String으로 하고 데이터의 저장은 int형으로 한다.
TestModel 객체의 생성자를 두 개를 만든다. 하나는 클래스에 저장할 용도.
다른 하나는 Parcel 객체를 파라미터로 받아서 초기화 하는 용도이다.
Parcel에 bundle을 넣어서 넘겨줄 예정이다.
그리고 Parcelable 객체는 꼭 CREATOR를 상수로 만들어주어야 한다.
Parcel객체로 TestModel 객체를 만들어주는 메서드와
TestModel[] 배열을 만들어주는 메서드가 있다.
Parcel 객체에 쓰는 메서드도 있다.
bundle 객체를 만들어서 값들을 넣고 parcel 객체에 써 주는 역할을 한다.
양방향 데이터 바인딩을 해서 구현을 했다. EditText에 @={A} 이런식으로 지정해 주면 값이 바뀔때마다 객체에서 해당하는 값이 바뀌게 된다.
처음으로 해야할 일은 메인액티비티에서 binding의 TestModel을 초기화 해 주는것이다.
그리고 메뉴 액티비티 실행 버튼의 온클릭 리스너를 설정해준다.
Intent 객체를 생성해서 MenuActivity를 실행할 것임을 파라미터로 명시해준다.
그리고 putExtra 메서드를 통해 name과 Data Binding 해준 TestModel객체를 넘겨준다.
메뉴 액티비티에서는 초기화 메서드에서 우선 Intent 객체를 생성한다.
생성한 Intent 객체의 getExtras() 메서드를 사용해 Bundle 객체를 만든다.
getExtras()는 Bundle 객체를 Return한다.
받아온 Bundle객체의 getParcelable(key값) 메서드를 이용해서 넘겨준 TestModel 객체를 받아온다.
메뉴 액티비티의 데이터 바인딩 TestModel 객체를 초기화 해준다.
사실 이 프로젝트를 하면서 느끼는 거지만, 거진 왠만하면 String 자료형이 낫다고 느껴졌다.
Int 자료형으로 만드니 괜히 위에서 보듯 get & set 메서드도 지저분해지고,
입력하는 도중에도 0이 지워지면 문자열 ""을 정수형으로 변환하는 것이므로 에러가 나면서 앱이 종료됐다.
data 클래스에서는 왠만하면 String형으로 만들기로 하자.
Parcelable 인터페이스를 사용하면 사용자가 정의한 객체의 데이터를 전달할 수 있어서 코드가 단순해지고 재사용성이 높아진다는 장점이 있다. 그러나 담아둘 새로운 객체를 일일이 정의하는 것이 번거롭다는 단점도 있다.
'안드로이드 > 개념' 카테고리의 다른 글
[Android] 액티비티의 생명주기 (0) | 2021.07.31 |
---|---|
[Android] 태스크 관리 (0) | 2021.07.31 |
[Android] 인텐트, Intent (0) | 2021.07.31 |
[Android] 화면 여러개 만들어서 화면 전환하기 - onActivityResult, startActivityForResult Deprecated. registerForActivityResult 사용해보기 (0) | 2021.07.28 |
[Android] 레이아웃 인플레이션 (0) | 2021.07.28 |