프로그램에서 함수는 스택구조이다.
0->1->2->3->3->2->1->0

MVP 패턴 
모델, 뷰, 프레젠터


Model : 데이터 처리
View : xml을 가지는 액티비티 또는 프래그먼트가 됨.
Presenter : 뷰와 모델을 연결해주는 인터페이스


view    <->  Presenter <-> Model 
뷰와 프레젠터는 화면을 그리기 위한 처리만한다.

프레젠터와 모델은 데이터 처리만 한다.(추가, 갱신, 삭제)

프레젠터가 모델에 데이터를 처리 요청을 하고 값을 돌려 받으면
프레젠터는 뷰에게 값만 전달하여 화면 변경을 한다.

액션(서버통신) 또는 데이터 가져오는 클래스가 모델이 된다.


소스예제.


1. 데이터 클래스 생성.
/**데이터를 생성하는 클래스.*/
class MakeData {

/**어레이리스트 형식으로 객체생성*/
    fun makeList(): MutableList {

        var data = mutableListOf()
        for (i in 0 until 50) {
            data.add("$i element row")
        }
        return data
    }

}

mvp 패턴에서 사용할 Base interface 등록

2. 인터페이스 생성.
/**뷰에서 구현할 인터페이스.*/
interface BaseView {
    /**제네릭으로 상속받을 프레젠터 클래스.*/
    val presenter: T
}

3. 인터페이스 생성.
/**프레젠터에서 구현할 인터페이스*/
interface BasePresent {
    /**
     * 제네릭으로 상속받을 뷰 클래스.
     * 최초 객체 생성이 null로 생성되므로 null type 선언.
     */
    val view: T?
}

4. 계약자 인터페이스 생성.
/**아답터에서사용할 계약자 인터페이스 */
interface MainActivityAdapterContract {

/**아답터뷰*/
    interface View {
     /**리스트 갱신을 위한 데이터 갱신*/
        fun changeData(data: MutableList)
    }

}

5. 계약자 인터페이스 생성.
/**
 * mvp 패턴에서 사용할 계약자 인터페이스 생성.
 * 계약자의 프레젠터를 상속 받음.
 * 등록한 뷰에는 UI처리만 하도록 한다. 화면에 그릴 데이터의 결과값만 던저준다. 
 */
/**mvp 패턴에서 사용할 계약자 인터페이스 생성.*/
interface MainActivityContract {

    /**BaseView 를 상속받은 인터페이스 제네릭으로 인터페이스(Present)를 넘겨줌*/
    interface View : BaseView {
        /**
         * 뷰는 데이터 처리를 하지 않으며 데이터의 결과만 전달한다.
         * 뷰는 프레젠터에서 넘겨받은 결과로 UI의 변경만 한다.
         */
    }

    /**BasePresent를 상속받은 인터페이스 제네릭으로 인터페이스(View)를 넘겨줌*/
    interface Present : BasePresent {
        /**
         * 프레젠터는 데이터를 처리한다.
         * 
         */

        fun attachView(view: View)
        /**뷰 해제.*/
        fun detachView()
        
        /**데이터 갱신위한 아답터뷰 등록*/
        var adapterView: MainActivityAdapterContract.View?
/**데이터 클래스에서 값 가져오기.*/
        fun getData()
        
    }
}

6. 리사이클러뷰 홀더 생성.
/**리사이클러뷰 각 항목 그리기 위한 홀더 생성.*/
class MainActivityViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView),
    LayoutContainer {

    companion object {
        fun newInstance(parent: ViewGroup): MainActivityViewHolder {
            val view = LayoutInflater.from(parent.context).inflate(R.layout.datalayout_row, parent, false)
            return MainActivityViewHolder(view)
        }
    }

    fun onBindView(str: String) {
        textView_Row.text = str
    }

}

7. 리사이클러뷰 아답터 
/** 아답터에 대한 MVP */
class MainActivityAdapter : RecyclerView.Adapter(), MainActivityAdapterContract.View {

    private var data: MutableList = mutableListOf()
        private set(value) {
            field = value
            notifyDataSetChanged()
        }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MainActivityViewHolder {
        return MainActivityViewHolder.newInstance(parent)
    }

    override fun getItemCount(): Int {
        return data.size
    }

    override fun onBindViewHolder(holder: MainActivityViewHolder, position: Int) {
        holder.onBindView(data[position])
    }

    override fun changeData(data: MutableList) {
        this.data=data
    }
}

