코틀린 isNullOrBlank or isNullOrEmpty 테스트.


// 널 을 가지고 있는 스트링.
var nullString: String? = null

//공백체크.
println(nullString.isNullOrBlank()?.toString()) //output: true
//비어있는
println(nullString.isNullOrEmpty()?.toString()) //output: true

// 데이터를 가지고 잇는 스트링.
var helloString: String = "Hello"
println(helloString.isNullOrBlank()?.toString()) //output: false
println(helloString.isNullOrEmpty()?.toString()) //output: false

// 빈 문자열을 가지고 있는 스트링.
var blankString: String = ""
println(blankString.isNullOrBlank()?.toString()) //output: true
println(blankString.isNullOrEmpty()?.toString()) //output: true

// 공백을 가지고 있는 스트링.
var emptyString: String = " "
println(emptyString.isNullOrBlank()?.toString()) //output: true
println(emptyString.isNullOrEmpty()?.toString()) //output: false

// 공백을 가지고 있는 스트링.
var emptyString2: String = " ㅇㅇㅇ"
println(emptyString2.isNullOrBlank()?.toString()) //output: false
println(emptyString2.isNullOrEmpty()?.toString()) //output: false


'Kotlin > study' 카테고리의 다른 글

Retrofit, RxJava, AndroidProject  (0) 2019.01.30
코틀린 클래스.  (0) 2018.10.04
코틀린 apply,let 함수  (0) 2018.08.24

코틀린 리사이클러뷰 예제



매인액티비티 생성.

MainActivity.kt

//////////////////////////////////////////////////////////////////////////////////////////


class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)


    }

}

//////////////////////////////////////////////////////////////////////////////////////////



Build.gradle(Module:app)에 com.android.support:recyclerview-v7 모듈 추가

//////////////////////////////////////////////////////////////////////////////////////////

dependencies {

    implementation fileTree(include: ['*.jar'], dir: 'libs')

    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

    implementation 'com.android.support:appcompat-v7:28.0.0'

    implementation 'com.android.support.constraint:constraint-layout:1.1.3'

    testImplementation 'junit:junit:4.12'

    androidTestImplementation 'com.android.support.test:runner:1.0.2'

    androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'

//리사이클러뷰 모듈 추가.

    implementation 'com.android.support:recyclerview-v7:28.0.0'

}

//////////////////////////////////////////////////////////////////////////////////////////


리사이클러뷰에 사용할 데이터 생성.


간단한 데이터 출력 하기위한 클래스 생성.

People.Kt

//////////////////////////////////////////////////////////////////////////////////////////

/**

 * 데이터 클래스 생성 및 초기화

 * 바로 생성자를 넣어서 만들어지게 구현.

 * 코틀린에서는 data class 를 지원 하며

 * java에서 처럼 toString 처리 하지 않아도 됨.

 */

data class People(val name: String, val age: String, val address: String)

//////////////////////////////////////////////////////////////////////////////////////////





리사이클러뷰에 보여줄 row layout 생성.


간단히 name, age, address 보여줌.


listview_row.xml

//////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.ConstraintLayout 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="wrap_content">



    <android.support.constraint.ConstraintLayout

        android:layout_width="match_parent"

        android:layout_height="wrap_content"

        android:layout_marginLeft="10dp"

        android:layout_marginTop="10dp"

        android:layout_marginRight="10dp"

        app:layout_constraintTop_toTopOf="parent">



        <TextView

            android:id="@+id/name"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:text="name"

            app:layout_constraintTop_toTopOf="parent" />


        <TextView

            android:id="@+id/age"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:text="age"

            app:layout_constraintTop_toBottomOf="@+id/name" />


        <TextView

            android:id="@+id/address"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:text="address"

            app:layout_constraintTop_toBottomOf="@+id/age" />



    </android.support.constraint.ConstraintLayout>

</android.support.constraint.ConstraintLayout>

