/**
 * 리사이클러뷰 아답터를 상속받는 아답터
 * 데이터 초기화.
 */
class CustomAdapter(private val dataSet: Array) :
        RecyclerView.Adapter() {

    /**
     * Provide a reference to the type of views that you are using (custom ViewHolder)
     */
    class ViewHolder(v: View) : RecyclerView.ViewHolder(v) {
        val textView: TextView

        /**홀더 초기화.*/
        init {
            // Define click listener for the ViewHolder's View.
            v.setOnClickListener { Log.d(TAG, "Element $adapterPosition clicked.") }
            textView = v.findViewById(R.id.textView)
        }
    }

    // Create new views (invoked by the layout manager)
    override fun onCreateViewHolder(viewGroup: ViewGroup, viewType: Int): ViewHolder {
        // Create a new view.
        val v = LayoutInflater.from(viewGroup.context)
                .inflate(R.layout.text_row_item, viewGroup, false)

        return ViewHolder(v)
    }

    // Replace the contents of a view (invoked by the layout manager)
    override fun onBindViewHolder(viewHolder: ViewHolder, position: Int) {
        Log.d(TAG, "Element $position set.")

        // Get element from your dataset at this position and replace the contents of the view
        // with that element
        viewHolder.textView.text = dataSet[position]
    }

    // Return the size of your dataset (invoked by the layout manager)
    override fun getItemCount() = dataSet.size

    /**로그켓 사용하는 태그 초기화.*/
    companion object {
        private val TAG = "CustomAdapter"
    }
}



레트로핏 사용.(java)


안드로이드 프로젝트 생성.


gradle dependencies setting.


app gradle.


dependencies {


    // 인터넷 연결 http 프로토콜

    // https://square.github.io/retrofit/

    // okhttp 를 포함하고 있다.

    implementation 'com.squareup.retrofit2:retrofit:2.5.0'


    // https://github.com/square/retrofit/tree/master/retrofit-converters/gson

    // gson 라이브러리를 포함하고 있다.

    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'


    // http 통신시 로그 보기위한 것.

    // https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor

    // okhttp 를 포함하고 있다.

    implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'



}

레트로핏을 사용할 기본 조건은 되었고.

레트로핏으로 통신을 할수있는 인터페이스 연결할 클래스 생성.

레트로핏은 http api를 인터페이스 형태로 사용한다.



public class GithubUser {



    private String login;

    private String url;

    private String name;

    private String location;

    private String repos_url;


    public String getLogin() {

        return login;

    }


    public void setLogin(String login) {

        this.login = login;

    }


    public String getUrl() {

        return url;

    }


    public void setUrl(String url) {

        this.url = url;

    }


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public String getLocation() {

        return location;

    }


    public void setLocation(String location) {

        this.location = location;

    }


    public String getRepos_url() {

        return repos_url;

    }


    public void setRepos_url(String repos_url) {

        this.repos_url = repos_url;

    }


    @Override

    public String toString() {

        return "login :" + login + ", url :" + url + ", name :" + name + ", location : " + location + ", repos_url :" + repos_url;

    }

}




public class GithubUserRepository {


    private String name;

    private String html_url;

    private String language;


    public String getName() {

        return name;

    }


    public void setName(String name) {

        this.name = name;

    }


    public String getHtml_url() {

        return html_url;

    }


    public void setHtml_url(String html_url) {

        this.html_url = html_url;

    }


    public String getLanguage() {

        return language;

    }


    public void setLanguage(String language) {

        this.language = language;

    }



    @Override

    public String toString() {

        return "name : " + name + ", html_url : " + html_url + ", language : " + language;

    }

}





public interface GithubService {


    @GET("users/{user}")

    Call<GithubUser> getGithubUser(@Path("user") String userName);


    @GET("users/{user}/repos")

    Call<List<GithubUserRepository>> getGithubUserRepository(@Path("user") String userName);

}




ApiConnection 클래스 생성.

실제 통신을 담당할 retrofit 객체를 생성한다.


public class ApiConnection {


    private Retrofit retrofit;


    private final String baseUrl = "https://api.github.com";


    /**

     * 생성자.

     */

