Kotlin을 사용하여 활동 간 Android 인텐트 처리
이 튜토리얼에서는 Android 인텐트에 대해 논의하고 애플리케이션에서 Kotlin을 사용하여 구현합니다.
무엇을 배울 것인가?
- 의도란 무엇입니까?
- 의도 유형
- 활동 간 의도 사용
- Android 인텐트를 사용하여 데이터 전송
- Parcelable 및 Serializable을 사용하여 개체 전달
- 속기 인텐트 만들기
Android 인텐트
이름에서 알 수 있듯이 Intent는 Android 애플리케이션의 흐름과 관련하여 일부 작업을 수행하는 데 사용되는 것입니다. 인텐트는 다음과 같은 용도로 사용할 수 있습니다.
- 새 활동을 시작하고 일부 데이터를 전달합니다.
- 프래그먼트 시작/프래그먼트 간 통신.
- 서비스 시작/종료.
- 브로드캐스트 수신기에서 활동 시작
이 튜토리얼에서는 주로 활동을 처리하기 위한 인텐트를 살펴볼 것입니다. 의도 정의는 주로 현재 활동의 인스턴스로 구성됩니다. 다음과 같은 구성 요소 이름을 설정합니다. 호출할 활동의 정규화된 클래스 이름입니다. 이 유형의 의도는 명시적 의도입니다. URL, 전화번호, 위치와 같은 작업. 해당 유형의 사용 가능한 모든 응용 프로그램이 표시됩니다. 이는 암시적 의도 범주에 속합니다. Kotlin에서 액티비티를 생성하는 방법은 다음과 같습니다.
val intent = Intent(this, OtherActivity::class.java)
startActivity(intent)
startActivity
는 활동 스택에 OtherActivity
를 추가하고 실행합니다. 애플리케이션은 어떤 활동이 가장 먼저 호출되는지 어떻게 알 수 있습니까? AndroidManifest.xml에서 우리는 실행될 첫 번째 활동에서 android.intent.action.MAIN
작업 및 카테고리 android.intent.category.LAUNCHER
로 인텐트 필터를 설정합니다. 우리의 응용 프로그램이 열릴 때. finish()
는 활동을 파괴하고 스택에서 제거하는 데 사용됩니다.
의도 플래그
플래그는 시작 프로세스를 사용자 지정하기 위해 인텐트에 설정할 수 있는 옵션과 같습니다. 매번 같은 활동을 시작하면 새 인스턴스가 생성되어 활동 스택에 추가됩니다. 이를 방지하기 위해 다음 플래그를 사용할 수 있습니다. FLAG_ACTIVITY_SINGLE_TOP
- 설정하면 활동이 실행되지 않습니다. 활동 스택의 맨 위에서 이미 실행 중입니다.
intent.flags = Intent.FLAG_ACTIVITY_SINGLE_TOP
마찬가지로 FLAT_ACTIVITY_CLEAR_TOP
플래그를 사용하면 활동의 다른 인스턴스가 이미 존재하는 경우 시작되지 않습니다. 이 플래그는 호출된 활동 위의 모든 활동을 지우고 스택 맨 위에 설정합니다.
인텐트를 통한 데이터 전달
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("keyString", "Androidly String data")
이러한 Extras 필드는 궁극적으로 전달할 모든 데이터를 보유하는 Bundle
개체로 래핑된 후드 아래에 있습니다. 다른 활동에서 데이터를 검색하려면 번들
에 대해 extras
속성을 사용해야 합니다. 새 활동에서 데이터 검색
val bundle: Bundle? = intent.extras
val string: String? = intent.getString("keyString")
val myArray: ArrayList<String>? = intent.getStringArrayList("myArray")
intent
, extras
는 Java의 getIntent()
, getExtras()
와 동일합니다. 데이터가 없을 때 NullPointerExceptions
를 방지하기 위해 nullable 유형 Bundle?
을 사용했습니다. 마찬가지로 키를 사용하여 가져온 데이터의 경우 키가 올바르지 않을 때 발생할 수 있는 NPE를 방지하기 위해 nullable 유형을 사용했습니다.
Parcelable 및 Serializable 데이터 사용
때때로 우리는 한 활동에서 다른 활동으로 완전한 객체를 전달해야 합니다. Parcelable 또는 Serializable 인터페이스를 구현하지 않으면 불가능합니다. Parcelable과 Serializable의 차이점
- Parcelable 인터페이스는 Android SDK의 일부입니다. Serializable은 Java의 표준 인터페이스입니다.
- Parcelable에서 Parcel 객체에 전달하는 데 필요한 모든 데이터를 설정하고 writeToParcel() 메서드 등을 재정의해야 합니다. 직렬화 가능 구현에서 인터페이스는 데이터를 전달하기에 충분합니다.
- Parcelable은 Serializable보다 빠릅니다.
Parcelable 데이터 보내기
Kotlin은 Parcelable에 데이터를 설정하기 위해 writeToParcel() 메서드를 재정의하지 않도록 몇 가지 편리한 주석을 제공합니다. 대신 아래와 같이 @Parcelize 주석을 사용할 수 있습니다.
@Parcelize
data class Student(
val name: String = "Anupam",
val age: Int = 24
) : Parcelable
참고: 현재 build.gradle에서 @Parcelize 주석이 작동하려면 다음 코드를 추가해야 합니다.
android {
androidExtensions {
experimental = true
}
//..
....
}
활동에서 다음을 수행합니다.
val student = Student()
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("studentData", student)
startActivity(intent)
직렬화 가능 데이터 보내기
data class Blog(val name: String = "Androidly", val year: Int = 2018) : Serializable
val blog = Blog("a", 1)
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("blogData", blog as Serializable)
startActivity(intent)
Android Studio 프로젝트에서 위의 지식을 사용해 봅시다.
프로젝트 구조
레이아웃 코드
activity_main.xml
레이아웃의 코드는 다음과 같습니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<Button
android:id="@+id/btnSimpleIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SIMPLE INTENT" />
<Button
android:id="@+id/btnSimpleIntentAndData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="SIMPLE INTENT WITH DATA" />
<Button
android:id="@+id/btnParcelableIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Parcelable Intent" />
<Button
android:id="@+id/btnSerializableIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Serializable Intent" />
<Button
android:id="@+id/btnBrowserIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Browser Intent" />
<Button
android:id="@+id/btnMapsIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Maps Intent" />
<Button
android:id="@+id/btnGenericIntent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Generic Intent" />
</LinearLayout>
activity_other.xml 레이아웃의 코드는 다음과 같습니다.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Intent Data goes here" />
</LinearLayout>
활동 코드
MainActivity.kt 클래스의 코드는 다음과 같습니다.
package net.androidly.androidlyintents
import android.app.Activity
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.os.Parcelable
import android.view.View
import android.widget.Toast
import android.widget.Toast.LENGTH_LONG
import kotlinx.android.parcel.Parcelize
import kotlinx.android.synthetic.main.activity_main.*
import java.io.Serializable
@Parcelize
data class Student(
val name: String = "Anupam",
val age: Int = 24
) : Parcelable
data class Blog(val name: String = "Androidly", val year: Int = 2018) : Serializable
class MainActivity : AppCompatActivity(), View.OnClickListener {
fun Context.gotoClass(targetType: Class<*>) =
ComponentName(this, targetType)
fun Context.startActivity(f: Intent.() -> Unit): Unit =
Intent().apply(f).run(this::startActivity)
inline fun <reified T : Activity> Context.start(
noinline createIntent: Intent.() -> Unit = {}
) = startActivity {
component = gotoClass(T::class.java)
createIntent(this)
}
var arrayList = ArrayList<String>()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btnSimpleIntent.setOnClickListener(this)
btnSimpleIntentAndData.setOnClickListener(this)
btnParcelableIntent.setOnClickListener(this)
btnSerializableIntent.setOnClickListener(this)
btnBrowserIntent.setOnClickListener(this)
btnMapsIntent.setOnClickListener(this)
btnGenericIntent.setOnClickListener(this)
arrayList.add("Androidly")
arrayList.add("Android")
arrayList.add("Intents")
}
override fun onClick(v: View?) {
when (v?.id) {
R.id.btnSimpleIntent -> {
val intent = Intent(this, OtherActivity::class.java)
startActivity(intent)
}
R.id.btnSimpleIntentAndData -> {
val intent = Intent(this, OtherActivity::class.java)
with(intent)
{
putExtra("keyString", "Androidly String data")
putStringArrayListExtra("arrayList", arrayList)
putExtra("keyBoolean", true)
putExtra("keyFloat", 1.2f)
}
startActivity(intent)
}
R.id.btnParcelableIntent -> {
val student = Student()
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("studentData", student)
startActivity(intent)
}
R.id.btnSerializableIntent -> {
val blog = Blog("a", 1)
val intent = Intent(this, OtherActivity::class.java)
intent.putExtra("blogData", blog as Serializable)
startActivity(intent)
}
R.id.btnBrowserIntent -> {
val url = "https://www.androidly.net"
val uri = Uri.parse(url)
val intent = Intent(Intent.ACTION_VIEW, uri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
Toast.makeText(applicationContext, "No application found", LENGTH_LONG).show()
}
}
R.id.btnMapsIntent -> {
val loc = "12.9538477,77.3507442"
val addressUri = Uri.parse("geo:0,0?q=" + loc)
val intent = Intent(Intent.ACTION_VIEW, addressUri)
if (intent.resolveActivity(packageManager) != null) {
startActivity(intent)
} else {
Toast.makeText(applicationContext, "No application found", LENGTH_LONG).show()
}
}
else -> start<OtherActivity> {
putExtra("keyString", "Androidly Generic Intent")
}
}
}
}
위의 코드에서는 Intent 유형별로 Button을 사용했습니다. 우리는 Kotlin의 with
표현식을 사용하여 매번 intent
개체에 데이터를 설정하는 것을 방지했습니다. 게다가 위에서 이미 논의한 것과는 별도로 세 가지 의도를 만들었습니다. 브라우저 인텐트는 브라우저 앱의 인텐트에 있는 URL을 실행하는 데 사용됩니다. Intent(Intent.ACTION_VIEW, uri)
를 사용합니다. 위치 인텐트는 지도 애플리케이션에서 lat,lng 위치를 실행하는 데 사용됩니다. 둘 다 암시적 인텐트입니다. 마지막으로 우리는 Kotlin의 확장 함수와 람다 표현식을 사용하여 인텐트를 시작하는 속기 함수를 만드는 일반 인텐트를 사용했습니다. 이를 위해 다음 기능을 사용합니다.
fun Context.gotoClass(targetType: Class<*>) =
ComponentName(this, targetType)
fun Context.startActivity(createIntent: Intent.() -> Unit): Unit =
Intent().apply(createIntent).run(this::startActivity)
inline fun <reified T : Activity> Context.start(
noinline createIntent: Intent.() -> Unit = {}
) = startActivity {
component = gotoClass(T::class.java)
createIntent(this)
}
startActivity는 상위 함수를 매개변수로 찾는 확장 함수입니다. 덕분에 이제 다음과 같은 몇 줄의 인텐트를 실행할 수 있습니다. start
OtherActivity.kt 클래스의 코드는 다음과 같습니다.
package net.androidly.androidlyintents
import android.content.Context
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import kotlinx.android.synthetic.main.activity_other.*
class OtherActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_other)
val bundle: Bundle? = intent.extras
bundle?.let {
bundle.apply {
//Intent with data
val string: String? = getString("keyString")
textView.text = string
val myArray: ArrayList<String>? = getStringArrayList("myArray")
showToast(message = "MyArrayList size:${myArray?.size}")
val arrayList: ArrayList<String>? = getStringArrayList("arrayList")
showToast(message = "ArrayList size:${arrayList?.size}")
val float: Float? = bundle.get("keyFloat") as Float?
var boolean = bundle.get("boolean") as? Boolean
showToast(message = "Float data is:$float")
showToast(message = "Boolean data is:$boolean")
boolean = bundle.get("keyBoolean") as? Boolean
showToast(message = "Boolean correct key data is:$boolean")
}
bundle.apply {
//Serializable Data
val blog = getSerializable("blogData") as Blog?
if (blog != null) {
textView.text = "Blog name is ${blog?.name}. Year started: ${blog?.year}"
}
}
bundle.apply {
//Parcelable Data
val student: Student? = getParcelable("studentData")
if (student != null) {
textView.text = "Name is ${student?.name}. Age: ${student?.age}"
}
}
}
}
private fun showToast(context: Context = applicationContext, message: String, duration: Int = Toast.LENGTH_SHORT) {
if (!message.contains("null"))
Toast.makeText(context, message, duration).show()
}
}
안드로이드 의도