//////////////////////////////////////////////////////////////////////////////////////////



뷰홀더 클래스 생성. RecyclerView.ViewHolder 상속

TestHolder_01.kt

//////////////////////////////////////////////////////////////////////////////////////////

/**생성자 지정 , 상위클래스 view 넘겨줌.  super(itemView);*/

class TestHolder_01(itemView: View) : RecyclerView.ViewHolder(itemView) {

    // 뷰 홀더를 상속 받고나면 생성자에서 상위 홀더에 view 를 전달.

    

    

    val name: TextView

    val age: TextView

    val address: TextView

    

    

    /**

     * 코틀린사용한 초기화

     * 초기화 블럭.

     */

    init {

        this.name = itemView.findViewById(R.id.name)

        this.age = itemView.findViewById(R.id.age)

        this.address = itemView.findViewById(R.id.address)

    }


    

    /**팩토리 함수 */

    companion object {

        fun newInstance(viewGroup: ViewGroup): TestHolder_01 {

            val view = LayoutInflater.from(viewGroup.context).inflate(R.layout.listview_row, viewGroup, false)

            return TestHolder_01(view)

        }

    }


    fun onBindView(position: Int, list: ArrayList<People>) {

        // 데이터를 화면에 그리기.

        name.text = list[position].name

        age.text = list[position].age

        address.text = list[position].address

    }

}

//////////////////////////////////////////////////////////////////////////////////////////





리사이클러뷰 아답터 생성.

TestAdapter_01.kt

//////////////////////////////////////////////////////////////////////////////////////////

/**생성자에서 리스트를 받아옴.*/

class TestAdapter_01(val list: ArrayList<People>) : RecyclerView.Adapter<TestHolder_01>() {



    override fun onCreateViewHolder(p0: ViewGroup, p1: Int): TestHolder_01 {

        //팩토리함수를 이용한 뷰홀더 생성.

        return TestHolder_01.newInstance(p0)

    }


    override fun getItemCount(): Int {

        return list.size

    }


    override fun onBindViewHolder(p0: TestHolder_01, p1: Int) {

        // 홀더에 정의된 함수로 뷰 그리기

        p0.onBindView(p1, list)

    }

}

//////////////////////////////////////////////////////////////////////////////////////////


activity_main.xml

//////////////////////////////////////////////////////////////////////////////////////////

<?xml version="1.0" encoding="utf-8"?>

<android.support.constraint.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">


    <android.support.v7.widget.RecyclerView

        android:id="@+id/recyclerView"

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        app:layoutManager="android.support.v7.widget.LinearLayoutManager">


    </android.support.v7.widget.RecyclerView>


</android.support.constraint.ConstraintLayout>

//////////////////////////////////////////////////////////////////////////////////////////



MainActivity.kt

//////////////////////////////////////////////////////////////////////////////////////////

class MainActivity : AppCompatActivity() {


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(R.layout.activity_main)

//UI그리기

        setupUI()

    }


//data 생성

    fun setData(): ArrayList<People> {


        val list = arrayListOf<People>()

        for (i in 0 until 30) {

            list.add(People("$i name", "$i age", "$i address"))

        }

        list.forEach {

            Log.e("log", "$it")

        }

        return list

    }


    fun setupUI() {

    //아답터 등록 후 끝.

        recyclerView.adapter = TestAdapter_01(setData())

        

    }

}


//////////////////////////////////////////////////////////////////////////////////////////



안드로이드 추상 클래스 이용한 퍼미션 권한 설정. 2-2

에서 만든 java 소스를 코틀린으로 변환 수정



BaseActivity.kt 

//////////////////////////////////////////////////////////////////////////////////////////

abstract class BaseActivity : AppCompatActivity() {