    private ApiConnection() {


        OkHttpClient httpClient = new OkHttpClient.Builder()

                .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))

                .build();


        this.retrofit = new Retrofit.Builder()

                .baseUrl(baseUrl)

                // 내려받는 데이터를 gson 형식으로 데이터 변환

                .addConverterFactory(GsonConverterFactory.create())

                .client(httpClient)

                .build();

    }

        /**

     * 2. 싱글턴 패턴 구현.

     */

    private static final ApiConnection INSTANCE = new ApiConnection();


    public static ApiConnection getInstance() {

        return INSTANCE;

    }


    /**

     * interface  리턴.

     */

    public GithubService getRetrofitService() {

        return retrofit.create(GithubService.class);

    }

}





    MainActivity 에서


    void connection_01() {


        Call<GithubUser> result = ApiConnection.getInstance().getRetrofitService().getGithubUser("bearkinf");


        result.enqueue(new Callback<GithubUser>() {

            @Override

            public void onResponse(Call<GithubUser> call, Response<GithubUser> response) {


                Log.w("LOG","GithubUser : " + response.body());

            }


            @Override

            public void onFailure(Call<GithubUser> call, Throwable t) {


            }

        });

    }



oncreate()에서 함수를 호출하면 깃허브에서 내용을 가져온다.






레트로핏을 이용한 통신 프로젝트에 RxJava 넣기..



라이브러리 추가.



dependencies {

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

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

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

    implementation 'com.android.support:support-v4:28.0.0'

    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.github.bearkinf:AndroidLogPrintUtil_Java:1.1.1'


    // 인터페이스를 통해 인터넷 연결을 가지고 있다.

    // https://square.github.io/retrofit/

    implementation 'com.squareup.retrofit2:retrofit:2.5.0'

    // https://github.com/square/retrofit/tree/master/retrofit-converters/gson

    implementation 'com.squareup.retrofit2:converter-gson:2.5.0'

    // http 통신시 로그 보기위한 것.

    // https://github.com/square/okhttp/tree/master/okhttp-logging-interceptor

    implementation 'com.squareup.okhttp3:logging-interceptor:3.10.0'


    // Rxjava 타입을 지원한다.

    // https://github.com/square/retrofit/tree/master/retrofit-adapters/rxjava2

    // 자체적으로 RxJava 라이브러리를 가지고 있다.(최신 버전은 아님.)

    // adapter-rxjava2 내부적으로 rxjava를 참조하나, 버그가 수정된 최신버전의 rxjava를 명확히 정의하여 해당 library를 사용하게 하도록한다.

    implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'


    // https://github.com/ReactiveX/RxJava

    // 각각의 라이브러리가 RxJava를 참조하나 최신 라이브러리를 지정한다.

    // rxandroid 내부적으로 rxjava를 참조하나, 버그가 수정된 최신버전의 rxjava를 명확히 정의하여 해당 library를 사용하게 하도록한다.

    implementation "io.reactivex.rxjava2:rxjava:2.2.6"

    // https://github.com/ReactiveX/RxAndroid 스케줄러 관리 (쓰레드 관리

    // 자체적으로 RxJava 라이브러리를 가지고 있다.(최신 버전은 아님.)

    implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'


}




레트로핏 인터페이스에 RxJava 추가.

public interface GithubService {


    @GET("users/{user}")

    Call<GithubUser> getGithubUser(@Path("user") String userName);



    @GET("users/{user}/repos")

    Call<List<GithubUserRepository>> getGithubUserRepository(@Path("user") String userName);



    //RxJava 용 .Observable

    @GET("users/{user}")

    Observable<GithubUser> getGithubUser2(@Path("user") String userName);



    @GET("users/{user}/repos")

    Flowable<List<GithubUserRepository>> getGithubUserRepository2(@Path("user") String userName);


}



레트로핏 객체에 RxJava 를 사용하기 위해 아답터 추가.


public class ApiConnection {


    private Retrofit retrofit;


    private final String baseUrl = "https://api.github.com";


    /**

     * 생성자.

     */

    private ApiConnection() {


        OkHttpClient httpClient = new OkHttpClient.Builder()

                .addInterceptor(new HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))

                .build();


        this.retrofit = new Retrofit.Builder()

                .baseUrl(baseUrl)

                // 내려받는 데이터를 gson 형식으로 데이터 변환

                .addConverterFactory(GsonConverterFactory.create())