8. 액티비티 구현을 위한 상속 액티비티
/**상속 액티비티*/
abstract class BaseActivity : AppCompatActivity() {

    protected abstract val layoutId: Int

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(layoutId)
    }
}

9. 구현 액티비티 
/**
 * 액티비티가 mvp 패턴에서 View 해당한다. View엔 데이터 처리를 하지않고
 * 데이터 처리를 위한 작업은 presenter에 요청한다.
 */
class MainActivity : BaseActivity(), MainActivityContract.View {


    override val layoutId = R.layout.activity_main

    override val presenter: MainActivityContract.Present = MainActivityPresenter()


    private lateinit var mainActivityAdapter: MainActivityAdapter

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        presenter.attachView(this)

        setupUI()

        presenter.adapterView = mainActivityAdapter

        //프레젠터에 데이터를 요청.
        presenter.getData()
    }

    override fun onDestroy() {
        presenter.detachView()
        super.onDestroy()
    }

    private fun setupUI() {
        setupRecyclerView()
    }

    private fun setupRecyclerView() {
        mainActivityAdapter = MainActivityAdapter()
        recyclerView.adapter = mainActivityAdapter
    }

}

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

안드로이드 코틀린 프로젝트 디펜던시  (0) 2019.01.25
안드로이드 액티비티 및 프래그먼트.  (0) 2018.09.27
레트로핏, okhttp  (0) 2018.08.27
RxJava  (0) 2018.07.30


안드로이드 코틀린 프로젝트.


안드로이드 targetSdkVersion 26(Oreo[8.0]) 이상으로 설정해야한다.(정책)


//코틀린 추가 확장(안드로이드 리사이클러뷰 뷰홀더에 사용함 LayoutContainer 구현.)

androidExtensions {

    experimental = true

}




안드로이드 프로젝트에서 자주 사용하는 라이브러리 정리



안드로이드 라이브러리.

Project Structure 에서 Dependencies 선택 후 Library Dependency 클릭하여 라이브러리 추가.(타겟버전에 맞추어 추가함.)



통신관련 라이브러리.


* 레트로핏 : 안드로이드 통신 라이브러리.

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

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

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

   

/*레트로핏 지원 라이브러리*/    

// jsonData 형식을 클래스 객체형식으로 변환하여 준다.

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

implementation 'com.squareup.retrofit2:converter-gson:latest.version'


// Rxjava 타입을 지원한다.

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

implementation 'com.squareup.retrofit2:adapter-rxjava2:latest.version'

   

* okhttp : 안드로이드 통신 라이브러리.(레트포핏을 사용하면 okhttp 최신 버전이 들어있다)

// http,http2 통신라이브러리

// https://square.github.io/okhttp/ 

implementation 'com.squareup.okhttp3:okhttp:3.12.1'

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

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

implementation 'com.squareup.okhttp3:logging-interceptor:(insert latest version)'



* Gson : 안드로이드 json 파싱 라이브러리.

// 객체 형태로 데이터를 만들어 준다.

implementation 'com.google.code.gson:gson:2.8.5'




프로그래밍 라이브러리.

// binding :제본   bind : 묶다 


RxJava

– Reactive Extensions for the JVM – a library for composing asynchronous and event-based programs using observable sequences for the Java VM.

* RxJava : 반응형 프로그래밍 라이브러리

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

   implementation "io.reactivex.rxjava2:rxjava:2.x.y"


/*

* RxKotlin 과 RxAndroid 는 내부적으로 RxJava를 참조하나 최신 버전의 RxJava를 명확하게 정의하여 해당 라이브러리를 쓰도록 한다.

*/


RxKotlin

RxJava bindings for Kotlin(기본적으로 RxJava 를 가지고 있다.)

* RxKotlin :    안드로이드 코틀린에서 확장지원 라이브러리.(RxJava가 있어야 하며 버전에 맞게 설정해야한다.)

        // 안드로이드 프로젝트라면. RxAndroid 설정후 .

        // https://github.com/ReactiveX/RxKotlin

        implementation 'io.reactivex.rxjava2:rxkotlin:x.y.z'


RxAndroid

RxJava bindings for Android(기본적으로 RxJava 를 가지고 있다.)