    abstract val setLayout: Int


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)


        setContentView(setLayout)

    }



    private val PERMISSION_REQUEST: Int = 1000



    /**인터페이스 등록.*/

    interface PermissionCheckListener {

        fun permissionCheckFinish()

    }


    /**클래스 내 사용할 퍼미션 체크 리스너 (setter 구현 방법이 특이함.)

     * 온 크레딧 바로 아래 생성 되어야 한다

     * */

    lateinit var permissionCheckListener: PermissionCheckListener


    /**

     * 스트링 배열로 퍼미션 체크.

     */

    fun permissionCheck(strings: Array<String>): Boolean {

        // 변수 사용시 리턴 타입 지정.

        // var check = false


        // 변수 사용안하고 바로 리턴시켜 버림.


        //안드로이드 마시멜로 이후 퍼미션 체크.

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

            for (i in 0 until strings.size) {

                if (ContextCompat.checkSelfPermission(this, strings[i]) == PackageManager.PERMISSION_DENIED) {

                    ActivityCompat.requestPermissions(this, strings, PERMISSION_REQUEST)

                    // check = true

                    // break

                    return true

                }

            }

        }

        //return check

        return false

    }



    /**

     * 거부를 했을때 처리

     * 다시보지 않기 체크 후 거부를 하면 설정에서 권한을 허용하도록 요청.

     * 허용하지 않을 경우 앱 사용 을 못함..

     * 처리를 잘못하면 무한 반복할 경우가 생김.

     */

    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {


        super.onRequestPermissionsResult(requestCode, permissions, grantResults)


        if (requestCode == PERMISSION_REQUEST) {

            //안드로이드 마시멜로 이후 퍼미션 체크.

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {

                for (i in grantResults.indices) {

                    if (grantResults[i] == 0) {

                        if (grantResults.size == i + 1) {

                            permissionCheckListener?.permissionCheckFinish()

                        }

                    } else {


                        // 거부한 이력이 있으면 true를 반환한다.

                        if (shouldShowRequestPermissionRationale(permissions[i])) {

                            ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST)

                            

                        } else {


                           AlertDialog.Builder(this)

                                .setTitle("다시보지않기 클릭.")

                                .setMessage(permissions[i] + " 권한이 거부되었습니다 설정에서 직접 권한을 허용 해주세요.")

                                .setNeutralButton("설정") { dialog, which ->


                                    val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS)

                                    intent.data = Uri.parse("package:$packageName")

                                    startActivity(intent)

                                    Toast.makeText(applicationContext, "권한 설정 후 다시 실행 해주세요.", Toast.LENGTH_SHORT).show()

                                    finish()

                                }

                                .setPositiveButton("확인") { dialog, which ->

                                    Toast.makeText(applicationContext, "권한 설정을 하셔야 앱을 사용할 수 있습니다.", Toast.LENGTH_SHORT)

                                        .show()

                                    finish()

                                }

                                .setCancelable(false)

                                .create().show()

                        }// shouldShowRequestPermissionRationale /else

                    } // 권한 거절

                } // for end

            }//Build.VERSION.SDK_INT  end

        }//requestCode  end

    }


}

//////////////////////////////////////////////////////////////////////////////////////////




MainActivity에서 사용 방법.


Manifest에 

<uses-permission android:name="android.permission.CAMERA" />

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

퍼미션 등록 확인.


MainActivity.kt

//////////////////////////////////////////////////////////////////////////////////////////

class MainActivity : BaseActivity() {


    override val setLayout = R.layout.activity_main


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)


        permissionCheckListener = object : PermissionCheckListener {

            override fun permissionCheckFinish() {

                Log.e("log", "start Activity")

            }

        }


        if (permissionCheck(arrayOf(Manifest.permission.CAMERA, Manifest.permission.WRITE_EXTERNAL_STORAGE))) {

            return

        }

        permissionCheckListener?.permissionCheckFinish()

    }

}



//////////////////////////////////////////////////////////////////////////////////////////


MVP 패턴.