                // RxJava 를 사용하게되면 해당 아답터팩토리를 등록해야 한다.

                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())


                .client(httpClient)

                .build();

    }

        /**

     * 2. 싱글턴 패턴 구현.

     */

    private static final ApiConnection INSTANCE = new ApiConnection();


    public static ApiConnection getInstance() {

        return INSTANCE;

    }


    /**

     * interface  리턴.

     */

    public GithubService getRetrofitService() {

        return retrofit.create(GithubService.class);

    }

}


MainActivity에서 RxJava를 이용한 레트로핏 통신 코드 넣기.



    void connection_03() {


        /**

         * 람다식으로 사용을하려면 .

         *   compileOptions {

         *         sourceCompatibility JavaVersion.VERSION_1_8

         *         targetCompatibility JavaVersion.VERSION_1_8

         *   }

         *   넣어 주어야 한다.

         */

        LogPrintUtil.w("connection_03 start");

        ApiConnection.getInstance().getRetrofitService()

                .getGithubUser2("bearkinf")

                .subscribeOn(Schedulers.io())

                .observeOn(AndroidSchedulers.mainThread())

                .subscribe(githubUser -> {

                            LogPrintUtil.w("Observable    Data :" + githubUser);

                        }, throwable -> {


                        }

                );

    }


oncreate()에서 함수를 호출하면 깃허브에서 내용을 가져온다.




코틀린 버전은 코틀린 탭에서. 다시 작성.





코틀린 프로잭트 생성.


레트로핏 인터페이스 생성.

interface GithubService {



    @GET("users/{user}")

    fun getGithubUser(@Path("user") userName: String): Call<GithubUser>



    @GET("users/{user}/repos")

    fun getgithubUserRepository(@Path("user") userName: String): Observable<List<GithubUserRepository>>


}


레트로핏 객체 클래스 생성.

/**스테틱 클래스 생성.*/

object ApiConnection {


    private val BASE_URL = "https://api.gitHub.com"


    private val retrofit by lazy {

        val httpClient = OkHttpClient.Builder()

            .addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))

            .build()


        Retrofit.Builder()

            .baseUrl(BASE_URL)

            .addConverterFactory(GsonConverterFactory.create())

            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())

            .client(httpClient)

            .build()

    }

    val getRetrofitService = retrofit.create(GithubService::class.java)

}


MainActivity 에서 oncreate 에 함수 적용.

    private fun retrofitConnection_01() {


        val getGithubUser = ApiConnection.getRetrofitService.getGithubUser("bearkinf")


        getGithubUser.enqueue(object : Callback<GithubUser> {


            override fun onFailure(call: Call<GithubUser>, t: Throwable) {

            }


            override fun onResponse(call: Call<GithubUser>, response: Response<GithubUser>) {


                LogPrintUtil.w("response : ${response.body()}")


            }

        })

    }


    private fun retrofitConnection_02() {



        ApiConnection.getRetrofitService

            .getgithubUserRepository("bearkinf")

            .subscribeOn(Schedulers.io())

            .observeOn(AndroidSchedulers.mainThread())


            .subscribe({


                LogPrintUtil.w("RxJava : $it")


            }, {


            })



    }





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

isNullOrBlank or isNullOrEmpty  (0) 2018.11.19
코틀린 클래스.  (0) 2018.10.04
코틀린 apply,let 함수  (0) 2018.08.24


코틀린 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



코디네이터레이아웃 사용해서 스크롤시 

툴바 및 리사이클러뷰 스크롤시 최상단 및 최하단 터치 감지가 불량일 때가 있다.

최상단 혹은 최하단 스크롤 후 리스트 항목을 클릭이 되지 않아 두번 클릭해야하는데 


안드로이드 sdk 28에서는 정상동작 한다.

이전 버전에서 AppBarLayout.Behavior 에 버그가 있는듯.



android coordinatorlayout recyclerview scroll click

이렇게 검색하니 스택오버플로우에 올라온 글

Click not working on RecyclerView in CoordinatorLayout when scrolling



코틀린 코드만 입력


게시글 중 해당 링크가 있고 수정된 코드 java와 kotlin이 있음.


https://gist.github.com/erikhuizinga/edf408167b46eb5b1568424563ca4e59


kotlin

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

/**

 * Workaround AppBarLayout.Behavior for https://issuetracker.google.com/66996774

 *

 *

 * See https://gist.github.com/chrisbanes/8391b5adb9ee42180893300850ed02f2 for

 * example usage.

 *

 * Kotlinised by Erik Huizinga (github: @erikhuizinga).

 */