* RxAndroid :  안드로이드 프로젝트에서 사용하기 위한 라이브러리.(RxJava가 있어야 한다.) 쓰레드 관련한 모듈을 제공한다.

       // https://github.com/ReactiveX/RxAndroid

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

       // Because RxAndroid releases are few and far between, it is recommended you also

       // explicitly depend on RxJava's latest version for bug fixes and new features.

       // (see https://github.com/ReactiveX/RxJava/releases for latest 2.x.x version)

       implementation 'io.reactivex.rxjava2:rxjava:2.x.x'

       

* RxBinding 를 사용하기 위한 추가 지원 라이브러리들.

//RxBinding : RxJava binding APIs for Android UI widgets from the platform and support libraries.

implementation 'com.jakewharton.rxbinding3:rxbinding:3.0.0-alpha2'

//

implementation 'com.jakewharton.rxbinding2:rxbinding-kotlin:2.1.0'

implementation 'com.jakewharton.rxbinding2:rxbinding-support-v4-kotlin:2.1.0'

implementation 'com.jakewharton.rxbinding2:rxbinding-appcompat-v7-kotlin:2.1.0'

implementation 'com.jakewharton.rxbinding2:rxbinding-design-kotlin:2.1.0'

implementation 'com.jakewharton.rxbinding2:rxbinding-recyclerview-v7-kotlin:2.1.0'

*RxPermission : 안드로이드 권한 라이브러리

//https://github.com/tbruyelle/RxPermissions

implementation 'com.tbruyelle.rxpermissions2:rxpermissions:0.9.5@aar'


* RxLifecycle : RxJava를 사용하면서 subscribe를 해제 하지 않으면 메모리릭이 발생될수도있기에 서브스크라이브 종료를 해주는 라이브러리.

// https://github.com/trello/RxLifecycle

implementation 'com.trello.rxlifecycle3:rxlifecycle:3.0.0'


// If you want to bind to Android-specific lifecycles

implementation 'com.trello.rxlifecycle3:rxlifecycle-android:3.0.0'


// If you want pre-written Activities and Fragments you can subclass as providers

implementation 'com.trello.rxlifecycle3:rxlifecycle-components:3.0.0'


// If you want pre-written support preference Fragments you can subclass as providers

implementation 'com.trello.rxlifecycle3:rxlifecycle-components-preference:3.0.0'


// If you want to use Android Lifecycle for providers

implementation 'com.trello.rxlifecycle3:rxlifecycle-android-lifecycle:3.0.0'


// If you want to use Kotlin syntax

implementation 'com.trello.rxlifecycle3:rxlifecycle-kotlin:3.0.0'


// If you want to use Kotlin syntax with Android Lifecycle

implementation 'com.trello.rxlifecycle3:rxlifecycle-android-lifecycle-kotlin:3.0.0'


// If you want to use Navi for providers

// DEPRECATED: Use rxlifecycle-android-lifecycle instead. This will be removed in a future release.

implementation 'com.trello.rxlifecycle3:rxlifecycle-navi:3.0.0'





추가지원 라이브러리.

* Realm : 객체중심의 데이터베이스 라이브러리.

// https://realm.io/docs/java/latest


* glide : 이미지 로딩 라이브러리

   repositories {

       mavenCentral()

     google()

           }


     dependencies {

     implementation 'com.github.bumptech.glide:glide:4.8.0'

     annotationProcessor 'com.github.bumptech.glide:compiler:4.8.0'

     }


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

MVP 패턴  (0) 2019.04.25
안드로이드 액티비티 및 프래그먼트.  (0) 2018.09.27
레트로핏, okhttp  (0) 2018.08.27
RxJava  (0) 2018.07.30


안드로이드 액티비티 & 프래그먼트.



액티비티 : 하나의 뷰(xml)에 하나의 액티비티만 사용.




프래그먼트 : 하나의 액티비티에 다수의 프래그먼트 사용.{


.add() tag : 나중에 프래그먼트를 검색하기 위한 선택적 태그 이름. (findFragmentByTag( tag ))


.replace() : 기존의 프래그먼트를 제거하고 새로운 프래그먼트로 대체.


.addToBackStack() name : 트랜잭션이 커밋 된 후에 기억되고 나중에 스택에서 꺼내 졌을때 트랜잭션을 되돌릴 것을 의미.  


findFragmentByTag는 add / replace 메서드 또는 addToBackStack 메서드로 추가 된 태그를 검색합니다.

}



