728x90
앱 build.gradle Implementation 추가
RecyclerView는 기본 API에 제공되어 있지 않기 때문에, Support Library 추가를 해야 사용할 수 있다.

추가 방법의 한가지이다.

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'


android {
    compileSdkVersion 29
    buildToolsVersion "29.0.3"

    defaultConfig {
        applicationId "com.link2me.android.recyclerview"
        minSdkVersion 21
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }

    compileOptions {
        sourceCompatibility = 1.8
        targetCompatibility = 1.8
    }
}


dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'

    implementation 'com.google.android.material:material:1.1.0'
    implementation 'androidx.cardview:cardview:1.0.0'  // 레이아웃으로 사용할 CardView
    implementation 'androidx.recyclerview:recyclerview:1.1.0'

    // 이미지 출력용 Glide
    implementation 'com.github.bumptech.glide:glide:4.11.0'
    annotationProcessor 'com.github.bumptech.glide:compiler:4.11.0'

    kapt 'com.github.bumptech.glide:compiler:4.11.0'
    // Kotlin plugin doesn't pick up annotationProcessor dependencies

}
 


데이터 클래스 정의

data class PersonModel (
    var idx: String,
    var name: String,
    var position : String,
    var mobileNO: String,
    var checkBoxState: Boolean
)


Layout 만들기

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:listitem="@layout/item_listview" />

</androidx.constraintlayout.widget.ConstraintLayout>
 


Item View 생성

cardView 만드는 방법은 https://link2me.tistory.com/1813 참조


Adapter 구현

import android.content.Context
import android.os.AsyncTask
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.link2me.android.recyclerview.model.PersonModel
import kotlinx.android.synthetic.main.item_listview.view.*
import java.net.HttpURLConnection
import java.net.URL

class PersonAdapter(val list: List<PersonModel>, val context: Context) : RecyclerView.Adapter<PersonAdapter.ViewHolder>() {

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // XML객체를 실제 View 로 만들어주기 위한 작업
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_listview,parent,false)
        return ViewHolder(view)
    }

    override fun getItemCount(): Int {
        return list.count()
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // 생성된 ViewHolder가 화면에 표시될 때 실제 데이터를 바인딩 해주는 함수이다.
        // ?. 연산자를 사용하면 null 값이 아닌 경우에만 호출된다.
        //holder?.bindItems(list[position], context) // 이렇게 하거나 아래줄과 같이 사용
        (holder as ViewHolder).bindItems(list[position],context)
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        // 코틀린에서는 기본적으로 null 값을 허용하지 않는다.

        // null 값을 허용하려면 자료형의 오른쪽에 ? 기호를 붙여준다.
        // 변수 뒤에 !!를 추가하면 null 값이 아님을 보증하게 된다.
        // ?. 연산자를 사용하면 null 값이 아닌 경우에만 호출된다.
        val mImage = itemView?.findViewById(R.id.listitem_image) as ImageView

        fun bindItems (person: PersonModel, context: Context) {
            val imageUri: String = "http://www.abc.com/photos/${person.idx}.jpg"
            if (mImage != null) {
                val urlexist: Boolean = URLExistTask().execute(imageUri).get()
                if (urlexist) {
                    Glide.with(context).load(imageUri).override(126, 160).into(mImage)
                } else {
                    val resourceId: Int = R.drawable.photo_base
                    Glide.with(context).load(resourceId).override(126, 160).into(mImage)
                }
            };
            itemView.listitem_title.text = person.name
            itemView.listitem_subtext1.text = person.position
            itemView.listitem_subtext2.text = person.mobileNO
            itemView.listitem_checkbox.isChecked = person.checkBoxState

            itemView.setOnClickListener({
                Toast.makeText(context,person.name,Toast.LENGTH_SHORT).show()
            })

        }

    }

    inner class URLExistTask : AsyncTask<String, Void, Boolean>() {
        override fun doInBackground(vararg params: String?): Boolean {
            return try {
                HttpURLConnection.setFollowRedirects(false)
                val con: HttpURLConnection = URL(params[0]).openConnection() as HttpURLConnection
                con.setConnectTimeout(1000)
                con.setReadTimeout(1000)
                con.setRequestMethod("HEAD")
                con.getResponseCode() === HttpURLConnection.HTTP_OK
            } catch (e: Exception) {
                e.printStackTrace()
                false
            }
        }
    }

}

서버에 실제 이미지가 존재하는지 여부를 확인하기 위한 URLExistTask 메소드를 구현한다.


Adapter 생성

class MainActivity : AppCompatActivity() {

