일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- Top-down
- k8s
- Singleton Pattern
- Codility
- 피보나치
- KAKAO
- 백준
- Backjoon
- cpu scheduling
- Python
- BubbleSort
- easy
- Observer Pattern
- Programmers
- Dynamic Programming
- Kotlin
- mobaXTerm
- GCP
- GKE
- go
- github
- 그리디
- docker
- java
- 파이썬
- 알고리즘
- golang
- kubernetes
- LeetCode
- Today
- Total
To Be Developer
[Android] Kotlin 정리 본문
안드로이드 4대 구성요소(각각 독립적으로 실행하는 단위이다)
Activity = 눈에보이는 화면단위를 관리하는 실행단위, 화면 연동해서 결과를 제공
사용자와 상호작용을 통해 값을 전달받음
Service = 백그라운드 프로세싱, 화면이 없다
Broadcast Receiver = 시스템을 감시하는 목적으로 사용
Content Provider = 서로 다른 어플리케이션이 가지고 있는 정보를 공유할 때 사용
Manifest
intent-filter : 안드로이드 os 가 각각의 구성요소를 구성하고 구분하기 위한 이름이라 생각하면 됨
<activity android:name=”.클래스이름”>
<action android:name=”android.intent.action.MAIN”/> <- 여러개의 화면 중 어떤 것을 가장 먼저 실행시킬지 표시해주는 것이다. 인텐트 필터 안에 있어야 된다.
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission> 어플리케이션에 필요한 권한을 주어준다.
onCreate 메서드 = activity 객체를 생성하게 되면 자동으로 실행되는 메서드
setContentView(R.layout.레이아웃이름) = 레이아웃을 표시해준다.
Activity 생명주기 – 액티비티가 실행 되서 소멸될 때까지의 과정
- 각 주기 때마다 자동으로 호출되는 메서드를 제공한다.
1. 액티비티가 실행
2. onCreate() 메서드 호출
3. onStart() 메서드 호출
4. onResume() 메서드 호출
5. 액티비티가 실행된 상태가 된다.
6. 액티비티가 종료될 때 onPause() 메서드가 호출 // 화면에 팝업창과 같이 앱을 멈춰야할 때
일시정지가 되는데 그럴 때 onPause()가 호출이 된다. 일시정지 해지하려면 onResume()이 호출이 된다.
7. onStop()// 앱을 복구하려면 onRestart() 메서드를 호출 하여 onStart() 메서드부터 다시 실행하여 어플리케이션 실행상태를 만들게 된다.
8. onDestroy() // 뒤로가기로 어플을 종료하고 다시 실행하면 onCreate()부터 시작한다.
9. Activity 종료가 된다.
View
- 안드로이드에서 눈에 보이는 모든 요소.
- 개발자가 배치한 모든 View는 Class로 제공되는데 View라는 클래스를 상속받고 있다.
- View 클래스는 모든 UI 요소들의 부모클래스로써 위젯과 레이아웃으로 나뉜다.
레이아웃
- 컨테이너, 뷰 그룹이라고 부르기도 하며 다른 뷰들을 포함하고(컨테이너) 내부의 뷰를 통합관리(뷰 그룹) 내부의 뷰 들이 배치되는 모양을 결정(레이아웃) 한다.
위젯
- 문자열 입력, 문자열 출력 등 어떤 기능을 가지고 있고 사용자와 상호작용을 하는 뷰들을 통칭해서 위젯이라 부른다.
View 의 주요 속성
id : xml 이나 코드에서 뷰를 지칭하기 위해 사용하는 속성
layout_width : 뷰의 가로 길이
layout_height : 뷰의 세로 길이
margin : 뷰의 외부 여백
padding : 뷰의 내부 여백
layout_gravity : 뷰의 위치 정렬
gravity : 뷰 내부의 정렬
background : 뷰의 배경 지정
Linear Layout
- 좌에서 우, 위에서 아래 방향으로 뷰를 배치하는 레이아웃
- orientation : 뷰가 배치될 방향 vertical, horizontal 이있다.
- weight : Linear Layout 에 배치된 뷰의 속성으로 배치 후 남은 공간을 할당 받을 비율을 설정한다.
코틀린은 변수를 선언할 때 자료형과 관계없이 var라는 키워드를 사용
var text: TextView?= null;
text = findViewById<TextView>(R.id.text);
text?.text="문자열2"
//text?.setText("문자열 입니다.")
권한 리스트
var permission_list = arrayOf(
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.SEND_SMS,
Manifest.permission.INTERNET
)
권한 물어보기
fun checkPermission(){
if(Build.VERSION.SDK_INT<Build.VERSION_CODES.M){
//마시멜로 버전 이전 버전에서는 그냥 종료를 하겠다.
return;
}
for(permission :String in permission_list){
var chk = checkCallingOrSelfPermission(permission)
if(chk==PackageManager.PERMISSION_DENIED){
requestPermissions(permission_list, 0)
break
}
}
}
권한 결과 표시하기 위해 사용
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
var idx = 0;
text3.text=""
for(idx in grantResults.indices){
if(grantResults[idx]==PackageManager.PERMISSION_GRANTED){
text3.append("${permission_list[idx]} : 허용함\n")
}else{
text3.append("${permission_list[idx]} : 허용하지 않음\n")
}
}
}
안드로이드 쓰레드
- 쓰레드는 여러 처리를 비 동기적으로 처리하기 위해 사용한다
- 안드로이드는 비 동기적 처리 외에 네트워크에 관련된 코드는 전부 쓰레드로 운영해야 한다.
ANR ( application not responed)
- 안드로이드는 Activity 의 코드를 처리하기 위해 쓰레드를 발생하는데, 여기서 발생되는 쓰레드를 Main Thread 라고 부르며 UI Thread 라고 부르기도 한다.
- Main Thread 가 현재 작업을 하지 않을 때만 화면 작업이 가능하며 Main Thread 가 바쁠 때 화면 작업이나 터치가 발생하면 ANR 이 발생한다.
화면 처리
- 안드로이드는 개발자가 발생 시킨 쓰레드에서 화면에 대한 처리를 하면 오류가 발생한다. 이 때문에 쓰레드 운영에 대한 처리를 학습해야 한다.
- 현재 안드로이드 오레오(8.0) 이상 부터는 개발자가 발생시킨 쓰레드에서 화면 처리가 가능하다.
- 이전 버전에서는 Main Thread 를 통해서만 화면 처리가 가능하므로 주의하자
inner class ThreadClass1 : Thread(){
override fun run(){
while(isRunning){
SystemClock.sleep(100)
var now = System.currentTimeMillis()
Log.d("test1", "쓰레드 : ${now}")
textView2.text = "쓰레드 : ${now}"
}
}
}
쓰레드는 비 동기적 처리를 위해 사용하는 요소
안드로이드는 Activity의 코드를 처리하기 위해 발생된 MainThread 에서만 화면처리 가능
안드로이드 오레오 버전 이상부터 개발자가 발생 시킨 쓰레드에서도 화면 처리가 가능
Main Thread에서의 반복
- Main Thread 에서 처리하는 코드(Activity 내의 코드) 중에 일정 작업을 계속 반복 처리해야할 경우가 있다
- 이 때 무한 루프를 쓰면 화면처리가 불가능
- Handler를 통하면 원하는 코드를 반복해서 작업하는 것이 가능
Handler
- Handler는 개발자가 안드로이드 OS에게 작업 수행을 요청하는 역할을 한다.
- 개발자가 작업을 요청하면 안드로이드 OS는 작업을 하지 않을 때 개발자가 요청한 작업을 처리하게 된다.
- 이 처리는 Main Thread에서 처리한다.
- 5초 이상 걸리는 작업 불가 // 만약 그러한 작업이 필요하다면 쓰레드를 만들어서 쓰레드를 발생시켜서 작업을 해야된다. << ANR을 발생시키기 때문에 어플리케이션을 강제종료하게 되는 경우가 많기 때문이다.
- 화면 처리 가능
class MainActivity : AppCompatActivity() {
var handler : Handler? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view ->
var time = System.currentTimeMillis()
textView.text = "버튼클릭 : ${time}"
}
handler = Handler()
/* while(true){
SystemClock.sleep(100)
var time = System.currentTimeMillis()
textView2.text = "while : ${time}"
}*/
var thread = ThreadClass()
//handler?.post(thread) //post 메서드를 사용하게 되면
안드로이드 os 가 한가할때 ThreadClass() 를 처리하게 된다.
handler?.postDelayed(thread,100) // 0.1 초 딜레이를 넣는다
}
inner class ThreadClass : Thread(){
override fun run() {
var time = System.currentTimeMillis()
textView2.text = "Handler : ${time}"
handler?.postDelayed(this, 100)
}
}
}
Handler 를 이용하면 특정 코드를 Main Thread 로 하여금 반복해서 작업을 할 수 있다.
Handler를 통한 화면 처리
- 안드로이드에서 네트워크에 관련된 처리나 5초 이상 걸리는 작업은 모두 개발자가 발생하는 쓰레드에서 처리해야 한다.
- 개발자가 발생하는 쓰레드에서 화면에 관련 처리를 하고자 할 때는 Handler를 이용해야 한다.
- 안드로이드 오레오 이상에서는 개발자가 발생한 쓰레드에서 화면 처리를 해도 된다.
Handler
- 쓰레드에서 코드 처리 중 화면에 관련된 작업이 필요하다면 Handler를 상속받은 클래스를 만들어 필요시 Handler를 요청하면 된다.
- Handler를 상속 받은 클래스에서 만든 메서드는 Main Thread에서 처리한다.
- 개발자가 발생시킨 쓰레들에서 화면에 관련된 처리를 하고자 할 때 Handler를 활용한다.
class MainActivity : AppCompatActivity() {
var isRunning:Boolean = false
var handler:DisplayHandler? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view ->
var time = System.currentTimeMillis()
textView.text ="버튼 클릭 : ${time}"
}
handler = DisplayHandler()
isRunning = true
var thread = ThreadClass()
thread.start()
}
override fun onDestroy() {
super.onDestroy()
isRunning = false
}
inner class ThreadClass : Thread(){
var a1 = 10
var a2 = 20
override fun run() {
while(isRunning) {
SystemClock.sleep(100)
var time = System.currentTimeMillis()
Log.d("test1", "쓰레드 : ${time}")
// textView2.text= "쓰레드 : ${time}"
//handler?.sendEmptyMessage(0)
/* var msg = Message()
msg.what = 0
msg.obj = time
handler?.sendMessage(msg)*/
var msg2 = Message()
msg2.what = 1
msg2.arg1 = ++a1
msg2.arg2 = ++a2
msg2.obj = "안녕하세요"
handler?.sendMessage(msg2)
}
}
}
inner class DisplayHandler : Handler(){
override fun handleMessage(msg: Message?) {
super.handleMessage(msg)
if(msg?.what == 0) {
//var time = System.currentTimeMillis()
textView2.text = "Handler : ${msg?.obj}"
}else if(msg?.what == 1){
textView2.text = "${msg?.arg1}, ${msg?.arg2}, ${msg?.obj}"
}
}
}
}
AsyncTask
- AsyncTask는 비 동기 처리를 위해 제공되는 클래스이다.
- 개발자가 발생 시키는 쓰레드와 핸들러의 조합으로 쓰레드 운영 중 화면 처리가 가능했던 구조를 클래스로 제공하는 것
onPreExecute : doInBackground 메서드가 호출되기 전에 최초에 딱 한번 호출되는 메서드. Main Thread 가 처리한다. (메인 쓰레드가 처리하기 때문에 작업할 때 5초 이상 걸리면 안된다.)
doInBackground : 일반 쓰레드에서 처리한다.(네트워크관련 작업이나 5초이상 걸리는 작업을 여기서 처리를 한다. 화면에 관련된 작업은 하지 않는게 좋다. 왜냐하면 오레오 버전 이하에서는 메인쓰레드에서만 화면 처리를 할 수 있기 때문이다.)
onProgressUpdate : doInBackground 메서드에서 publishProgress 메서드를 호출하면 Main Thread가 처리하는 메서드. doInBackground 메서드 내에서 화면 처리가 필요할 때 사용한다.
onPostExecute : doInBackground 메서드 수행 완료 후 호출. Main Thread 가 처리한다. AsyncTask 가 끝나는 시점이라고 생각하면 된다.
- 정리 : AsyncTask를 사용하면 개발자가 발생 시키는 일반 쓰레드와 화면 처리를 위해 Main Thread를 이용하는 것을 조합하여 작업이 가능하다.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view->
var time = System.currentTimeMillis()
textView.text = "버튼 클릭 : ${time}"
}
var sync = AsyncTaskClass()
sync.execute(10, 20) //가변형 integer 배열을 준다// doInBackground 의 매개변수로 순차적으로 간다
}
inner class AsyncTaskClass : AsyncTask<Int, Long, String>() {
override fun onPreExecute() {
super.onPreExecute()
textView2.text = "AsyncTask 가동"
}
override fun doInBackground(vararg params: Int?): String {
var a1 = params[0]!! //a1 의 값
// 정수값을 뽑아 낼려면 null을 허용하지 않아야기 때문에 null 을 허용하는 변수를
//허용하지 않는 변수에 넣기 위해 "!!" 를 사용한다.
// null 을 허용하지 않아야만 사칙연산 등을 할 수 있기에 그렇게 사용한다.
var a2 = params[1]!! // a2
for (idx in 0..9) { // 0..9 코틀린에서 0에서 9까지 값을 가지고 있는 배열을 뜻한다. 10번을 반복
SystemClock.sleep(1000)
a1++
a2++
Log.d("text1", "${idx}: ${a1}, ${a2}")
// textView.text = "${idx}: ${a1}, ${a2}" <- 오레오 이하 버전에서는 불가능
var time = System.currentTimeMillis()
publishProgress(time) // AsyncTask 의 두 번째 제네릭의 Long은 publishProgress를 호출할 때 넘겨주는 값의 타입이다
// 여기에 담겨진 값을 쉼표로 배열을 줄 수 있는데 Long 배열로 주어
// onProgressUpdate 의 매개변수로 배열 값이 전달 된다.
}
return "수행이 완료되었습니다." //onPostExecute 메서드의 매개변수로 반환하게 된다.
}
override fun onProgressUpdate(vararg values: Long?) {
super.onProgressUpdate(*values)
textView2.text = "Async : ${values[0]}"
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
textView2.text = result
}
}
}
RunOnUiThread
- RunOnUiThread 메서드는 개발자가 발생시킨 일반 쓰레드에서 코드 일부를 Main Thread 가 처리하도록 하는 메서드이다.
- Java에서는 메서드로 제공하나 Kotlin 에서는 람다식으로 제공되고 있으므로 작성하는 것이 간편하다.
- Handler 나 AsyncTask 는 상속을 받아 복잡하게 코드를 작성해야 하는 불편함이 있으나, RunOnUiThread 는 필요할 때마다 이 메서드를 이용하여 굉장히 단순한 작업으로 코드를 작성할 수 있다.
정리 : RunOnUiThread 를 사용하면 일반 쓰레드 운영 중 화면 처리를 간편히 할 수 있다.
class MainActivity : AppCompatActivity() {
var isRunning:Boolean = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view->
var time = System.currentTimeMillis()
textView.text = "버튼 클릭 : ${time}"
}
isRunning = true
var thread = ThreadClass()
thread.start()
}
override fun onDestroy() {
super.onDestroy()
isRunning = false
}
inner class ThreadClass : Thread(){
override fun run() {
while(isRunning){
SystemClock.sleep(100)
var time = System.currentTimeMillis()
Log.d("test1", "쓰레드 : ${time}")
// textView2.text ="쓰레드 : ${time}" // 오레오 이전에는 일반 쓰레드에서 화면 처리 작업을 할 수 없다.
runOnUiThread {
textView2.text = "쓰레드 : ${time}" // 메인쓰레드가 가져와서 메인쓰레드가 처리하게 된다.// 엄청 편하다
}
}
}
}
}
액티비티 실행하기
안드로이드 4대 구성 요소 – 안드로이드 4대 구성요소는 AndroidManifest.xml 에 다 작성해야 된다. 정보를 다 집어넣어야 된다.
- 하나의 어플리케이션은 독립된 실행단위인 4대 구성 요소로 구성된다.
1. Activity : 화면을 관리하는 실행단위
2. Service : 백그라운드에서 실행되는 실행단위
3. Broad Cast Recevier : OS가 전달하는 메시지를 전달 받아 실행되는 실행단위
4. Contents Provider : 저장된 데이터를 제공하기 위한 실행 단위
Intent
- 안드로이드의 4대 구성 요소를 실행하기 위해서는 Intent라는 객체가 필요하다.
- 안드로이드의 4대 구성 요소를 실행하기 위해서는 개발자가 직접 실행하는 것이 아니라 OS에게 실행을 요청하게 된다.
- 실행 요청을 전달 받은 OS는 해당 실행 요소를 실행하게 되는데 실행 요청을 위한 정보를 담는 객체가 Intent이다.
Activity 실행 및 종료
- startActivity : 지정된 Intent 에 담긴 정보를 토대로 Activity를 실행한다.
- finish : 현재 실행되어 있는 Activity를 종료한다.
Back Stack
- Activity에서 다른 Activity를 실행하게 되면 이전 Activity는 Back Stack에 담겨 정지 상태가 되고 새로 실행된 Activity가 활동하게 된다.
- 새로 실행된 Activity가 제거 되면 Back Stack에 있던 Activity가 다시 활동하게 된다.
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view ->
var intent = Intent(this, SecondActivity::class.java)
startActivity(intent)
}
button3.setOnClickListener { view->
finish()
}
}
}
SecondActivity
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
button2.setOnClickListener { view->
finish()
}
}
}
startActivityForResult
- Activity에서 다른 Activity를 실행하고 다시 돌아왔을 때 어떤 처리가 필요하다면 Activity를 실행할 때 startActivity가 아닌 startActivityForResult 메서드를 사용한다.
onActivityResult
- startActivityForResult 메서드를 이용해 Activity를 실행하고 돌아오면 자동으로 onActivityResult 메서드가 호출된다. 여기에서 필요한 작업을 처리하면 된다.
정리 : startActivityForResult 메서드를 통해 Activity를 실행하면 다시 돌아올 때 필요한 처리를 할 수 있다.
MainActivity
class MainActivity : AppCompatActivity() {
val SECOND_ACTIVITY = 1 //val는 상수
val THIRD_ACTIVITY = 2 //val는 상수
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button2.setOnClickListener { view->
var intent = Intent(this, SecondActivity::class.java)
//startActivity(intent)
startActivityForResult(intent, SECOND_ACTIVITY)
}
button4.setOnClickListener { view ->
var intent = Intent(this, ThirdActivity::class.java)
startActivityForResult(intent, THIRD_ACTIVITY)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
// requestCode 는 startActivityForResult(intent, 100) 의 100 이다
// 사용하는 이유는 어떤 Activity를 실행하고 돌아왔는지 구분하기 위해서 그런 것이다.
// resultCode 다른 액티비티로 이동하고 작업이 이루어진 후 작업의 결과가 어떻게 되었는지
// 파악하는 것이 resultCode이다
super.onActivityResult(requestCode, resultCode, data)
when(requestCode){
SECOND_ACTIVITY-> {
textView2.text = "Second Activity에서 돌아옴\n"
when(resultCode){
Activity.RESULT_OK->{
textView2.append("RESULT_OK")
}
Activity.RESULT_CANCELED->{
textView2.append("RESULT_CANCELED") // 세컨드 액티비티에서 뒤로가기 버튼 누르면 CANCELED 값이 들어온다
}
Activity.RESULT_FIRST_USER->{
textView2.append("RESULT_FIRST_USER")
}
}
}
THIRD_ACTIVITY -> {
textView2.text = "Third Activity에서 돌아옴"
}
}
}
}
SecondActivity
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
button.setOnClickListener { view->
//setResult(100) // 이 result 값이 이전 액티비티인 MainActivity로 돌아갈때
// onActivityResult의 두 번째 매개변수인 resultCode 값으로 돌아가게 된다.
setResult(Activity.RESULT_OK) // 결과가 정상적으로 처리 되었다는 상수 값 // 모두 정수 값이다 다른 정수를 넣어도 된다.
finish()
}
button5.setOnClickListener { view->
setResult(Activity.RESULT_CANCELED) // 사용자에 의해 취소 되었을 때 사용되는 상수 값
finish()
}
button6.setOnClickListener { view ->
setResult(Activity.RESULT_FIRST_USER) // 그 외의 여러가지 결과에 대해 적용할 수 있도록 처리하는 값
finish()
}
}
}
ThirdActivity
class ThirdActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_third)
button3.setOnClickListener { view ->
finish()
}
}
}
Intent에 데이터 셋팅하기
- Activity 를 실행하기 위해 사용하는 Intent 객체에 putExtra 메서드를 이용하여 데이터를 셋팅하면 실행되는 Activity 에서 데이터를 전달 받을 수 있다.
- putExtra 메서드는 자료형 별로 메서드가 제공되기 때문에 타입을 가리지 않는다.
Intent 에서 데이터 가져오기
- Intent에 셋팅된 데이터는 get자료형Extra 메서드를 이용해 가져오면된다.
- 자료형 별로 메서드가 제공되므로 가져오고자 하는 데이터 타입에 맞는 메서드를 이용하여 가져온다.
정리 : Activity 가 실행되거나 돌아올 때 Intent를 통해서 데이터를 전달하거나 가져올 수 있다.
MainActivity
class MainActivity : AppCompatActivity() {
val SECOND_ACTIVITY =1;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener { view->
var intent = Intent(this, SecondActivity::class.java)
intent.putExtra("data1", 100)
intent.putExtra("data2", 11.11)
intent.putExtra("data3", true)
intent.putExtra("data4", "문자열")
//startActivity(intent)
startActivityForResult(intent, SECOND_ACTIVITY)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when(resultCode){
Activity.RESULT_OK->{
var value1 = data?.getIntExtra("value1", 0)
var value2 = data?.getDoubleExtra("value2", 0.0)
var value3 = data?.getBooleanExtra("value3", false)
var value4 = data?.getStringExtra("value4")
textView.text = "value1 : ${value1}\n"
textView.append("value2 : ${value2}\n")
textView.append("value : ${value3}\n")
textView.append("value4 : ${value4}\n")
}
}
}
}
SecondActivity
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
var data1 = intent.getIntExtra("data1", 0) // "data1" 에 값이 없다면 0 이 들어가도록 설정한다.
var data2 = intent.getDoubleExtra("data2", 0.0)
var data3 = intent.getBooleanExtra("data3", false)
var data4 = intent.getStringExtra("data4") // StringExtra는 두번째 매개변수 값이 없다. 문자열 뿐만 아니라
// 객체를 추출하는 메서드는 default 값이 없으므로 null 값이 들어간다.
textView2.text ="data1 : ${data1}\n"
textView2.append("data2: ${data2}\n")
textView2.append("data3: ${data3}\n")
textView2.append("data4: ${data4}\n")
button2.setOnClickListener { view ->
var intent2 = Intent()
intent2.putExtra("value1", 200)
intent2.putExtra("value2", 22.2)
intent2.putExtra("value3", true)
intent2.putExtra("value4", "문자열2")
setResult(Activity.RESULT_OK,intent2)
finish()
}
}
}
DrawerLayout
- Activity 에 메뉴가 많을 경우 메뉴를 숨겼다가 필요할 때 보이게 하는 UI 요소 이다.
HeaderLayout
- NavigationView의 상단에 표시되는 헤더 부분
SnackBar
Parcelable // 다른기기간 객체를 전달하려면 객체 진열화라는 작업을 해야한다.
// 형태가 같은 클래스를 하나 더 만들어준다는 개념
// A클래스가 가지고있는 객체의 값을 전달해서 객체를 복원하는 것이다.
- Intent를 통해 객체를 전달 할 때는 Parcleable 인터페이스를 구현한 객체만 가능하다
- Parcelable 인터페이스는 전달 받은 쪽에서 객체를 복원할 때 필요한 정보를 가진 부분을 의미한다.
TestClass
class TestClass : Parcelable{
var data10 : Int = 10
var data20 : String? = null
companion object { // static 타입의 객체 참조 변수를 선언할 때 사용
@JvmField // 안드로이드 os 가 사용할 때 붙여준다.
var CREATOR : Parcelable.Creator<TestClass> = object : Parcelable.Creator<TestClass> {
// 반드시 CREATOR 라는 이름을 붙여줘야지 사용이 가능하다. 안그럼 객체 복원이 불가능
override fun createFromParcel(source: Parcel?): TestClass { // 객체를 복원하는 메서드
var test = TestClass() // 객체 하나만 넘겼을때 사용
test.data10 = source?.readInt()!!
test.data20 = source.readString()
return test
}
override fun newArray(size: Int): Array<TestClass?> { // 객체를 배열로 넘겼을경우 이 메서드를 사용
return arrayOfNulls<TestClass>(size) // TestClass 값에 우선 null 을 채워주겠다
}
}
}
override fun writeToParcel(dest: Parcel?, flags: Int) { // Parcel 타입의 객체가 들어온다. 클래스가 가지고 있는 멤버의 값을 저장하는 용도이다
dest?.writeInt(data10)
dest?.writeString(data20)
}
override fun describeContents(): Int {
return 0
}
}
MainActivity
class MainActivity : AppCompatActivity() {
val SECCOND_ACTIVITY = 1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
button.setOnClickListener {view ->
var t1 = TestClass()
t1.data10 = 100
t1.data20 ="문자열1"
var intent = Intent(this, SecondActivity::class.java)
intent.putExtra("test1", t1) // writeToParcel 메서드를 호출한다
startActivityForResult(intent, SECCOND_ACTIVITY)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if(resultCode == Activity.RESULT_OK){
var t2 = data?.getParcelableExtra<TestClass>("test2")
textView.text ="t2.data10 : ${t2?.data10}\n"
textView.append("t2.data20 : ${t2?.data20}")
}
}
}
SecondActivity
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
var t1 = intent.getParcelableExtra<TestClass>("test1")
textView2.text = "t1.data10 : ${t1.data10}\n"
textView2.append("t1.data20 : ${t1.data20}")
button2.setOnClickListener { view ->
var t2 = TestClass()
t2.data10 = 200
t2.data20 = "문자열2"
var intent2 = Intent()
intent2.putExtra("test2", t2)
setResult(Activity.RESULT_OK, intent2)
finish()
}
}
}
ActionBar
- ActionBar는 Option Menu 구성 시 showAsAction 속성을 이용한다.
showAsAction
- None : 기본. ActionBar에 표시하지 않는다.
- Always : 무조건 ActionBar에 표시한다.
- ifRoom : 공간이 허락할 경우 ActionBar에 표시한다.
- Icon : 액션바에 표시될 때 사용할 아이콘을 지정한다.
- withText : 공간이 허락할 경우 아이콘과 함께 문자열을 표시한다.
res/menu/main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item1"
android:title="메뉴1"
app:showAsAction="always" />
<item
android:id="@+id/item2"
android:icon="@android:drawable/ic_menu_add"
android:title="메뉴2"
app:showAsAction="ifRoom" />
<item
android:id="@+id/item3"
android:checkable="true"
android:enabled="true"
android:icon="@android:drawable/ic_menu_agenda"
android:title="메뉴3"
android:visible="true"
app:showAsAction="ifRoom" />
<item
android:id="@+id/item4"
android:title="메뉴4"
app:showAsAction="ifRoom" />
</menu>
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean { // 메뉴를 생성하는 메서드
menuInflater.inflate(R.menu.main_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean { // 메뉴 선택시 실행되는 메서드
when (item?.itemId) {
R.id.item1 -> {
textView.text = "1번 메뉴"
}
R.id.item2 -> {
textView.text = "2번 메뉴"
}
R.id.item3 -> {
textView.text = "3번 메뉴"
}
}
return super.onOptionsItemSelected(item)
}
}
ActionView
- ActionBar에 뷰를 배치하고 이를 접었다 폈다 할 수 있는 개념
- 주로 검색 기능을 만들 때 사용한다.
res/menu/main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item1"
android:icon="@android:drawable/ic_menu_search"
android:title="SearchBar"
android:visible="true"
app:showAsAction="always|collapseActionView"
app:actionViewClass="android.support.v7.widget.SearchView"
/> <!-- app:actionViewClass="android.support.v7.widget.SearchView" 접었다 폈다 할 수 있게 한다 -->
</menu>
MainActivity.kt
class MainActivity : AppCompatActivity() {
var searchView:SearchView? = null
var data_list = arrayOf("aaa","bbb","ccc","ddd")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var adapter = ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, data_list)
list1.adapter = adapter
list1.isTextFilterEnabled = true // 리스트 뷰에 대한 검색기능을 활성화시킨다
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
var item = menu?.findItem(R.id.item1) // main_menu.xml 아이템을 가져온다
var listener = ActionListener()
item?.setOnActionExpandListener(listener)
searchView =item?.actionView as SearchView
searchView?.queryHint ="입력해주세요" //안내 문구 설정
var listener2 = ActionListner2()
searchView?.setOnQueryTextListener(listener2)
return true
}
inner class ActionListener : MenuItem.OnActionExpandListener{
//접혔을때 이벤트
override fun onMenuItemActionCollapse(item: MenuItem?): Boolean {
textView.text ="접혀졌습니다."
return true
}
//펼쳤을때 이벤트
override fun onMenuItemActionExpand(item: MenuItem?): Boolean {
textView.text ="펼쳐졌습니다."
return true
}
}
inner class ActionListner2 : SearchView.OnQueryTextListener{
//입력할 때 호출
override fun onQueryTextChange(p0: String?): Boolean {
textView2.text = p0
list1.setFilterText(p0) // 입력된 값을 검색한다
if(p0?.length == 0){ // 입력된 값의 길이가 0 이면 필터를 클리어 하겠다
list1.clearTextFilter()
}
return true
}
// 키보드의 확인 버튼을 눌렀을 때
override fun onQueryTextSubmit(p0: String?): Boolean {
textView2.text = "엔터키 : ${p0}"
searchView?.clearFocus() // 서치 버튼이 포커스가 풀리도록
return true
}
}
}
activity_main.xml
<?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">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<TextView
android:id="@+id/textView2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<ListView
android:id="@+id/list1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
ActionBar Navigation
ActionBar의 좌측에 버튼을 활성화 하여 이전 화면으로 돌아가는 기능을 구현할 수 있다.
SecondActivity.kt
class SecondActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
var action = supportActionBar // actionBar 객체 만들기
action?.setHomeButtonEnabled(true) // 홈버튼 사용
action?.setDisplayHomeAsUpEnabled(true) //홈버튼이 보여질지 여부
action?.setHomeAsUpIndicator(android.R.drawable.ic_menu_directions) // 홈버튼 아이콘 변경
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item?.itemId){
android.R.id.home ->{ // home 버튼을 눌렀을때 액티비티 종료하도록
finish()
}
}
return super.onOptionsItemSelected(item)
}
}
ActionBar 커스터마이징
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
//액션바 커스터마이징을 허용한다.
supportActionBar?.setDisplayShowCustomEnabled(true)
// 기존 액션바의 요소들을 숨긴다.
supportActionBar?.setDisplayShowTitleEnabled(false)
supportActionBar?.setDisplayShowHomeEnabled(false)
var actionView = layoutInflater.inflate(R.layout.custom_actionbar, null)
supportActionBar?.customView = actionView
var actionText = actionView.findViewById<TextView>(R.id.textView)
actionText.text ="커스텀 액션바"
actionText.setTextColor(Color.WHITE)
var actionBtn = actionView.findViewById<Button>(R.id.button)
actionBtn.setOnClickListener { view ->
Toast.makeText(this, "버튼을 눌렀습니다.", Toast.LENGTH_SHORT).show()
}
return true
}
}
custom_actionbar.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/button"
android:layout_centerHorizontal="true"
android:text="TextView"
android:textAppearance="@style/TextAppearance.AppCompat.Large" />
<Button
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:text="Button" />
</RelativeLayout>
ToolBar
- 안드로이드에서 ActionBar를 보다 자유롭게 사용할 수 있도록 Toolbar 라는 뷰를 제공하고 있다
- Toolbar를 이용해 탭 등 다양한 기능에 이용할 수 있도록 제공하고 있으며 기본적인 부분은 ActionBar와 동일하다. 기능을 똑같이 쓸 수 있고 똑같이 구현하면 되는데
Toolbar의 기능이 좀 더 많은 편이다.
menu/main_menu.xml
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="@+id/item1"
android:title="메뉴1" />
<item
android:id="@+id/item2"
android:icon="@android:drawable/ic_menu_add"
android:title="메뉴2"
app:showAsAction="always" />
<item
android:id="@+id/item3"
android:icon="@android:drawable/ic_menu_call"
android:title="메뉴3"
app:showAsAction="always" />
</menu>
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//액션바 대신 툴바를 사용하도록 설정한다.
setSupportActionBar(toolbar)
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.main_menu, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem?): Boolean {
when(item?.itemId){
R.id.item1 -> {
textView.text = "메뉴1 을 눌렀습니다."
}
R.id.item2 -> {
textView.text = "메뉴2 을 눌렀습니다."
}
R.id.item3 -> {
textView.text = "메뉴3 을 눌렀습니다."
}
}
return super.onOptionsItemSelected(item)
}
}
style.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Base.Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="windowActionBar">false</item> <!-- 액션바 사용하지 않겠다-->
<item name="windowNoTitle">true</item> <!-- 제목을 표시하지 않겠다 -->
</style>
</resources>
Appbar Layout
- Appbar Layout은 툴바를 포함하고 있는 뷰를 만들어 다양하게 사용할 수 있도록 제공되는 레이아웃이다.
- 대부분의 기능이 이미 구현 되어 있어 개발자는 적당히 배치해서 사용하면 된다.