69일차(2)/Android App(12) : ListView, Adapter 활용 예제 / java to kotlin 작성 연습
- 사용자에게 입력받은 값을 ListView에 추가하기
- 같은 코드 Kotlin으로 작성해보기
- 새 모듈 생성
- java로 생성하기!!
step05example
package com.example.step05example;
import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import androidx.appcompat.app.AppCompatActivity;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//필요한 필드 선언
EditText editText;
List<String> names;
ArrayAdapter<String> adapter;
ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//필요한 UI의 참조값을 UI에 부여된 id를 이용해서 얻어오기
listView=findViewById(R.id.listView);
editText=findViewById(R.id.editText);
Button addBtn=findViewById(R.id.addBtn);
//버튼 리스너 등록
addBtn.setOnClickListener(this);
//model생성
names=new ArrayList<>();
//adapter 생성
adapter=new ArrayAdapter<>(this,
android.R.layout.simple_list_item_1,
names);
//listView에 아답타 연결하기
listView.setAdapter(adapter);
}
@Override
public void onClick(View view) {
//1. EditText에 입력한 문자열을 읽어온다.
String inputName=editText.getText().toString();
//2. 모델에 데이터 추가
names.add(inputName);
//3. ListView가 업데이트할 수 있도록 아답타에 모델이 수정되었다고 전달
adapter.notifyDataSetChanged();
//4. EditText에 입력한 문자열 삭제
editText.setText("");
}
}
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"
tools:context=".MainActivity"
android:orientation="vertical">
<ListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/listView"
android:layout_weight="1"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:id="@+id/editText"
android:hint="이름 입력..."/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="추가"
android:id="@+id/addBtn"/>
</LinearLayout>
</LinearLayout>
- 기본 Contstraint Layout에서 Linear Layout 으로 바꾸고싶다면 이렇게 코드에서 직접 수정해주면 된다.
- ListView, editText, Button요소 추가해주기
- 코드로 작성시 android: 는 입력하지 않아도 된다. 앞의 속성명만 작성하면 자동완성된다.
- 위와 같은 코드로 이런 형태가 된다.
- 아래쪽 텍스트 입력란과 버튼은 수평 정렬이고, 수평 폭을 나눠가지고 있다.
- 리스트뷰는 높이를 나누어가지고 있다. 하단 리니어가 일부 가지고, 남은 높이를 listview가 전부 가지고 있는 것.
- "vertical" 로 지정된 LinearLayout 의 자식 요소들은 수직 높이를 가지고 경쟁하게 된다.
- listview는 폭을 가지지 않고(0dp), 아래쪽 리니어는 필요한만큼만 가진다. 이후 listView가 남는 폭을 전부 가진다.
- 기준이 수평(horizontal)인 LinearLayout 의 자식요소들은 폭을 가지고 경쟁한다.
- EditText는 일단 0으로 하고, 버튼은 필요한 만큼의 폭만 가지고, 남은 폭은 EditText가 전부 가진다.
- 이렇게 레이아웃 전략을 잘 짜서 만들어보기!
- 문자열을 입력하고 추가버튼을 누르면 문자열이 리스트에 하나씩 출력되도록 할 예정!
- 버튼에 리스너를 등록해서 입력된 값을 읽어와서 리스트뷰에 하나씩 추가되도록 하면 된다.
- findViewById로 UI의 참조값을 얻어와서 리스너 등록해주기
- 다른 메소드에서 필요한 값은 필드로 선언해서 필드에 저장!
- 읽어와서 모델에 추가하고, notifyDataSetChanged() 로 아답타에 알리기
- 내가 입력한 값으로 리스트에 동적으로 아이템이 추가되는 것을 볼 수 있다.
- 똑같은 기능을 하는 메인 액티비티를 코틀린으로 만들어보기
- MainActivity가 들어있는 패키지에 우클릭- new - Activity - Empty Activity
- 언어를 코틀린으로 설정!
package com.example.step05example
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.Button
import android.widget.EditText
import android.widget.ListView
import androidx.appcompat.app.AppCompatActivity
/*
extends AppCompatActivity 상속 => : AppCompatActivity
implements View.OnClickListener 인터페이스 구현=> , View.OnClickListener
*/
class MainActivity2 : AppCompatActivity(), View.OnClickListener {
//null로 초기화하기 위해서는 type 뒤에 ? 가 필요하다.
var editText:EditText?=null;
var names:MutableList<String>?=null;
var adapter:ArrayAdapter<String>?=null
//위의 선언이 불편하다면 아래와 같이 뒤늦은 초기화도 가능하다.
lateinit var listView:ListView //참조값을 나중에 넣고 싶으면 lateinit 예약어를 사용하면 된다.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
listView=findViewById(R.id.listView)
editText=findViewById(R.id.editText)
//findViewById<UI의 type>
var addBtn=findViewById<Button>(R.id.addBtn)
addBtn.setOnClickListener(this)
names=mutableListOf()
adapter=ArrayAdapter(this,
android.R.layout.simple_list_item_1,
names!!) //names는 null이 확실히 아니니까 그냥 받아 주세요! 라는 의미이다.
/*
[ java ]
.setXXX(value)
[ kotlin ]
.xxx = value
*/
//아답타를 ListView에 연결
listView.adapter=adapter
}
override fun onClick(p0: View?) {
//editText?.text는 editText 안의 값이 null이 아니면 .text를 참조하겠다는 의미
val inputName:String=editText?.text.toString()
names?.add(inputName)
adapter?.notifyDataSetChanged()
editText?.setText("")
}
}
** Kotlin에서는
- : 클래스명() 으로 클래스의 상속을 표기한다. () 는 기본 생성자를 호출하기 위한 것.
- : 인터페이스명 으로 인터페이스의 구현을 표기한다.
- 연이어서 클래스, 인터페이스의 상속, 구현을 할 때에는 , 로 표기해주면 된다.
- override는 메소드 앞에 override 예약어만 붙이면 된다.
- 레이아웃 xml문서는 똑같이 사용한다(activity_main).
- 필드 선언하기
- 코틀린에서는 선언하는 것만으로는 null이 되지않는다. 직접 null을 넣어주어야 한다.(초기화)
- 그리고 null을 넣어주려면 필드명 뒤에 ? 표기가 필요하다.
- 만약 만들어만 놓고 값은 나중에 넣고싶다면 lateinit 예약어를 사용
- java 코드와 직접 비교하면 이렇다. 비교하며 작성해보고 공부하기!
- 필요한 ui 의 참조값 얻어오기
- 인터페이스를 구현하고, 메소드를 override해준다.
- 이제 아래에서 버튼의 리스너를 this 로 등록할 수 있다.
- 필드에서 names에 이미 타입이 지정되어 있기 때문에 MutableList 의 타입은 지정하지 않아도 된다.
- List 대신 MutableList로 선언한다.
- java: (type)names
→ Kotlin: names as type
- 만약 type 캐스팅을 할 일이 있다면 이렇게 하면 된다.
- 오류가 발생해서 보니 null이 들어갈 수 없게 되어있다. null을 들어가지 않게 하려면 !! 를 넣으면된다.
- 이건 null이 아니니까 받아달라! 는 뜻이라고 생각하고 사용하면 된다..
- java : .setXXX(value)
- kotlin: .xxx = value
- 코틀린의 특징! java에서 setXXX.(value) 으로 값을 넣어주는 메소드를 코틀린에서는 그냥 = 으로 넣는다.
- 바로 대입연산자로 대입한다고 생각하면 된다.
- 아답타에 그냥 대입연산자로 넣어버린다! 그냥 필드에 값을 담듯이 넣으면 된다.
- 메소드에도 .getText() 가 없다. 이것도 그냥 필드 참조하듯이 text() 를 사용해서 넣으면 된다.
- 그냥 text.toString() 해주면 된다.
- null일 가능성이 있는 변수나 필드를 만들면 값을 가져올때도 ? 를 써주어야 하는 경우가 있다.
- editText?.text() 는 editText 안의 값이 null이 아니면 .text를 참조하겠다는 의미
- 번거로운 면이 있다... 그래서 코틀린에서는 null을 그다지 안 쓰는 것이 편하다...
- override한 메소드. null일 가능성이 있는 view타입을 의미한다.
- 항상 ?를 넣어주어야해서 좀 불편하다..
- manifest에서 intent-filter 를 코틀린 쪽으로 옮겨오고 테스트하기!
- manifest에서 exported="true" 로 바꾸어주어야 나온다!(안그러면 오류 표시된다)
- java와 똑같이 작동되는 것을 확인할 수 있다.
- 사전에 필드 선언시 번거로운 부분이 많아서 lateinit 예약어를 쓸 일이 많다. 나중에 값을 집어넣으려고 할 경우에 쓰기!
- java 코드로 작성된 문서를 kotlin으로 변환하는 것을 요약하면,
- 클래스 상속은 : 클래스명 ()
- 인터페이스 구현은 : 인터페이스명
- null일 가능성이 있는 필드를 선언한다면, ? 를 붙여주기
- 자주 사용하던 java의 ArrayList<> 같은 경우에는 MutableList<> 로 받아주기
- lateinit : 지금은 null로 초기화하지만 나중에 꼭 null이 아닌 값을 넣을 것이다! 라는 의미
(만약 나중에 init 하지 않으면 당연히 nullPointException이 발생한다.)
- !! : null을 허용하지 않는 공간에 null 일 가능성이 있는 값을 전달하려면
여기 들어가게 될 값이 null이 아니라는 것을 단언해야 한다!! 그런 의미로 사용.
- setter 메소드는 필드를 참조하는 것처럼 사용한다.
- setXXX라는 메소드가 없다.
- Null일 가능성이 있는 필드를 참조할때는 ? 를 붙여서 참조하기!
'국비교육(22-23)' 카테고리의 다른 글
70일차(2)/Android App(14) : Kotlin Extend, Interface / inner class 사용하기 (0) | 2023.01.16 |
---|---|
70일차(1)/Android App(13) : Custom Adapter 생성, Serializable 인터페이스 구현 (0) | 2023.01.16 |
69일차(1)/Android App(11) : Kotlin Constructor, field / null 값 허용 문법 (0) | 2023.01.14 |
68일차(2)/Android App(10) : ListView, OnClickListener, AlertDialog 활용 예제 (0) | 2023.01.13 |
68일차(1)/Android App(9) : Kotlin 기본 문법 예제 (0) | 2023.01.13 |