class FixAppBarLayoutBehavior(context: Context?, attrs: AttributeSet?) :

AppBarLayout.Behavior(context, attrs) {


override fun onNestedScroll(coordinatorLayout: CoordinatorLayout, child: AppBarLayout,

                            target: View, dxConsumed: Int, dyConsumed: Int, dxUnconsumed: Int,

                            dyUnconsumed: Int, type: Int) {

super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed,

dyUnconsumed, type)

stopNestedScrollIfNeeded(dyUnconsumed, child, target, type)

}


override fun onNestedPreScroll(coordinatorLayout: CoordinatorLayout, child: AppBarLayout,

                               target: View, dx: Int, dy: Int, consumed: IntArray, type: Int) {

super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type)

stopNestedScrollIfNeeded(dy, child, target, type)

}


private fun stopNestedScrollIfNeeded(dy: Int, child: AppBarLayout, target: View, type: Int) {

if (type == ViewCompat.TYPE_NON_TOUCH) {

val currOffset = topAndBottomOffset

if (dy < 0 && currOffset == 0 || dy > 0 && currOffset == -child.totalScrollRange) {

ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH)

}

}

}

}

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


코드 사용법 

AppBarLayout abl = findViewById(R.id.app_bar);

((CoordinatorLayout.LayoutParams) abl.getLayoutParams()).setBehavior(new FixAppBarLayoutBehavior());



xml 사용법

<android.support.design.widget.CoordinatorLayout 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">


    <android.support.design.widget.AppBarLayout

            android:id="@+id/app_bar"

            android:layout_height="..."

            android:layout_width="..."

            app:layout_behavior="your.package.FixAppBarLayoutBehavior">


    </android.support.design.widget.AppBarLayout>


    <!-- Content -->


</android.support.design.widget.CoordinatorLayout>






코틀린 리사이클러뷰 예제



매인액티비티 생성.

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()

    }

}



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


코틀린 클래스 정의



클래스는 class 키워드를 사용하여 선언하며, 자신의 맴버 속성(변수)과 맴버 함수를 가질 수 있다.

예 ) class Friend(/**생성자 */){

// 클래스 내부.

}


클래스 접근 제한자.


final

: 클래스에 지정하면 서브 클래스(상속)를 만들 수 없다.

코틀린에선 클래스와 클래스 맴버 모두 기본적으로 final 이다.


open 

: final과 반대의 의미를 가진다. open을 지정한 클래스는 서브 클래스(상속가능)를 만들 수 있고

클래스 맴버에 open을 지정하면 슈퍼 클래스의 맴버를 서브클래스에서 오버라이딩 할 수 있다.

abstract

: 클래스에 지정하면 추상 클래스가 되며 인스턴스를 생성할 수 없다.(자바와 동일)

추상 클래스는 대개 구현 코드가 없는 추상 함수를 맴버로 갖지만, 구현 코그가 있는 맴버 함수도 같이

가질 수 있다. abstract 맴버 함수는 기본적으로 open이다.


클래스 상속

open을 사용하여 클래스를 상속할 수 있다.

클래스의 맴버변수, 맴버함수에 open을 사용하여 상속할 수 있다.

이때 서브 클래스에서는 overrride 하여 사용한다.





인터페이스 정의.


interface 키워드 사용한다. 구현코드가 없는 추상 함수를 갖지만, 구현코드가 있는 확장함수도 포함할 수 있다.




추상클래스 정의.


abstract 키워드 사용한다. 추상클래스를 상속받은 서브 클래스에서는 추상클래스의 추상 함수들을 반드시 오버라이딩 해야한다.


통합내용.

인터페이스와 추상 클래스는 상호 운용이 가능하고 둘다 접근제한은 open 이다.

추상 클래스는 하나만 상속이 가능하며 인터패이스는 여러개 구현이 가능하다.


object.


객체선언

: 클래스 대신 객체를 선언하고 생성

하나의 인스턴스만 생성하고 공유하는 싱글톤 구현

클래스 처럼 객체 선언에도 속성과 함수  및 초기화 블럭 사용. 단 생성자는 가질 수 없다.


동반객체

: 클래스 내부에 객체 선언을 하면 포함하는 클래스의 인스턴스를 생성하지 않아도 객체의 선언의 함수와 속성

을 사용할 수 있다. (static)

최상위 수준 함수를 사용해도 동일한 효과를 볼 수 있다.