프래그먼트




    /**

     * add : 프래그먼트를 추가 합니다. 프래그먼트는 선택적으로 뷰를 가질 수 있습니다.

     *id: Int, : 레이아웃 지정. (xml)

     * fragment: Fragment, : 화면에 보여질 프래그먼트.

     * tag: String? = null, : 프래그먼트 태그 지정.(findFragmentByTag (tag) 로 검색)

     * backStackCheck: Boolean = false : 트랜잭션 커밋 후 스택에 저장된 후 상위 프래그먼트가 제거되면 스택에 저장된

     * 프래그먼트를 불러온다.

     *

     * findFragmentByTag는 add / replace 메서드 또는 addToBackStack 메서드로 추가 된 태그를 검색합니다.

     */

    protected fun addFragment(id: Int, fragment: Fragment, tag: String? = null, backStackCheck: Boolean = false) {



        if (backStackCheck) {

            supportFragmentManager

                    .beginTransaction()

                    .add(id, fragment, tag)

                    .addToBackStack(tag)

                    .commit()

        } else {

            supportFragmentManager

                    .beginTransaction()

                    .add(id, fragment, tag)

                    .commit()

        }

    }



    /**

     * replace : 기존의 프래그먼트를 제거하고 새로운 프래그먼트로 대체 합니다. 프래그먼트는 선택적으로 뷰를 가질 수 있습니다.

     *id: Int, : 레이아웃 지정. (xml)

     * fragment: Fragment, : 화면에 보여질 프래그먼트.

     * tag: String? = null, : 프래그먼트 태그 지정.(findFragmentByTag (tag) 로 검색)

     * backStackCheck: Boolean = false : 트랜잭션 커밋 후 스택에 저장된 후 상위 프래그먼트가 제거되면 스택에 저장된

     * 프래그먼트를 불러온다.

     *

     * findFragmentByTag는 add / replace 메서드 또는 addToBackStack 메서드로 추가 된 태그를 검색합니다.

     */

    protected fun replaceFragment(id: Int, fragment: Fragment, tag: String? = null, backStackCheck: Boolean = false) {


        if (backStackCheck) {

            supportFragmentManager

                    .beginTransaction()

                    .replace(id, fragment, tag)

                    .addToBackStack(tag)

                    .commit()

        } else {

            supportFragmentManager

                    .beginTransaction()

                    .replace(id, fragment, tag)

                    .commit()

        }

    }


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

MVP 패턴  (0) 2019.04.25
안드로이드 코틀린 프로젝트 디펜던시  (0) 2019.01.25
레트로핏, okhttp  (0) 2018.08.27
RxJava  (0) 2018.07.30

레트로핏 사용방법.


사용하는 방법은 대충 알겄는디 ??? 

정작 글로 쓸려고하니 뭔가 막히는 구문이 있다.



안드로이드에서 사용되는 여러 다양한 통신 기법 중 많이 사용되고 있는 레트로핏 통신방법


먼저 프로젝트를 생성한 다음 앱 그래들에 모듈을 포함시켜 준다.



GRADLE


//레트로핏 

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

// 레트로핏 gson converter

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

// gson

implementation 'com.google.code.gson:gson:2.8.2'


//okhttp 로그 인터셉터

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


퍼미션에서 인터넷 권한을 준다.





//여기에 접속해서 필요한 데이터를 가져온다.

https://api.github.com/users/bearkinf



gson으로 데이터받을 클래스 생성.


/**유저 정보 관련 데이터 클래스*/

public class GithubUser {

    

    private String login;

    private String id;

    private String url;

    private String name;


    public String getLogin() {

        return login;

    }


    public void setLogin(String login) {

        this.login = login;

    }


    public String getId() {

        return id;

    }


    public void setId(String id) {

        this.id = id;

    }


    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 class GithubRepos {

    

    private String name;

    private String full_name;

    private String html_url;


    public String getName() { return name;  }


    public void setName(String name) {

        this.name = name;

    }


    public String getFull_name() {

        return full_name;

    }


    public void setFull_name(String full_name) {

        this.full_name = full_name;

    }


    public String getHtml_url() {

        return html_url;

    }


    public void setHtml_url(String html_url) {

        this.html_url = html_url;

    }

}




접속하기 위한 인터페이스를 만들고


public interface GithubConnectService {


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

    Call<List<GithubUser>> getUser(@Path("user") String user);


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

    Call<List<GithubRepos>> getUserRepos(@Path("user") String user);

}



인터페이스르 사용하여 접속할 클래스 메서드를 만든다.


public class GithubConnectionApi {


    /**connection interface 리턴받음*/