    var adapter: PersonAdapter?= null
    var personList: List<PersonModel> = ArrayList()
    // Java 에서는 new 키워드로 객체를 생성하지만, 코틀린에서는 new 키워드를 사용하지 않는다.

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        personList = listOf(
            PersonModel("250","홍길동","차장","010-111-1000",true),
            PersonModel("340","강감찬","부장","010-111-1001",true),
            PersonModel("419","이순신","본부장","010-111-1002",true),
            PersonModel("490","김구","부장","010-111-1003",true),
            PersonModel("503","양만춘","대리","010-111-1004",true),
            PersonModel("3","김두환","과장","010-111-1005",true),
            PersonModel("1","정성룡","사원","010-111-1006",true)
        )

        adapter = PersonAdapter(personList,this)
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.setHasFixedSize(true)
        recyclerView.adapter = adapter
    }
}
 


리스트는 서버에서 가져온 리스트라고 가정하고 Local 데이터를 생성하여 테스트한다.


테스트에 사용한 소스코드를 첨부한다.

recyclerview_kotlin.zip


참고하면 좋은 자료

https://www.andreasjakl.com/kotlin-recyclerview-for-high-performance-lists-in-android/


Adapter 구현 수정사항

class PersonAdapter(val items: List<PersonModel>, val context: Context) : RecyclerView.Adapter<PersonAdapter.ViewHolder>() {

    override fun getItemCount(): Int = items.size

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        // 생성된 ViewHolder가 화면에 표시될 때 실제 데이터를 바인딩 해주는 함수이다.
        //(holder as ViewHolder).bindItems(list[position],context)
        var item = items[position]
        val listener = View.OnClickListener {it ->
            Toast.makeText(it.context, "Clicked: ${item.name}", Toast.LENGTH_SHORT).show()
        }
        holder.apply {
            // apply()함수는 블록에 객체 자신이 리시버 객체로 전달되고 이 객체가 반환된다.
            // 객체의 상태를 변화시키고 그 객체를 다시 반환할 때 주로 사용한다.
            bindItems(listener, item, context)
            itemView.tag = item
        }
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        // XML객체를 실제 View 로 만들어주기 위한 작업
        val view = LayoutInflater.from(parent.context).inflate(R.layout.item_listview,parent,false)
        return ViewHolder(view)
    }

    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        // 코틀린에서는 기본적으로 null 값을 허용하지 않는다.

        // null 값을 허용하려면 자료형의 오른쪽에 ? 기호를 붙여준다.
        // 변수 뒤에 !!를 추가하면 null 값이 아님을 보증하게 된다.
        // ?. 연산자를 사용하면 null 값이 아닌 경우에만 호출된다.
        val mImage = itemView?.findViewById(R.id.listitem_image) as ImageView

        fun bindItems (listener: View.OnClickListener,person: PersonModel, context: Context) {
            val imageUri: String = "http://www.abc.com/photos/${person.idx}.jpg"
            if (mImage != null) {
                val urlexist: Boolean = URLExistTask().execute(imageUri).get()
                if (urlexist) {
                    Glide.with(context).load(imageUri).override(126, 160).into(mImage)
                } else {
                    val resourceId: Int = R.drawable.photo_base
                    Glide.with(context).load(resourceId).override(126, 160).into(mImage)
                }
            };
            itemView.listitem_title.text = person.name
            itemView.listitem_subtext1.text = person.position
            itemView.listitem_subtext2.text = person.mobileNO
            itemView.listitem_checkbox.isChecked = person.checkBoxState
            itemView.setOnClickListener(listener)
        }

    }

    inner class URLExistTask : AsyncTask<String, Void, Boolean>() {
        override fun doInBackground(vararg params: String?): Boolean {
            return try {
                HttpURLConnection.setFollowRedirects(false)
                val con: HttpURLConnection = URL(params[0]).openConnection() as HttpURLConnection
                con.setConnectTimeout(1000)
                con.setReadTimeout(1000)
                con.setRequestMethod("HEAD")
                con.getResponseCode() === HttpURLConnection.HTTP_OK
            } catch (e: Exception) {
                e.printStackTrace()
                false
            }
        }
    }

}
 


728x90

'안드로이드 > Kotlin 기능' 카테고리의 다른 글

[코틀린] PrefsHelper  (0) 2020.05.04
[코틀린] ViewPager 만들기  (0) 2020.04.24
[코틀린] webView 예제1  (0) 2020.04.20
Checking if a URL Exists in Kotlin  (0) 2020.04.17
Splash Screen with Kotlin  (0) 2020.04.09
블로그 이미지

Link2Me

,