자바에서의 static 처럼 companion object 하면 된다.(private 한 팩토리 함수)


객체표현식

:익명 객체를 생성하는 방법(익명 내부 클래스.)

리스너에 사용시 

test.setOnClickListener(object : View.OnClickListener {

        override fun onClick(v: View?) {

                       

            }

        })

        이런식으로 사용.


중첩 클래스와 내부 클래스.

클래스 내부에 선언된 클래스

:중첩 클래스 - 중첩클래스는 외부 클래스의 맴버를 참조할 수 없다.

:내부 클래스 - 내부 클래스는 외부클래스의 맴버를 참조할 수 있다.

inner 키워드 사용.

대이터 클래스.

: data 키워드를 지정하면 데이터 클래스가 된다.

기본 생성자에 속성을 지정해야 한다.



































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

Retrofit, RxJava, AndroidProject  (0) 2019.01.30
isNullOrBlank or isNullOrEmpty  (0) 2018.11.19
코틀린 apply,let 함수  (0) 2018.08.24



apply 사용


apply()는

apply()함수를 호출하는 객체를 이어지는 블록의 리시버{블록 안에 메서드 및 속성에 바로 접근할 수 있도록 할 객체}

로 전달하고, 객체 자체를 반환


    val people01 = People().apply {

        //this: People        

        // People 객체를 넘겨주고 속성을 초기화 한 후 people01 변수에 값을 넣어준다.

        name = "ppppp"

        age = 20

    }

    

//run 사용법.    

    people01.run {

        println("${people01.afterAge(age!!)}")

    }

   


apply 를 사용하지 않는 동일한 코드는 다음과 같다.


    val people02 = People()

    people02.name = "ppp02"

    people02.age = 21



//data class 

//class

data class People(var name: String? = null,

                  var age: Int? = null) {

    var doubleAge: Int? = null

}


let 사용


let()는

let() 함수를 호출하는 객체를 인자로 받아서 넘기고 블록의 결과값을 리턴해준다.


  val people01 = People().apply {

        //this: People        

        name = "ppppp"

        age = 20

// age = 20     

    }

    

    //억지스럽지만 이렇게도 된다.

    people01.doubleAge = people01.age?.let { it + it }
















let 함수

fun main(args: Array<String>) {


    // 코틀린 let 함수

    // public inline fun <T, R> T.let(block: (T) -> R): R

    // T 를 인자로 받아서 블록안에 넘기고 (뭔가 작업을 하고)블록의 결과값 R을 리턴해줍니다.


    // 어떤 변수 또는 리턴값이 있는 메서드에서 let함수를 호출 하면

    // 호출한 변수값이나 메서드값을 {(블록)}의 인자로 넘기고

    // {} 안에 결과값을 반환한다.(retrun)


    // RxJava에서 map 함수와 비슷한 기능이랄까???


    var number100 = 100


    number100.let { it ->


        //필요에 위해 가공을 한다면 

        val returnCount = it + it


        //이렇게 값을 반환할 수 있다.

        return@let returnCount

    }

    // let 함수의 리턴받을 변수가 없기에 number100 은 아무 변화가 없다.

    println("number100 = $number100")



    //let 함수를 호출하면 

    number100 = number100.let { it ->


        //필요에 위해 가공을 한다면 

        val returnCount = it + it


        //이렇게 값을 반환할 수 있다.

        return@let returnCount

    }

    // number100 에 let 함수에서 받은 반환걊을 받아 값이 변하였다.

    println("number100 = $number100")

    //위 값에선 변화가 없지만.




    // 새로운 변수를 지정하고 let 함수를 리턴 받으면. 

    // 앞에서 number100은 200이 되었다.

    val number200 = number100.let { it ->

        val returnCount = it + it

        return@let returnCount

    }

    println("number200 = $number200")

    

    // 예제.

    fun doubleCount(count: Int): Int {

        return count * count

    }

    

    val data = doubleCount(2).let {

        // doubleCount 값 2*2를 인자로 받아서 

        // 4

        return@let it + it

        // 4+4 하고

        // val returnData = it + it

        // 그값을 리턴한다.

        // returnData

    }

    println("$data")


}



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

Retrofit, RxJava, AndroidProject  (0) 2019.01.30
isNullOrBlank or isNullOrEmpty  (0) 2018.11.19
코틀린 클래스.  (0) 2018.10.04

+ Recent posts