To Be Developer

[Android] Kotlin 정리 본문

Android

[Android] Kotlin 정리

Jeff Hwang 2019. 3. 6. 15:08

안드로이드 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은 툴바를 포함하고 있는 뷰를 만들어 다양하게 사용할 수 있도록 제공되는 레이아웃이다.

- 대부분의 기능이 이미 구현 되어 있어 개발자는 적당히 배치해서 사용하면 된다.