예를 들어서 어떤 화면에서 값을 입력받아 버튼을 누르면 다른 화면으로 이동해서 컨텐츠를 보여줘야 하는 경우가 있습니다.
Fragment를 사용하지 않고 아예 다른 화면으로 넘어가서 이전 화면에서 입력받은 정보를 불러와 처리해야 한다면 가장 기본적으로 DB에 입력받은 데이터를 저장하고 다른 화면에서 DB에 들어간 정보를 다시 불러와서 처리해주는 방식을 떠올릴 수 있을 것입니다.
그러나 간단한 숫자나 문자열 등을 DB에 저장해서 다시 이를 불러오는 작업은 그렇게 효율적이라는 생각은 들지 않는 것 같습니다.
Spring에서 Model
이라는 객체를 사용하여 addAttribute
로 전달해줄 값을 설정해주고 이를 불러올 곳에서 getAttribute
로 값을 불러와 사용했습니다.
마찬가지로 안드로이드에서는 getSharedPreferences
를 사용할 수 있습니다. 그러나 getSharedPreferences
는 기본 자료형의 형태만 전달할 수 있다는 단점이 있습니다.
다시 말해서 object
형태는 전달해 줄 수 없다는 뜻인데, object
를 전달해주기 위해서 Parcelable
를 사용할 수 있습니다.
또는 값을 서로 전달하여 받는 방식 이외에 싱글턴이라는 공동 공유공간을 만들어서 값을 끌어올 수도 있습니다.
그러면 지금부터 각각을 어떻게 사용할 수 있는지 살펴보겠습니다.
getSharedPreferences
장면 전환을 위해 레이아웃을 두개 만들 것입니다. 우선 메인 레이아웃을 다음과 같이 구성하였습니다
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="496dp"
android:layout_height="54dp"
android:inputType="textPersonName"
android:ems="10"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.158"/>
<Button
android:id="@+id/write"
android:text="Preference 쓰기"
android:layout_width="495dp"
android:layout_height="54dp"
app:layout_constraintTop_toBottomOf="@+id/editText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintVertical_bias="0.098"/>
<Button
android:id="@+id/move"
android:text="다음 화면으로 이동"
android:layout_width="495dp"
android:layout_height="54dp"
app:layout_constraintTop_toBottomOf="@+id/editText"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.504"
app:layout_constraintVertical_bias="0.242"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="@+id/textView"
android:text="TextView"
android:layout_width="395dp"
android:layout_height="127dp"
android:textSize="30dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.283"/>
<Button
android:id="@+id/read"
android:text="Preference 읽기"
android:layout_width="431dp"
android:layout_height="80dp"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintVertical_bias="0.255"/>
</androidx.constraintlayout.widget.ConstraintLayout>
MainActivity
레이아웃을 구성하였으니 이제 버튼을 클릭했을 때 다음 화면으로 넘겨줄 정보를 입력받고 다음화면으로 넘겨서 그 정보를 가져와 보겠습니다.
메인 화면에서는 두개의 버튼을 준비했습니다. 넘겨줄 정보를 저장해주고 다음 페이지로 넘기는 작업을 해보겠습니다.
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val write = findViewById<Button>(R.id.write)
val move = findViewById<Button>(R.id.move)
val edit = findViewById<EditText>(R.id.editText)
우선 컴포넌트들을 아이디 값으로 불러옵니다.
write.setOnClickListener {
val pref = getSharedPreferences("pref", MODE_PRIVATE)
val editor = pref.edit() // 초기화
editor.putString("myData", edit.text.toString())
editor.apply()
edit.setText("")
}
변수 write
로 지정된 버튼을 클릭했을 때 이벤트 리스너입니다.
pref
변수에는 getSharedPreferences
를 넣어주었습니다. 이 넘겨줄 정보의 이름이 "pref"
이며 MODE_PRIVATE
로 지정하여 새로운 값을 넣어줄 때마다 덮어쓰기 하게 해주었습니다.
editor
변수에는 pref
를 초기화 하기 위한 것이 들어있습니다.
putString
을 통해 "myData"
라는 이름으로 사용자 입력 컴포넌트에 있는 값을 문자열로 넣어줍니다.
apply()
를 통해 적용해주고 작업이 완료되면 빈칸으로 세팅합니다.
move.setOnClickListener {
val i = Intent(this, SecondActivity::class.java)
startActivity(i)
}
}
}
다음 페이지로 이동하는 버튼을 눌렀을 때 SecondActivity
로 넘겨줍니다.
Activity는 앱 안의 단일 화면을 나타냅니다. Activity의 새 인스턴스를 시작하려면 Intent를 startActivity()로 전달하면 됩니다. Intent는 시작할 액티비티를 설명하고 모든 필수 데이터를 담습니다.
- 안드로이드 개발자 문서
다시 말해서 Intent
를 통해 이 페이지에서 다른 페이지로 넘겨줄 것임을 명시해주고 startActivity
로 전달하여 다음 페이지로 이동하게 해주었습니다.
Parcelable
Parcelable
을 살펴보기 위해 메인 레이아웃과 서브 레이아웃을 만들어주겠습니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editName"
android:layout_width="392dp"
android:layout_height="55dp"
android:inputType="textPersonName"
android:ems="10"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.193"
/>
<EditText
android:id="@+id/editCount"
android:layout_width="392dp"
android:layout_height="55dp"
android:inputType="textPersonName"
android:ems="10"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.279"
/>
<EditText
android:id="@+id/editLevel"
android:layout_width="392dp"
android:layout_height="55dp"
android:inputType="textPersonName"
android:ems="10"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.369"
/>
<Button
android:id="@+id/move"
android:text="Button"
android:layout_width="393dp"
android:layout_height="53dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintVertical_bias="0.525"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.497"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SecondActivity">
<TextView
android:id="@+id/textView"
android:text="TextView"
android:textSize="30dp"
android:layout_width="413dp"
android:layout_height="130dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.502"
app:layout_constraintVertical_bias="0.187"/>
<Button
android:id="@+id/read"
android:text="읽기"
android:layout_width="271dp"
android:layout_height="57dp"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.501"
app:layout_constraintVertical_bias="0.239"/>
</androidx.constraintlayout.widget.ConstraintLayout>
object
전달 연습을 위해 DTO를 하나 만들어주겠습니다.
package dto
import android.os.Parcel
import android.os.Parcelable
class Student(var name: String?, var count:Int, var level: String?) : Parcelable {
constructor(parcel: Parcel):this(parcel.readString(), parcel.readInt(), parcel.readString()) {}
override fun writeToParcel(parcel: Parcel?, p1: Int) {
parcel?.writeString(name)
parcel?.writeInt(count)
parcel?.writeString(level)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Student> {
override fun createFromParcel(parcel: Parcel): Student {
return Student(parcel)
}
override fun newArray(size: Int): Array<Student?> {
return arrayOfNulls(size)
}
}
}
우리는 장면 전환 시 객체를 전달해줄 것이기 때문에 전달해줄 형태의 객체는 Parcelable
을 상속받아야 합니다.
Parcelable
을 상속받았기 때문에 writeToParcel
과 describeContents
의 오버라이드가 필요합니다.
또한 companion object
의 형태로 CREATOR
가 구현되어야 합니다.
역시 버튼 클릭시 이벤트를 발생시켜보겠습니다.
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
import dto.Student
// preference는 기본자료형만 보낼 수 있어서...
// intent를 사용하면 객체를 전달해줄 수 있다!
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val editName = findViewById<EditText>(R.id.editName)
val editCount = findViewById<EditText>(R.id.editCount)
val editLevel = findViewById<EditText>(R.id.editLevel)
val move = findViewById<Button>(R.id.move)
move.setOnClickListener {
var student = Student(editName.text.toString(), editCount.text.toString().toInt(), editLevel.text.toString())
val nextIntent = Intent(this, SecondActivity::class.java)
nextIntent.putExtra("student", student)
startActivity(nextIntent)
}
}
}
버튼을 클릭했을 때 객체를 생성하여 생성에 필요한 것들을 넣어주었습니다.
그리고 다음 페이지로 넘어가기 위해 Intent
를 사용하였습니다.
이 때 putExtra
를 사용하여 "student"
라는 이름으로 student
변수에 저장된 객체를 넘겨줍니다.
메인 페이지에서 다음 화면으로 넘어왔을 때 처리해 줄 것들입니다.
import android.annotation.SuppressLint
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import dto.Student
class SecondActivity : AppCompatActivity() {
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
val textView = findViewById<TextView>(R.id.textView)
val read = findViewById<Button>(R.id.read)
read.setOnClickListener {
val student = intent.getParcelableExtra<Student>("student")
if (student != null) {
textView.text = "${student.name} ${student.count} ${student.level}"
}
}
}
}
read
버튼 클릭 시 getParcelableExtra
로 메인 화면에서 전달해 준 "student"
를 받아옵니다.
null
이 아닌 경우 텍스트뷰에 받아온 정보를 뿌려줍니다.
Singleton
싱글톤은 전역변수를 선언하지 않더라도 싱글톤 객체 하나만을 생성하여 어디서든 참조할 수 있게 해줍니다.
화면 이동간 싱글톤을 통해 메인 레이아웃에서 입력한 텍스트를 서브 레이아웃에서 받아올 것입니다.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<EditText
android:id="@+id/editText"
android:layout_width="428dp"
android:layout_height="72dp"
android:inputType="textPersonName"
android:text="Name"
android:ems="10"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.382"/>
<Button
android:id="@+id/move"
android:text="Button"
android:layout_width="264dp"
android:layout_height="52dp"
app:layout_constraintTop_toBottomOf="@+id/editText"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintVertical_bias="0.25"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".SubActivity">
<TextView
android:id="@+id/textView"
android:text="TextView"
android:textSize="30sp"
android:layout_width="334dp"
android:layout_height="84dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
class Singleton {
companion object {
var chicken:String? = null
}
}
싱글톤은 반드시 companion object
가 선언되어야 합니다.
이 싱글톤 객체는 어디서든 참조할 수 있게 됩니다. 초기값을 null
로 지정하였습니다.
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.EditText
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val editText = findViewById<EditText>(R.id.editText)
val move = findViewById<Button>(R.id.move)
move.setOnClickListener {
// 싱글턴 호출 및 적용
Singleton.chicken = editText.text.toString()
// 이동
val intent = Intent(this, SubActivity::class.java)
startActivity(intent)
}
}
}
싱글톤을 호출할 때는 Singleton.
으로 할 수 있으며 내부에 선언된 변수를 붙여주면 됩니다.
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
class SubActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sub)
val textView = findViewById<TextView>(R.id.textView)
textView.text = Singleton.chicken.toString()
}
}
싱글톤에 있는 정보를 가져올 때도 Singleton.
으로 불러올 수 있습니다.