    public static GithubConnectService setConnect() {


        OkHttpClient okHttpClient = new OkHttpClient.Builder()

                //통신시 request 및 response 상태 표시

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

                .build();


        return new Retrofit.Builder()

                .baseUrl("https://api.github.com/")

                // gson 데이터 파싱 메서드

                .addConverterFactory(GsonConverterFactory.create())

                // 통신 클라이언트 지정

                .client(okHttpClient)

                .build()

                // 통신 인터페이스 등록

                .create(GithubConnectService.class);

    }

}



MainActivity에서 통신 할 방법을 구현 한다.

public class MainActivity extends AppCompatActivity {


    Button button;

    TextView textview;


    @Override

    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.activity_main);


        textview = findViewById(R.id.textview);

        button = findViewById(R.id.button);



        button.setOnClickListener(new View.OnClickListener() {

            @Override

            public void onClick(View v) {


                Log.d("bear", "버튼 클릭");


                Call<GithubUser> githubUserCall = GithubConnectionApi.setConnect().getUser("bearkinf");


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

                    @Override

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


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


                        GithubUser user = response.body();

                        

                        Log.w("bear", "getId : " + user.getId());

                        Log.w("bear", "getLogin : " + user.getLogin());

                        Log.w("bear", "getName : " + user.getName());

                        Log.w("bear", "getUrl : " + user.getUrl());

                    }


                    @Override

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

                        t.printStackTrace();

                    }

                });

            }

        });

    }

}





안드로이드 4.4.4버전에서 ssl 관련 통신 에러 발생함.


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

MVP 패턴  (0) 2019.04.25
안드로이드 코틀린 프로젝트 디펜던시  (0) 2019.01.25
안드로이드 액티비티 및 프래그먼트.  (0) 2018.09.27
RxJava  (0) 2018.07.30

RxJava



함수형 프로그래밍, 비동기 작업, 서버연동, 옵저버 패턴, 마블 다이어그램.

학습 곡선이 높다고 표현한다. 어떤식으로 작업을 해야 쉽게 이해가 될 수 있을까?



기본 


Observable : 데이터 생성을 위한 시작 클래스. 정적 팩토리함수로 인스턴스를 생성. 


just       : 데이터를 발행하는 정적팩토리 함수. 

     데이터를 발행하려는 메서드.하나의 인자 또는 최대 10개 까지의 같은 타입의 인자를 받음.

             subscribe()를 호출해야 실제 데이터 발행이 진행됨.


subscribe  : 데이터를 구독하는 함수. Observable에 데이터를 발행하라고 요구 (이함수가 없으면 RxJava 가 실해되지 않는다.)



Observable의 팩토리 함수 


create(), just(), from(), 

fromArray(), fromIterable(), fromCallable(), fromFuture(),

interval(), range(), timer(), defer()




Single : 오직 1개의 데이터만 발행하도록 한정됨.

  보통 결과가 유일한 서버api를 호출할때 사용.

  배열 및 리스트로 값을 받아도 1번의 값만 동작.



Flowable : 뜨거운 Observable 에서 데이터를 처리할때 배압을 고려할때 사용.

           배압은 Observable에서 테이타를 발행하는 속도와 구독자의 처리하는 속도의 차이가 발생할때 사용.

   Observable과 같은 방법으로 사용 하여도 된다.




기본 예제


   //자바 8 메서드 레퍼런스활용

   Observable.just("start Rxjava", "Rxjava end").subscribe(System.out::println);


   //람다식 적용.

   Observable.just("start Rxjava", "Rxjava end").subscribe(

           s -> {

               System.out.println("실행결과 : " + s);

       }

   );


   // 람다식 적용안함.

   Observable.just("start Rxjava", "Rxjava end").subscribe(new Consumer<String>() {

       @Override

       public void accept(String s) throws Exception {


           System.out.println("실행결과 : " + s);


       }

   });


   Single.just("fsdjaklfjasdklf").subscribe(System.out::println);


   Flowable.just("start Rxjava", "Rxjava end").subscribe(System.out::println);




연산자 활용


interval() : 일정시간 간격으로 데이터 흐름을 생성.

     주어진 시간을 간격으로 0부터 1씩 증가하는 Long 객체를 발행.



















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

MVP 패턴  (0) 2019.04.25
안드로이드 코틀린 프로젝트 디펜던시  (0) 2019.01.25
안드로이드 액티비티 및 프래그먼트.  (0) 2018.09.27
레트로핏, okhttp  (0) 2018.08.27

+ Recent posts