출처 : Do it! 안드로이드 앱 프로그래밍 / 정재곤
액티비티로 만든 화면이 한 번 메모리에 만들어졌는데도 계속 startActivity()나 startActivityForResult() 메소드를 여러 번 호출하면 동일한 액티비티가 메모리에 여러 개 만들어질 것이다. 중복된 액티비티를 띄우지 않으려면 어떻게 해야 할까? 이런 문제는 플래그(Flag)를 사용하면 조정할 수 있다.
플래그
플래그를 이해하려면 액티비티가 처리되는 방식을 이해해야 한다. 액티비티는 액티비티 매니저(ActivityManager)라는 객체에 의해 액티비티 스택(Activity Stack)이라는 것으로 관리된다. 다음 그림은 액티비티 스택의 처리 과정을 나타낸 것이다.
이렇게 일반적인 스택 구조를 이용해 액티비티가 관리되기는 하지만 만약 동일한 액티비티를 여러 번 실행한다면 동일한 액티비티가 여러 개 스택에 들어가게 되고 동시에 데이터를 여러 번 접근하는 문제가 발생할 수 있다. 대표적인 플래그들은 다음과 같다.
- FLAG_ACTIVITY_SINGLE_TOP : 액티비티를 생성할 때 이미 생성된 액티비티가 있으면 그 액티비티를 그대로 사용한다.
- FLAG_ACTIVITY_NO_HISTORY : 처음 이후에 실행된 액티비티는 액티비티 스택에 추가되지 않는다.
- FLAG_ACTIVITY_CLEAR_TOP : 액티비티 위에 있는 다른 액티비티를 모두 종료시키게 된다.
출처 : http://egloos.zum.com/surprisen/v/2511530
부가 데이터
한 액티비티에서 다른 액티비티를 띄울 때 데이터를 전달해야 하는 경우도 있다. 이럴 때는 액티비티를 띄울 때 전달되는 인텐트 안에 부가 데이터(Extra data)를 넣어 전달하는 방법을 사용한다.
인텐트 안에는 번들 객체가 있는데, 번들 객체는 해시테이블과 유사해서 putExtra()와 getXXXExtra() 메소드로 데이터를 넣거나 빼낼 수 있다. 기본적으로는 기본 자료형을 넣었다 뺄 수 잇지만 바이트 배열이나 Serializable 객체도 넣었다 뺄 수 있다.
번들 안에 문자열이나 정수와 같은 부가 데이터를 넣을 때는 키와 값을 쌍으로 만들어 넣는다.
만약 전달하고 싶은 데이터가 기본 자료형이 아니라 객체 자료형인 경우에는 객체 자체를 전달할 수는 없다. 객체 데이터는 바이트 배열로 변환하거나 Serializable 인터페이스를 구현하는 객체를 만들어 직렬화한 다음 전달해야 한다. 그러나 안드로이드는 객체를 전달할 때 Parcelable 인터페이스를 권장한다. Parcelable 인터페이스는 Serializable과 유사하지만 직렬화했을 때 크기가 작아 안드로이드 내부의 데이터 전달에 자주 사용된다. 단, 다음의 두 가지 메소드를 모두 구현해야 한다.
public abstract int describeContents()
public abstract void writeToParcel(Parcel dest, int flags)
describeContents() 메소드는 직렬화하려는 객체의 유형을 구분할 때 사용한다. writeToParcel() 메소드는 객체가 가지고 있는 데이터를 Parcel 객체로 만들어주는 역할을 한다.
위의 두 가지 메소드를 모두 구현한 다음에는 CREATOR라는 상수를 만들어야 하는데 이 상수는 Parcel 객체로부터 데이터를 읽어 들여 객체를 생성하는 역할을 한다. 이 객체는 반드시 static final로 선언되어야 한다.
> Parcelable 사용한 객체 데이터 전달하기 예제
우선 전달할 액티비티인 MenuActivity와 activity_menu를 생성한다.
Data.java
package com.example.project00_java;
import android.os.Parcel;
import android.os.Parcelable;
public class Data implements Parcelable {
int num;
String msg;
public Data(int num, String msg) {
this.num = num;
this.msg = msg;
}
public Data(Parcel src) {
num = src.readInt();
msg = src.readString();
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public Data createFromParcel(Parcel in) {
return new Data(in);
}
public Data[] newArray(int size) {
return new Data[size];
}
};
public int describeContents() {
return 0;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(num);
dest.writeString(msg);
}
}
MainActivity
package com.example.project00_java;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
public static final int REQUEST_CODE_MENU = 101;
public static final String KEY_STRING_DATA = "data";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
Button button = findViewById(R.id.button6);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent(getApplicationContext(), MenuActivity.class);
Data data = new Data(100, "hello");
intent.putExtra(KEY_STRING_DATA, data);
startActivityForResult(intent, REQUEST_CODE_MENU);
}
});
}
}
MenuActivity
package com.example.project00_java;
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;
public class MenuActivity extends AppCompatActivity {
TextView textView;
public static final String KEY_SIMPLE_DATA = "data";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_menu);
textView = findViewById(R.id.textView);
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent intent = new Intent();
intent.putExtra("name", "mike");
setResult(RESULT_OK, intent);
finish();
}
});
Intent intent = getIntent();
processIntent(intent);
}
private void processIntent(Intent intent) {
if (intent != null) {
Bundle bundle = intent.getExtras();
Data data = bundle.getParcelable(KEY_SIMPLE_DATA);
if (data != null) {
textView.setText("전달 받은 데이터\nNumber : " + data.num
+ "\nMessage : " + data.msg);
}
}
}
}
activity_main
<?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" >
<Button
android:id="@+id/button6"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
activity_menu
<?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">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
'Android' 카테고리의 다른 글
[Android] 안드로이드 정리 (10) - 프래그먼트 (Fragment) (0) | 2020.03.12 |
---|---|
[Android] 안드로이드 정리 (9) - 액티비티의 생명주기 (0) | 2020.03.12 |
[Android] 안드로이드 정리 (7) - 인텐트(Intent) (0) | 2020.03.12 |
[Android] 안드로이드 정리 (6) - 여러 화면 만들고 화면 간 전환하기 (0) | 2020.03.12 |
[Android] 안드로이드 정리 (5) - 레이아웃 인플레이션 이해하기 (0) | 2020.03.12 |