MODEL : 데이터 처리.


VIEW : 뷰 


PRESENT : MODEL과 VIEW 사이의 매개체



MVP 패턴의 동작


VIEW 에서 사용자 이벤트 수신

VIEW 에서 PRESENTER 이벤트 호출

PRESENTER 에서 MODEL 데이터 요청

MODEL 에서 PRESENTER 로 데이터 전달

PRESENTER 에서 전달받은 데이털 처리 후 VIEW 업데이트 요청

VIEW 에서 화면 업데이트



구현 방법


interface Contact


inner interface View

inner interface Present 


View 에서 처리할 이벤트 선언

Present 에서 처리할 이벤트 선언



View를 상속받는 Activiry 구현

Present를 상속받는 Presenter 구현


Presenter 에서 Model로 데이터 요청.(통신을 통한 서버 데이터 요청)


Model 에서 Presenter 가 요청한 데이터를 전달 후 Presenter에서 데이터 가공 후 View에 업데이트 요청


View 로 가공된 데이터를 가지고 화면 업데이트. 




MainActivityContract


MainActivity  MainActivityContract.View 상속


MainActivityPresenter MainActivityContract.Present 상속


MainActivityDataAction Present에서 데이터 요청




코틀린으로 코드 구현.




/**

 * 액티비티 상속 클래스

 */

abstract class BaseActivity : AppCompatActivity() {


    /**레이아웃 뷰 추상화 등록*/

    protected abstract val layoutId: Int


    override fun onCreate(savedInstanceState: Bundle?) {

        super.onCreate(savedInstanceState)

        setContentView(layoutId)

    }

}




/**

 * mvp 계약자 정의

 */

interface MainActivityContract {

    /**

     * 단순 화면 처리

     * 액티비이에서 뷰 구현

     */

    interface View {


        /** 뷰에 프레젠터 등록.*/

        val presenter: Present


        fun buttonClickChangeUI(count: Int)


    }


    /**

     * 프레젠터 뷰와 모델의 데이터 처리

     * 프레젠터 클래스를 생성하여 인터페이스 구현.

     */

    interface Present {


        /**

         * 프레젠터에 뷰 등록

         *

         */

        var view: View?


        /** 전달받을 뷰를 등록함.*/

        fun attachView(view: View)


        /** 뷰 해제*/

        fun detachView()



        fun buttonClickCountUp(count: Int)

    }

}


/**

 * MainActivity

 * 

 */

class MainActivity : BaseActivity(), MainActivityContract.View {


    /**BaseActivity에서 상속받은 변수. */

    override val layoutId = R.layout.activity_main

    /**뷰에 지정한 프레젠터 등록.*/

    override val presenter: MainActivityContract.Present = MainActivityPresenter()


    override fun onCreate(savedInstanceState: Bundle?) {


        super.onCreate(savedInstanceState)

        presenter.attachView(this)

        buttonEvent()

    }



    fun buttonEvent() {


        button_Click.setOnClickListener(View.OnClickListener {

            Log.w("bear", "buttonclick")

            presenter.buttonClickCountUp(count)

        }

        )

    }


    var count = 0

    override fun buttonClickChangeUI(count: Int) {

        this.count = count

        textview.text = "${this.count}"

    }

}




/**

 * 데이터를 처리하는 프레젠터

 * 처리된 결과를 등록한 뷰에 전달.

 */

class MainActivityPresenter : MainActivityContract.Present {


    /**뷰 초기화*/

    override var view: MainActivityContract.View? = null


    /**뷰 지정.onCreate 에 등록*/

    override fun attachView(view: MainActivityContract.View) {

        this.view = view

    }


    /**뷰 해제*/

    override fun detachView() {

        this.view = null

    }


    override fun buttonClickCountUp(count: Int) {

        view?.buttonClickChangeUI(count + 1)

    }

}






이런식으로 사용이 가능하다.





+ Recent posts