<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>개발자이야기</title>
    <link>https://webprogramcustom.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 11 Aug 2026 04:08:24 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>개발자가되고싶어</managingEditor>
    <item>
      <title>HTTP 와 HTTPS 차이점</title>
      <link>https://webprogramcustom.tistory.com/60</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;해당 내용에대한 질문을 받았다. 음.. 인증서를 발급받아 https를 적용하고 https는 암호화가 된다는것 정도는 알겠는데 구체적으로 왜 그래야 하는가를 잊었다.. 그래서 정리해보게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;512&quot; data-filename=&quot;https-g2f58deace_1280.jpg&quot; width=&quot;683&quot; height=&quot;273&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfXMMq/btrhGTcFRmg/FmerU3PPjk5UL8gVY5WRt0/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfXMMq/btrhGTcFRmg/FmerU3PPjk5UL8gVY5WRt0/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfXMMq/btrhGTcFRmg/FmerU3PPjk5UL8gVY5WRt0/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbfXMMq%2FbtrhGTcFRmg%2FFmerU3PPjk5UL8gVY5WRt0%2Fimg.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;512&quot; data-filename=&quot;https-g2f58deace_1280.jpg&quot; width=&quot;683&quot; height=&quot;273&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP(HyperText Transfer Protocol)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;nbsp;인터넷의 기초를 형성하는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://www.techtarget.com/searchnetworking/definition/TCP-IP&quot;&gt;TCP/IP&lt;/a&gt;&lt;span&gt; 기반으로 만들어진 &lt;/span&gt;프로토콜 이며,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP는 텍스트, 이미지, 사운드, 비디오 등과 같은 데이터를 주고받을 수 있는 프로토콜 이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;프로토콜이란? 프로토콜은 컴퓨터와 같은 서로 다른 엔티티 간의 정보 교환의 방식을 정의하는 규칙입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP작동방식&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTP 프로토콜은 웹서비스를 통해 클라이언트 장치와 서버 간에 리소스가 교환된다. 클라이언트는 웹 페이지를 로드하는데 필요한 리소스에 대한 요청을 서버에 보낸다. 서버는 요청을 이행하기 위해 클라이언트에 응답을 다시 보내며 요청과 응답은 이미지, 텍스트 등에 대한 데이터와 같은 리소스를 공유한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPS(HyperText Transfer Protocol Secure)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;HTTPS는 HTTP의 암호화된 버전이며 반대되는 개념이 아닌 향상된 버전이다. HTTPS 는 TLS 와 SSL의 조합을 사용한다. 이렇게 호스트와 브라우저간에 암호화된 보안연결이 설정된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주요 차이점&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 280px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; text-align: center; height: 20px;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;HTTP&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: center;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;HTTPS&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;HTTP는 www(World Wide Web)을 위한 통신의 기초로 정의된다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;HTTPS는 추가 보안 인증서와 함께 작동하는 HTTP이므로 인터넷에서 데이터를 안전하게 전송할 수 있다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: left;&quot;&gt;통신을 위한 기본 포트 번호는 80이다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: left;&quot;&gt;HTTPS의 기본 포트 번호는 443이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: left;&quot;&gt;HTTP는 애플리케이션 계층(application layer) 에서 작동한다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 20px; text-align: left;&quot;&gt;HTTPS는 전송 계층(transport layer) 에서 작동한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;TCP/IP 수준에서 동작한다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;별도의 프로토콜이 없으며 HTTP를 통해 실행되지만 TLS/SSL 암호화 연결을 사용한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;HTTP 웹사이트는 신원을 확인하기 위해 인증서를 요구하지 않는다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;HTTPS 웹사이트는 신원을 확인하기 위해 SSL 인증서가 필요하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 60px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 60px; text-align: left;&quot;&gt;HTTP에서는 웹사이트의 속도가 빠르다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 60px; text-align: left;&quot;&gt;HTTPS에서는 리다이렉션 및 데이터 암호화로 인해 속도가 느려진다.(과거가 아닌 현재의 환경에서는 큰 속도차이를 느끼진 않는다.)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 40px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;개인 블로그와 같이 단순한 정보를 전달하기 위한 웹사이트에 적합하다.&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 40px; text-align: left;&quot;&gt;신용/직불 카드 세부 정보, 개인 정보 등과 같은 중요한 데이터를 다루는 웹사이트에 적합하다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSL(&lt;span style=&quot;color: #666666;&quot;&gt;Secure Socket Layers) / TLS(&lt;span style=&quot;color: #373737;&quot;&gt;Transport Layer Security)&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;SSL / TLS&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 웹 브라우저와 웹 서버 간의 암호화된 통신을 가능하게 하는 글로벌 표준 보안 기술이며&lt;span&gt;&amp;nbsp;&lt;/span&gt;수많은 온라인 비즈니스 및 개인이 민감한 정보(예: 신용 카드 번호, 사용자 이름, 비밀번호, 이메일 등)를 해커의 도난이나 변조의 위험을 줄이기 위해 사용된다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 보안 연결을 생성하기 위해&lt;span&gt;&amp;nbsp;&lt;/span&gt;SSL / TLS 인증서&lt;span&gt; &lt;/span&gt;가 웹 서버에 설치되고 두 가지 기능을 제공한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;웹사이트의 신원을 인증합니다(이것은 방문자가 가짜 사이트에 있지 않다는 것을 보장합니다)&lt;/li&gt;
&lt;li&gt;전송되는 데이터를 암호화합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TLS(&lt;span style=&quot;color: #373737;&quot;&gt;Transport Layer Security)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #373a3c;&quot;&gt;1999년도에 SSL 3.0의 업그레이드 버전으로 공개되었다. SSL 3.0과 큰 차이가 있는 것은 아니나, SSL 3.0이 가지고 있는 대부분의 취약점이 해결되었다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #373a3c;&quot;&gt;위의SSL과 TLS을 조사해 보았다. 결국 TLS는 SSL의 향상된 버전이라고 보면 되는걸까? 한번 차이를 간단하게 알아보자.&lt;/span&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;SSL&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;text-align: center;&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;TLS&lt;/b&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Netscape는 1995년에 SSL의 첫 번째 버전을 개발했다.&lt;/td&gt;
&lt;td&gt;TLS의 첫 번째 버전은 1999년 IETF(Internet Engineering Taskforce)에서 개발했다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL은 명시적 연결을 사용하여 웹 서버와 클라이언트 간의 보안 통신을 설정하는 암호화 프로토콜입니다.&lt;/td&gt;
&lt;td&gt;TLS는 암시적 연결을 통해 웹 서버와 클라이언트 간에 보안 통신을 제공하는 암호화 프로토콜이며.&lt;span&gt;&amp;nbsp;&lt;/span&gt;SSL 프로토콜의 후속 제품이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL 1.0, 2.0, 3.0의 세 가지 버전이 출시되었다.&lt;/td&gt;
&lt;td&gt;TLS 4가지 버전(TLS 1.0, 1.1, 1.2, 1.3)이 출시되었다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSL의 모든 버전은 취약한 것으로 확인되었으며 모두 더 이상 사용되지 않는다.&lt;/td&gt;
&lt;td&gt;TLS 1.0 및 1.1은 2020년 3월부터 더 이상 사용되지 않는다. TLS 1.2는 가장 널리 사용되고 있는 프로토콜 버전이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위와 같은 내용으로 정리된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제는 흔히 사용하던 SSL이란 단어는 맞지 않는걸까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직도 인증서를 찾아보게되면 SSL이란 단어를 사용하는것을 자주 볼수 있다. 사실 이건 단순 사람들에게 익숙한 SSL 브랜드명을 사용하는 것이라고 볼 수 있다. 웹개발자라면 SSL 인증서라는 단어는 누구나 알고 있듯이 말이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조사한 내용을 토대로 작성했습니다. 틀린 내용이나 궁금한점은 댓글 부탁드립니다.&lt;/p&gt;</description>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/60</guid>
      <comments>https://webprogramcustom.tistory.com/60#entry60comment</comments>
      <pubDate>Thu, 14 Oct 2021 16:16:39 +0900</pubDate>
    </item>
    <item>
      <title>android ViewPager custom animation</title>
      <link>https://webprogramcustom.tistory.com/59</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Viewpager PageTransFormer&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스팅은 viewpager 애니메이션을 간단히 공유하려 했으나 허전한거 같아 Viewpager PageTransFormer에 대해 간단히 알아보려고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;11번가 앱을 사용하는 중 11번가의 viewpager 롤링 애니메이션이 마음에 들어 구현해보게 되었다. 11번가 viewpager 롤링 애니메이션은 아래와 같다. 혹시 아래의 캡처화면이 문제가 된다면 삭제하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: center;&quot; data-ke-size=&quot;size16&quot;&gt;광고아님!! 예시이미지 입니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;301&quot; data-filename=&quot;ezgif.com-gif-maker (1).gif&quot; width=&quot;442&quot; height=&quot;222&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m1n2p/btreFRoibBP/GgY7edC2vUAKaw3VgPa3lK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m1n2p/btreFRoibBP/GgY7edC2vUAKaw3VgPa3lK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m1n2p/btreFRoibBP/GgY7edC2vUAKaw3VgPa3lK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/m1n2p/btreFRoibBP/GgY7edC2vUAKaw3VgPa3lK/img.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;301&quot; data-filename=&quot;ezgif.com-gif-maker (1).gif&quot; width=&quot;442&quot; height=&quot;222&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Viewpager.PageTransFormer&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PageTransFormer는 무엇일까?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;PageTransformer는 페이지가 스크롤될 때마다 호출된다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리하여 페이지가 넘어갈때 애니메이션을 직접 커스텀할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Android 3.0 이상에서만 지원되므로 이전 플랫폼 버전의 ViewPager에서 PageTransformer를 설정하는 것은 무시됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 사용방법은 아래와 같다. 필자는 ViewPager2를 사용하였다. ViewPager1을 사용하여도 다르지 않으니 걱정하지 말자&lt;/p&gt;
&lt;pre id=&quot;code_1631248558702&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TransFormer : ViewPager2.PageTransformer {
    override fun transformPage(view: View, position: Float) {
        //do Something..
    }
}

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

        val adapter = ViewPagerAdapter()
        viewPager.setPageTransformer(TransFormer())
        viewPager.adapter = adapter
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;transformPage() 매개변수 view, position&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18606%;&quot;&gt;view&lt;/td&gt;
&lt;td style=&quot;width: 93.8372%;&quot; width=&quot;100%&quot;&gt;View: 이 페이지에 변환 적용&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 9.18606%;&quot;&gt;position&lt;/td&gt;
&lt;td style=&quot;width: 93.8372%;&quot; width=&quot;100%&quot;&gt;float: 호출기의 현재 전면 및 중앙 위치를 기준으로 한 페이지의 위치입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;0은 앞과 중앙입니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;1은 오른쪽으로 한 페이지 전체 위치이고 -1은 왼쪽으로 한 페이지 위치입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 우에서 좌로 드래그를 할 경우 우측 view가 좌측으로 롤링된다. 이때 원래 있던 view는 좌측으로 밀려가며 우측에서는 다음의 view가 밀고 들어온다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 매개변수인 view와 position의 값을 확인해보면 원래 자리하고 있던 view와 position &lt;span style=&quot;letter-spacing: 0px;&quot;&gt;0 ~ -1의 값이 전달된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;우측에서 밀고들어오는 view는 position 1 ~ 0의 값이 되는 것 이다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 위의 값을 토대로 view를 커스텀하여 구현 하면 된다.&lt;/p&gt;
&lt;pre id=&quot;code_1631250818819&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TransFormer : ViewPager2.PageTransformer {
    override fun transformPage(view: View, position: Float) {
        val img = view.findViewById&amp;lt;ImageView&amp;gt;(R.id.img)
 
        view.apply {
            val pageWidth = width
            when {
                position &amp;lt;= 0 -&amp;gt; { // [-1,0] 왼쪽으로 밀려나는 image
                    img.translationX = -position * pageWidth
                }
                position &amp;gt; 0 -&amp;gt; { // (0,1] 오른쪽에서 밀고들어오는 image
                    img.translationX = -position * pageWidth
                }
                else -&amp;gt; { // (1,+Infinity]
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 transformPage 메소드는 드래그를 할때 호출된다. 위의 코드에 호출되는 만큼 view 안에서 imageView를 찾는 findViewId 함수가 들어가있다. android 에서 findViewById 함수는 소모비용이 크다. 어떻게 처리할지 아이디어가 떠오르면 업데이트 하도록 하겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot; data-filename=&quot;ezgif.com-gif-maker.gif&quot; width=&quot;514&quot; height=&quot;321&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mQ31C/btreCsJM4Qq/4SukzdRT7FtqkuTIH6Kf9K/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mQ31C/btreCsJM4Qq/4SukzdRT7FtqkuTIH6Kf9K/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mQ31C/btreCsJM4Qq/4SukzdRT7FtqkuTIH6Kf9K/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/mQ31C/btreCsJM4Qq/4SukzdRT7FtqkuTIH6Kf9K/img.gif&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;375&quot; data-filename=&quot;ezgif.com-gif-maker.gif&quot; width=&quot;514&quot; height=&quot;321&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/boidmy/viewpager-custom-animation/tree/master&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/boidmy/viewpager-custom-animation/tree/master&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1631251725134&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - boidmy/viewpager-custom-animation&quot; data-og-description=&quot;Contribute to boidmy/viewpager-custom-animation development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/boidmy/viewpager-custom-animation/tree/master&quot; data-og-url=&quot;https://github.com/boidmy/viewpager-custom-animation&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/cAEBWm/hyLxz3172E/E3LsGj3noKHBGj40BHiF10/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/boidmy/viewpager-custom-animation/tree/master&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/boidmy/viewpager-custom-animation/tree/master&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/cAEBWm/hyLxz3172E/E3LsGj3noKHBGj40BHiF10/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - boidmy/viewpager-custom-animation&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to boidmy/viewpager-custom-animation development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;조금이라도 도움이 되셨다면 공감 부탁드립니다!&lt;/p&gt;</description>
      <category>android</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/59</guid>
      <comments>https://webprogramcustom.tistory.com/59#entry59comment</comments>
      <pubDate>Fri, 10 Sep 2021 14:31:39 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 가장 먼 노드</title>
      <link>https://webprogramcustom.tistory.com/58</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;가장 먼 노드 &lt;span&gt;Java&lt;span&gt;&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/49189&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1630828301208&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 가장 먼 노드&quot; data-og-description=&quot;6 [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] 3&quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bcHKiU/hyLuSPn5SZ/bgKGa5ogGGFj5Uoi56EE8K/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/x3TOx/hyLu3wDBSh/teHb6dpk8RJbsF862W7fRK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/49189&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bcHKiU/hyLuSPn5SZ/bgKGa5ogGGFj5Uoi56EE8K/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/x3TOx/hyLu3wDBSh/teHb6dpk8RJbsF862W7fRK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 가장 먼 노드&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;6 [[3, 6], [4, 3], [3, 2], [1, 3], [1, 2], [2, 4], [5, 2]] 3&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;풀이&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최단 경로 알고리즘인 다익스트라 알고리즘을 사용했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 노드의 최단경로로 인접 노드를 방문하며 cost를 구해 가장 큰 값을 가진 노드들을 카운트 하는 방법으로 해결했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선순위큐를 사용하여 인접노드를 방문하기까지의 cost를 구했기 때문에 최단거리를 보장받을 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1630828274956&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static class Node implements Comparable&amp;lt;Node&amp;gt; {
    int index;
    int cost;
    ArrayList&amp;lt;Integer&amp;gt; edge = new ArrayList&amp;lt;&amp;gt;();

    public Node(int index, int cost) {
        this.index = index;
        this.cost = cost;
    }

    public void addEdge(int edge) {
        this.edge.add(edge);
    }

    @Override
    public int compareTo(Node node) {
        if (this.cost &amp;gt; node.cost) return 1;
        else return 0;
    }
}

public static int solution(int n, int[][] edge) {
    ArrayList&amp;lt;Node&amp;gt; ar = new ArrayList&amp;lt;&amp;gt;();
    for (int i=0; i&amp;lt;=n; i++) {
        ar.add(new Node(i, 0));
    }
    for (int[] item : edge) {
        int nodeIndex = item[0];
        int nodeEdge = item[1];
        ar.get(nodeIndex).addEdge(nodeEdge);
        ar.get(nodeEdge).addEdge(nodeIndex);
    }

    int maxCost = dijkstra(ar, n);
    int answer = 0;
    for (int i=1; i&amp;lt;=n; i++) {
        if (ar.get(i).cost == maxCost) answer+=1;
    }
    return answer;
}

public static int dijkstra(ArrayList&amp;lt;Node&amp;gt; ar, int n) {
    PriorityQueue&amp;lt;Node&amp;gt; pq = new PriorityQueue&amp;lt;&amp;gt;(); //우선순위 큐
    boolean[] visit = new boolean[n+1]; //방문체크
    pq.add(ar.get(1));
    int maxCost = 0; //해당 변수의 값을 갱신해주며 최대 값을 저장한다.
    while (!pq.isEmpty()) {
        Node me = pq.poll();
        if (visit[me.index]) continue; //중복된 방문을 방지한다.
        visit[me.index] = true; //방문한 노드는 방문처리를 한다.
        ar.get(me.index).cost = me.cost; 
        maxCost = Math.max(maxCost, me.cost);
        for (int edgeIndex : me.edge) {
            if (visit[edgeIndex]) continue; //방문한 노드를 큐에 넣지 않기위한 조건
            Node edgeNode = new Node(edgeIndex, me.cost+1); //큐에 넣기위한 Node를 생성한다
            edgeNode.edge = ar.get(edgeIndex).edge; //새로운 Node를 생성했기에 인접 노드도 함께 저장한다.
            pq.add(edgeNode);
        }
    }
    return maxCost;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>알고리즘</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/58</guid>
      <comments>https://webprogramcustom.tistory.com/58#entry58comment</comments>
      <pubDate>Sun, 5 Sep 2021 17:00:08 +0900</pubDate>
    </item>
    <item>
      <title>프로그래머스 입국심사</title>
      <link>https://webprogramcustom.tistory.com/57</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;알고리즘 입국심사&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/43238&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://programmers.co.kr/learn/courses/30/lessons/43238&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1630675106050&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;코딩테스트 연습 - 입국심사&quot; data-og-description=&quot;n명이 입국심사를 위해 줄을 서서 기다리고 있습니다. 각 입국심사대에 있는 심사관마다 심사하는데 걸리는 시간은 다릅니다. 처음에 모든 심사대는 비어있습니다. 한 심사대에서는 동시에 한 &quot; data-og-host=&quot;programmers.co.kr&quot; data-og-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43238&quot; data-og-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43238&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bsuY2C/hyLt1liOFi/Z4mCzNgaXM1ayOG4sBT3s0/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/Tgq7A/hyLtTHzolE/s3qPGKeRSSieQ2CY6j8TKK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626&quot;&gt;&lt;a href=&quot;https://programmers.co.kr/learn/courses/30/lessons/43238&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://programmers.co.kr/learn/courses/30/lessons/43238&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bsuY2C/hyLt1liOFi/Z4mCzNgaXM1ayOG4sBT3s0/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626,https://scrap.kakaocdn.net/dn/Tgq7A/hyLtTHzolE/s3qPGKeRSSieQ2CY6j8TKK/img.jpg?width=626&amp;amp;height=626&amp;amp;face=0_0_626_626');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;코딩테스트 연습 - 입국심사&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;n명이 입국심사를 위해 줄을 서서 기다리고 있습니다. 각 입국심사대에 있는 심사관마다 심사하는데 걸리는 시간은 다릅니다. 처음에 모든 심사대는 비어있습니다. 한 심사대에서는 동시에 한&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;programmers.co.kr&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;680&quot; width=&quot;552&quot; height=&quot;622&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NXM9p/btrd0vUy97h/0H1XLKn1oZbNgp1h1NKoz0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NXM9p/btrd0vUy97h/0H1XLKn1oZbNgp1h1NKoz0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NXM9p/btrd0vUy97h/0H1XLKn1oZbNgp1h1NKoz0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNXM9p%2Fbtrd0vUy97h%2F0H1XLKn1oZbNgp1h1NKoz0%2Fimg.png&quot; data-origin-width=&quot;603&quot; data-origin-height=&quot;680&quot; width=&quot;552&quot; height=&quot;622&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;529&quot; width=&quot;551&quot; height=&quot;485&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXqBnq/btrd2yJh1UE/KYaO4R1PW2xnLCc2O45ny0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXqBnq/btrd2yJh1UE/KYaO4R1PW2xnLCc2O45ny0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXqBnq/btrd2yJh1UE/KYaO4R1PW2xnLCc2O45ny0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXqBnq%2Fbtrd2yJh1UE%2FKYaO4R1PW2xnLCc2O45ny0%2Fimg.png&quot; data-origin-width=&quot;601&quot; data-origin-height=&quot;529&quot; width=&quot;551&quot; height=&quot;485&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;이분탐색 시간복잡도&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(logn)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주어진 n명의 사람이 주어진 times 배열의 시간을 활용하여 최단시간내에 입국심사를 받으면 되는 문제다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 문제는 이분탐색 카테고리에 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 이 카테고리 못봤으면 이분탐색으로 생각도 못했을거같다. 많이 풀어봐야겠다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이분탐색의 기준은 시간기준으로 0 ~ times[가장큰값] * n 을 기준으로 탐색을 진행하게 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당문제의 포인트는 주어진 n 을 기준으로 한명씩 심사를 받게 하는것이 아닌 최대의 시간을 가지고 그 시간내에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n명의 인원이 심사를 완료할수 있는가를 생각해보면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드&lt;/p&gt;
&lt;pre id=&quot;code_1630675436167&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static long solution(int n, int[] times) {
        Arrays.sort(times);
        long answer = 0; //최단시간을 저장할 변수
        long left = 0; //최저시간
        long right = (long) n*times[times.length-1]; //n명의 고객이 최대의 시간을 거쳐 심사를 받을 수 있는 시간
        long pivot; //중간값을 저장할 변수
        while (left &amp;lt;= right) { //갱신되는 최저시간(left)이 최대시간(right)과 같아지거나 커지면 반복 종료
            pivot = (left + right) / 2; //최저시간과 최대시간의 중간값을 저장한다.
            long sum = 0; //고객의 수를 저장할 변수
            for (long item : times) { //주어진 times 배열을 모두 반복한다
                sum += pivot / item;  //times시간을 현재 pivot(시간)으로 나누어 최대 심사를 받을 수 있는 인원을 구한다.
            }
            if (sum &amp;lt; n) { //심사를 받은 사람이 주어진 n보다 작을경우(시간이 모자란것)
                left = pivot + 1; //left(최저시간)를 갱신하여 다시 반복한다.
            } else { //심사를 받은 사람이 주어진 n보다 크거나 같다(시간이 남을수도 있음)
                right = pivot - 1; //시간이 남을 수 있기때문에 right를 갱신하여 다시 반복
                answer = pivot; //pivot(현재 구한 시간)을 저장
            }
        }
        return answer;
    }&lt;/code&gt;&lt;/pre&gt;</description>
      <category>알고리즘</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/57</guid>
      <comments>https://webprogramcustom.tistory.com/57#entry57comment</comments>
      <pubDate>Fri, 3 Sep 2021 22:32:00 +0900</pubDate>
    </item>
    <item>
      <title>디자인패턴 Adapter pattern</title>
      <link>https://webprogramcustom.tistory.com/56</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Adapter&amp;nbsp;pattern&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어댑터 패턴이란?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;용도는 비슷하게 사용되지만 서로 다른 interface를 구현한다면 같이 사용할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 호환성 문제를 해결하기 위해 어댑터 패턴을 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 예시&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 모니터를 본체와 연결할때 dvi 케이블과 hdmi 케이블을 사용할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 내 모니터는 hdmi만을 연결할 수 있고 나는 dvi 케이블만을 가지고있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이를 해결하기위해 dvi를 hdmi로 연결하기 위한 adapter가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot; data-filename=&quot;laptop-829334_1280.jpg&quot; width=&quot;428&quot; height=&quot;285&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bX0yBR/btrdOw6Ho31/FOKJlhkAVH5mQ2KXnmpZe1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bX0yBR/btrdOw6Ho31/FOKJlhkAVH5mQ2KXnmpZe1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bX0yBR/btrdOw6Ho31/FOKJlhkAVH5mQ2KXnmpZe1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbX0yBR%2FbtrdOw6Ho31%2FFOKJlhkAVH5mQ2KXnmpZe1%2Fimg.jpg&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;853&quot; data-filename=&quot;laptop-829334_1280.jpg&quot; width=&quot;428&quot; height=&quot;285&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 한번 봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;DVI&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630563366984&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Dvi {
    void insertDviSlot();
    void printScreen();
}

public class SamsungDvi implements Dvi {
    @Override
    public void insertDviSlot() {
        System.out.println(&quot;insertDvi&quot;);
    }

    @Override
    public void printScreen() {
        System.out.println(&quot;printScreen&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;HDMI&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630563580425&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface Hdmi {
    void insertHdmiSlot();
    void printScreen();
}

public class LgHdmi implements Hdmi {
    @Override
    public void insertHdmiSlot() {
        System.out.println(&quot;insertHdmi&quot;);
    }

    @Override
    public void printScreen() {
        System.out.println(&quot;printScreen&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 client는 가지고있는 Dvi interface를 구현한 dvi 케이블만 있습니다. 그렇기에 현재 client는 Hdmi가 필요한 모니터를 사용할 수 없는 상황입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;195&quot; data-origin-height=&quot;176&quot; data-filename=&quot;hdmi.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7MdbH/btrdMKkNyU7/L3heQmz6InEkbckYlHEf11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7MdbH/btrdMKkNyU7/L3heQmz6InEkbckYlHEf11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7MdbH/btrdMKkNyU7/L3heQmz6InEkbckYlHEf11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7MdbH%2FbtrdMKkNyU7%2FL3heQmz6InEkbckYlHEf11%2Fimg.png&quot; data-origin-width=&quot;195&quot; data-origin-height=&quot;176&quot; data-filename=&quot;hdmi.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재는 단순히 client가 Dvi interface에 의존하고 있으며 Hdmi를 사용할 수 없는 상황입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Monitor&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630565514915&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Monitor {
    private Hdmi hdmi;

    public Monitor(Hdmi hdmi) {
        this.hdmi = hdmi;
    }

    public void printScreen() {
        hdmi.printScreen();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 연결해서 사용할 모니터 입니다. hdmi 케이블밖에는 지원하지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Adapter&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630570930385&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class DviAdapter implements Hdmi {
    Dvi dvi;
    public DviAdapter(Dvi dvi) {
        this.dvi = dvi;
    }

    @Override
    public void insertHdmiSlot() {
        dvi.insertDviSlot();
    }

    @Override
    public void printScreen() {
        dvi.printScreen();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client가 필요한것은 Hdmi 케이블입니다. 우리는 Hdmi interface를 구현한 Adapter를 만들어주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이젠 Hdmi 만을 지원하는 모니터를 사용할 준비가 끝났습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Client&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1630565615164&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Client {

    public static void main(String[] args) {
        DviAdapter adapter = new DviAdapter(new SamsungDvi());
        Monitor monitor = new Monitor(adapter);
        monitor.printScreen();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;client는 이제 dvi 케이블을 어댑터를 사용하여 moniter를 사용할 수 있게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;장점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;사용하려는 코드를 수정하지 않고 달성하려는 목적의 interface에 호환되게 만들 수 있다.&lt;/li&gt;
&lt;li&gt;기존 코드를 변경하지 않고 목적에 맞게 호환시킬 수 있기 때문에 재활용성에서 좋아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드 복잡성 증가&lt;/li&gt;
&lt;li&gt;구현하려는 목적의 interface의 내용을 모두 구현해야한다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>디자인패턴</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/56</guid>
      <comments>https://webprogramcustom.tistory.com/56#entry56comment</comments>
      <pubDate>Thu, 2 Sep 2021 16:19:00 +0900</pubDate>
    </item>
    <item>
      <title>kotlin coroutine</title>
      <link>https://webprogramcustom.tistory.com/55</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR'; color: #000000;&quot;&gt;kotlin coroutine&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Android 어플리케이션은 Background Thread 를 만들어주지 않으면 Main Thread에서 모든일을 처리 한다는 것을 대부분 알고 계실 것 입니다. Main Thread는 이미 ui를 출력해주는 작업 만으로도 많은 일을 하고있는 셈 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;만약 오랜 시간이 걸리는 작업을 Main Thread에서 처리한다면 ANR(Application Not Responding)을 만나게 될 것 입니다. 그래서 우리는 Main Thread의 부담을 덜어주기 위해 네트워크 작업, 시간이 오래 걸리는 작업 등을 Multi Thread 환경에서 작업합니다. 우리는 이러한 비동기 처리를 위해 android 에서 AsyncTask, RxJava를 사용하곤 했습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코루틴이란?&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코루틴은 가벼운 스레드 입니다. 경량 스레드(light-weight thread)라고도 표현합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코루틴은 매우 가볍다는 것 입니다. 수백개의 코루틴을 만들어도 문제되지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;(코루틴은 스레드와 비교되지만 병렬처리의 개념이 아닙니다! 이 내용에 대해서는 다음 포스팅으로 이어가겠습니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코루틴의 중요한 개념을 간단히 살펴보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;suspend&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Dispatchers&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Job&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CoroutineScope&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. suspend&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;suspend 키워드는 컴파일러에게 이 함수가 코루틴 스코프에서 실행 되어야 한다는 것을 알려줍니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;suspend 함수 내에서 순차적으로 실행하고 완료될 때까지 기다릴 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629728000172&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;suspend fun coroutineFunction() {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위에서 설명 하였지만 suspend 함수는 코루틴 스코프 또는 다른 suspend 함수에서만 호출되어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1629729214128&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        GlobalScope.launch {
            println(&quot;case1=${System.currentTimeMillis()}&quot;)
            val value = coroutineFunction()
            println(&quot;case2=${System.currentTimeMillis()}&quot;)
            println(&quot;case3=${System.currentTimeMillis()}value = $value&quot;)
        }
    }
}

suspend fun coroutineFunction(): Int {
    println(&quot;case4=${System.currentTimeMillis()}&quot;)
    delay(5000)
    return 100
}

결과
I/System.out: case1=1629729538838
I/System.out: case4=1629729538841
I/System.out: case2=1629729543901
I/System.out: case3=1629729543911 value = 100&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;결과에서 알 수 있듯 suspend 함수 내에서 5초의 시간 delay를 넣어놓았고 마치 일반적인 동기화 프로세스처럼 작동하며 5초를 기다린 후 결과를 반환 하는 것을 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. Dispatchers&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;디스패처는 작업을 수행해야 하는 스레드를 지정합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Dispatchers.Main &lt;/b&gt;(벌써부터 ui 업데이트에 사용될거 같은 냄새가 물씬 풍깁니다.)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Main Thread에서 코루틴을 실행합니다. 이 디스패처는 ui와 상호작용하고 빠른 작업을 할때만 사용해야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Dispatchers.Default&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대기시간이 없고 지속적인 cpu 작업이 요구되는 JSON파싱, 복잡한 연산 작업에 적당한 디스패처 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Dispatchers.IO&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;대기시간이 있는 네트워크 작업에 적합한 디스패처 입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. job&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;코루틴을 컨트롤 하기 위해 job을 제공해 줍니다. 우리는 job을 이용해 코루틴을 취소 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629733665884&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SubActivity: AppCompatActivity() {
   
    val job = Job()
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activty_sub)

        CoroutineScope(Dispatchers.IO+job).launch {
            delay(5000)
            CoroutineScope(Dispatchers.Main).launch {
                hello.text = &quot;안뇽&quot;
            }
        }

        hello.setOnClickListener {
            job.cancel()
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위의 코드에서 변수 job 객체를 생성하였습니다. 그리고 생성하는 CoruoutineScope를 추가하여 컨트롤 할 수 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위의 코드에서 자식 스코프인 CoroutineScope(Dispatchers.Main) 실행되기 전 job을 이용하여 취소하면 실행되지 않습니다. &lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;하지만 만약 자식 스코프가 실행된 상태에선 어떻게 취소해야 할까요?&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629817072799&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val job = Job()

CoroutineScope(Dispatchers.IO+job).launch {
    CoroutineScope(Dispatchers.Main+job).launch {
        repeat(5) {
            delay(1000)
            println(&quot;취소확인!&quot;)
        }
    }
}

job.cancel()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;위처럼 자식 스코프에 디스패처 등록을 job과 같이 해주면 됩니다. 하나의 job 객체에 n개의 스코프를 등록해 줌으로써 함께 취소할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629817857772&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CoroutinScope.kt

@Suppress(&quot;FunctionName&quot;)
public fun CoroutineScope(context: CoroutineContext): CoroutineScope =
    ContextScope(if (context[Job] != null) context else context + Job())&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CoroutineScope 를 생성할때 job을 함께 등록해주면 위의 &lt;span style=&quot;color: #000000;&quot;&gt;CoroutineScope&lt;span&gt; 함수에 디스패처와 &lt;/span&gt;&lt;/span&gt;job이 &lt;span style=&quot;color: #000000;&quot;&gt;인자값으로&lt;span&gt; 넘어오며&lt;/span&gt;&lt;/span&gt; 함께 등록됩니다. 역시나 친절합니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Job 객체에는 cancel 메소드 이외에도 start, join, cancelAndJoin 등이 있습니다. 자세한 내용은 추후에 포스팅 하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;4. CoroutineScope&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/&quot;&gt;CoroutineScope&lt;/a&gt;는&amp;nbsp;launch&amp;nbsp;또는&amp;nbsp;async를 사용하여 만든 코루틴을 추적합니다. 진행 중인 작업, 즉 실행 중인 코루틴은 언제든지&amp;nbsp;scope.cancel()을 호출하여 취소할 수 있습니다. Android에서 일부 KTX 라이브러리는 특정 수명 주기 클래스에 자체&amp;nbsp;CoroutineScope를 제공합니다. 예를 들어&amp;nbsp;ViewModel에는&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary?hl=ko#(androidx.lifecycle.ViewModel).viewModelScope:kotlinx.coroutines.CoroutineScope&quot;&gt;viewModelScope&lt;/a&gt;가 있고&amp;nbsp;Lifecycle에는&amp;nbsp;&lt;a style=&quot;color: #000000;&quot; href=&quot;https://developer.android.com/reference/kotlin/androidx/lifecycle/package-summary?hl=ko#lifecyclescope&quot;&gt;lifecycleScope&lt;/a&gt;가 있습니다. 하지만 디스패처와 달리&amp;nbsp;CoroutineScope는 코루틴을 실행하지 않습니다. (공식사이트 인용)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;간단히 launch 함수를 알아보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;launch&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;launch() 함수는 Job 객체를 반환합니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629735529415&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val job = CoroutineScope(Dispatchers.IO).launch {
    delay(5000)
}
job.join()
job.cancel()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;반환받은 객체로 코루틴 블럭을 취소할 수 있으며 join 메소드로 코루틴 블럭이 완료 되기를 기다릴 수도 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좀더 정확하게 쓰기위해 알아야 할 것들이 아직 많이 있습니다. 내용을 계속 추가 작성할 계획입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;틀린부분은 지적 부탁드립니다. 읽어주셔서 감사합니다.&lt;/p&gt;</description>
      <category>kotlin</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/55</guid>
      <comments>https://webprogramcustom.tistory.com/55#entry55comment</comments>
      <pubDate>Tue, 24 Aug 2021 01:27:23 +0900</pubDate>
    </item>
    <item>
      <title>android Jetpack</title>
      <link>https://webprogramcustom.tistory.com/54</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;android Jetpack&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jetpack은 개발자가 고품질의 앱을 더 쉽게 작성할 수 있도록 도와주는 라이브러리 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단어에서부터 벌써 사용하면 날아갈거 같네요&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;AndroidX&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;androidx네임스페이스&lt;span&gt;&amp;nbsp;&lt;/span&gt;내의 아티팩트&lt;span&gt;&amp;nbsp;&lt;/span&gt;는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://developer.android.com/jetpack&quot;&gt;Android Jetpack&lt;/a&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;라이브러리를&lt;span&gt;&amp;nbsp;&lt;/span&gt;구성합니다&lt;span&gt;&amp;nbsp;&lt;/span&gt;.&lt;span&gt; SupportLibrary&amp;nbsp;&lt;/span&gt;와 마찬가지로&lt;span&gt;&amp;nbsp;&lt;/span&gt;androidx네임스페이스의&lt;span&gt;&amp;nbsp;&lt;/span&gt;라이브러리&lt;span&gt;&amp;nbsp;&lt;/span&gt;는 Android 플랫폼과 별도로 제공되며 Android 릴리스 간에 이전 버전과의 호환성을 제공합니다. (공식문서 문구 인용)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;androidX는 더이상 지원되지 않는 SupportLibrary 개선된 버전입니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;s&gt;아니 그래서 AndroidX가 Jetpack 이라는 거야 뭐야?&lt;/s&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;androidX와 Jetpack은 같은것이라 생각하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;androidX는 Jetpack에 포함된 모든 라이브러리에 대한 버전 관리 및 릴리즈 정책을 정의하는 오픈 소스 프로젝트입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jetpack은 Androidx 라이브러리에 있는 구성요소의 외부 브랜딩 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단순히 친숙하게 Jetpack이란 이름으로 각각의 라이브러리의 구성요소를 나타내고 라이브러리는 androidX오픈 소스로 관리되는 것 입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;Jetpack 구성요소&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;337&quot; data-filename=&quot;1_fS8RGD9PgM6Bk4BvQ31cdg.png&quot; width=&quot;634&quot; height=&quot;330&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bwdYi3/btrcLAiAGxP/0YHdKJZB2Ri3zomdKzVsa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bwdYi3/btrcLAiAGxP/0YHdKJZB2Ri3zomdKzVsa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bwdYi3/btrcLAiAGxP/0YHdKJZB2Ri3zomdKzVsa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbwdYi3%2FbtrcLAiAGxP%2F0YHdKJZB2Ri3zomdKzVsa1%2Fimg.png&quot; data-origin-width=&quot;647&quot; data-origin-height=&quot;337&quot; data-filename=&quot;1_fS8RGD9PgM6Bk4BvQ31cdg.png&quot; width=&quot;634&quot; height=&quot;330&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jetpack 구성요소로는 위와같이 구성되어 있습니다. 우리가 평소 사용하는 거의 대부분의 것들이 Jetpack 라이브러리의 구성요소 라고 보면 됩니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Jetpack은 androidx 패키지 라이브러리로 구성됩니다. 최신 가이드에 따르기 위해 androidx로의 마이그레이션이 필요합니다. SupportLibrary 마지막 버전은 28 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;주관적인 기준으로 Jetpack구성요소를 간단하게 살펴보겠습니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 80px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;a href=&quot;https://developer.android.com/jetpack/androidx/releases/activity&quot;&gt;activity *&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Access composable APIs built on top of Activity.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;a href=&quot;https://developer.android.com/jetpack/androidx/releases/fragment&quot;&gt;fragment *&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Segment your app into multiple, independent screeens that are hosted within an Activity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;a href=&quot;https://developer.android.com/jetpack/androidx/releases/recyclerview&quot;&gt;recyclerview&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;Display large sets of data in your UI while minimizing memory usage.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;a href=&quot;https://developer.android.com/jetpack/androidx/releases/databinding&quot;&gt;databinding *&lt;/a&gt;&lt;/td&gt;
&lt;td style=&quot;height: 20px;&quot;&gt;&lt;span style=&quot;color: #202124;&quot;&gt;Bind UI components in your layouts to data sources in your app using a declarative format.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리가 평소 흔하게 쓰는 것 들이며 이외에도 정말 많은것들이 있습니다. 한번 살펴보시는걸 추천드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/jetpack/androidx/explorer?case=ui&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.android.com/jetpack/androidx/explorer?case=ui&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;androidX 마이그레이션 하기&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AndroidX는 SupportLibrary&amp;nbsp;API를&lt;span&gt;&amp;nbsp;&lt;/span&gt;androidx네임스페이스의&lt;span&gt;&amp;nbsp;&lt;/span&gt;패키지로 대체합니다&lt;span&gt;&amp;nbsp;&lt;/span&gt;.&lt;span&gt;&amp;nbsp;&lt;/span&gt;패키지 및 Maven 아티팩트 이름만 변경되었습니다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;클래스, 메서드 및 필드 이름은 변경되지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;전제조건&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이그레이션을 진행하기 전에 SupportLibrary 버전을 최종 버전인 28.0.0으로 업데이트 후 진행하는 것이 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마이그레이션을 진행하기 전 소스 백업을 해놓은 후 진행하는 것이 안전할 것 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;485&quot; data-filename=&quot;화면 캡처 2021-08-21 010600.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/vuD4F/btrcNlyeLPn/VpIEMChIFOHbP7JNQRSQPk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/vuD4F/btrcNlyeLPn/VpIEMChIFOHbP7JNQRSQPk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/vuD4F/btrcNlyeLPn/VpIEMChIFOHbP7JNQRSQPk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FvuD4F%2FbtrcNlyeLPn%2FVpIEMChIFOHbP7JNQRSQPk%2Fimg.png&quot; data-origin-width=&quot;250&quot; data-origin-height=&quot;485&quot; data-filename=&quot;화면 캡처 2021-08-21 010600.png&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>android</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/54</guid>
      <comments>https://webprogramcustom.tistory.com/54#entry54comment</comments>
      <pubDate>Sat, 21 Aug 2021 00:54:37 +0900</pubDate>
    </item>
    <item>
      <title>Java Thread</title>
      <link>https://webprogramcustom.tistory.com/53</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Java Thread&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Java Thread란?&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;우리는 하나의 프로세스를 작성하며 하나의 프로세스 내에 여러개의 스레드로 작업을 진행합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;특정 작업을 진행할때 많은 시간이 소요되는 작업이 존재하기 마련입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;이럴때 우린 sub thread 를 만들어 처리를 위임하고 main thread는 자기의 일을 이어서 진행 할 필요가 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Thread 장점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단일 프로세스 내에서 많은 동시 작업 가능&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;유지 보수 비용 절감&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;CPU 리소스를 효율적으로 사용&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;스레드는 시스템 리소스에 최소한의 영향을 미칩니다.&amp;nbsp;스레드는 기존 프로세스보다 생성, 유지 및 관리에 더 적은 오버헤드가 필요합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;Thread 단점&lt;/b&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;복잡한 디버깅 및 테스트 프로세스&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;교착 상태 발생 가능성 증가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;프로그램 작성 난이도 증가&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #000000;&quot;&gt;예측할 수 없는 결과의 발생 가능성&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;구현 방법&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. Thread의 상속&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629040412232&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    Thread thread = new MyThread();
    thread.start();
}

class MyThread extends Thread {
    @Override
    public void run(){
        //doSomething
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Thread를 상속하여 구현한 방식입니다. Thread를 상속하여 구현할 경우 다중 상속이 불가능 하기 때문에 interface인 Runnable을 구현하는 것이 일반적입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. Runnable의 구현&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1629039849874&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    Thread thread = new Thread(new MyThread()); //Thread 생성자의 인자로 Runnable의 구현체를 넘겨주어야함
    thread.start(); //Thread 실행 메소드
}

class MyThread implements Runnable {
    @Override
    public void run(){
        //doSomething
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;Runnable interface를 구현하는 방식입니다. 다중 상속이 불가능한 java의 특성상 Runnable interface를 구현하여 사용하는 경우가 일반적입니다. 이 방법의 경우 Thread를 시작해주기 위해 Thread 객체를 생성하여 Ruunable의 구현체를 생성자에 인자값으로 넣어주어 실행을 시켜주어야 합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>JAVA</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/53</guid>
      <comments>https://webprogramcustom.tistory.com/53#entry53comment</comments>
      <pubDate>Mon, 16 Aug 2021 01:06:11 +0900</pubDate>
    </item>
    <item>
      <title>Java String vs StringBuffer vs StringBuilder</title>
      <link>https://webprogramcustom.tistory.com/52</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;String&amp;nbsp;vs&amp;nbsp;StringBuffer&amp;nbsp;vs&amp;nbsp;StringBuilder&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Java에서 문자열을 다루는 세 가지의 class에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 위의 세가지를 구분 지어 사용하는 이유에 대해 이해하기 위해선 memory 영역에 객체가 어떻게 할당되는지를 우선 알아야 할 필요가 있습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;String&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1628730512769&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    String st = &quot;안뇽&quot;;
    st = st + &quot;하세요&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 Memory 영역에 어떻게 할당될까요? 단순히 st 변수에 &lt;span style=&quot;color: #409d00;&quot;&gt;안뇽하세요&lt;/span&gt; 문자가 저장되니 문제가 없지 않을까요?&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 객체는 불변의 객체입니다. 이제 메모리가 어떤 식으로 할당되는지 살펴봅시다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;386&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKCyLu/btrbOOPBDFf/M6GScNvyUEzkJqNVHFvBV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKCyLu/btrbOOPBDFf/M6GScNvyUEzkJqNVHFvBV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKCyLu/btrbOOPBDFf/M6GScNvyUEzkJqNVHFvBV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKCyLu%2FbtrbOOPBDFf%2FM6GScNvyUEzkJqNVHFvBV0%2Fimg.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;386&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Stack memory는 객체의 참조를 가지고 있으며 Heap memory의 String pool 영역은 같은 문자를 공유합니다. st 변수의 문자의 변경이 일어남으로써 안뇽 문자의 참조가 끊어졌습니다. String pool 영역의 문자 객체도 GC(Garbage Collection) 대상에 포함됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;이것이 핵심입니다. 단순 문자를 덧붙였을 뿐인데 Heap memory의 String pool 영역에 쓸데없는 값이 쌓이고 있습니다.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;GC(Garbage Collection)가 수행되기 전까지는 불필요한 memory를 차지하는 것과 같습니다. 웬만한 경우는 문제가 없을 것이나 방대한 양의 문자열 처리가 필요하다면 분명 무시할 수 없는 memory 낭비가 될 것입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;StringBuffer &amp;amp; StringBuilder&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;둘의 사용법은 거의 같으며 차이는 &lt;span style=&quot;color: #292929;&quot;&gt;thread-safe의 차이입니다. StringBuffer는 동기화됩니다. 그렇기 때문에 멀티스레드 환경에서 사용하며 StringBuilder는 동기화되지 않기 때문에 단일 스레드 환경에서 사용하면 됩니다. 멀티스레드 환경이 아니라면 StringBuilder를 사용합시다. 동기화 작업은 성능적으로 유리하지 못합니다.&lt;/span&gt;&lt;span style=&quot;color: #292929;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1628733091833&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    StringBuilder sb = new StringBuilder(&quot;첫번째&quot;);
    sb.append(&quot;Builder&quot;);
    StringBuffer sbf = new StringBuffer(&quot;두번째&quot;);
    sbf.append(&quot;Buffer&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 코드는 메모리가 어떻게 할당될까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자를 통한 객체의 생성은 모두 Heap memory 영역에 따로 저장됩니다. 위의 방법은 String pool 영역이 아닌 별도의 영역에 생성됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;382&quot; width=&quot;538&quot; height=&quot;338&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bFlvxa/btrbOJ86dve/JpqmI4xbnLfpuBQjUEUiu1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bFlvxa/btrbOJ86dve/JpqmI4xbnLfpuBQjUEUiu1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bFlvxa/btrbOJ86dve/JpqmI4xbnLfpuBQjUEUiu1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbFlvxa%2FbtrbOJ86dve%2FJpqmI4xbnLfpuBQjUEUiu1%2Fimg.png&quot; data-origin-width=&quot;608&quot; data-origin-height=&quot;382&quot; width=&quot;538&quot; height=&quot;338&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국 StringBuilder와 StringBuffer는 append 연산이 이루어져도 Heap memory 영역에 새로운 문자 객체가 할당되는 것이 아닌 기존의 문자 객체에 덧붙여진다는 것을 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;memory의 할당에 대해 안다면 차이를 정확히 이해할 수 있을 것이라 생각합니다.&lt;/p&gt;</description>
      <category>JAVA</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/52</guid>
      <comments>https://webprogramcustom.tistory.com/52#entry52comment</comments>
      <pubDate>Thu, 12 Aug 2021 01:05:38 +0900</pubDate>
    </item>
    <item>
      <title>Java interface vs abstract(추상클래스) 차이</title>
      <link>https://webprogramcustom.tistory.com/51</link>
      <description>&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;interface vs abstract 차이&lt;/span&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인터페이스? 추상클래스?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우린 위의 두개가 무엇인지 어느정도는 알고있습니다. 해당 포스팅까지 찾아오신 분이라면 쓰는방법은 알고 계실거라 생각됩니다. 하지만 왜? 어떻게 두개를 구분해서 써야하는거지? 인터페이스는 음.. 다중상속이 되고 추상 메소드를 가지고 있다. 추상클래스는 음.. 다중상속이 되지 않고 추상 메소드를 가지고 있다.. 뭐야.. 그럼 다중상속이 되는 인터페이스를 쓰면되겠네..!?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인터페이스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스는 설계의 기초 틀을 잡아 놓는 역할을 한다고 생각하면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628669217239&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface 인터페이스 {
    int oh = 1; //상수
    String method(); //추상메소드
    default void method2() { //default 메소드
        System.out.println(&quot;default 메소드!&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위처럼 인터페이스의 기존 틀을 잡아놓고 사용할 수 있습니다. default 메소드는 java8 에서 추가된 인터페이스 내에서 구현이 가능한 메소드 입니다. 그리고 추상메소드의 경우 앞에 abstract가 왜 안붙냐 라고 생각하실 수도 있습니다. 인터페이스에서는 abstract 키워드가 생략됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 구성요소를 살펴보았습니다.. 잠시 후 예제를 통하여 좀더 깊게 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추상클래스&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상클래스는 여러개의 클래스에서 공통된 기능을 추출하여 모아놓는 역할을 합니다.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1628671110743&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class 추상클래스 {
    int oh; //필드
    void method1(){ //메소드
        System.out.println(&quot;method&quot;);
    }
    public abstract void method2(); //추상메소드
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;추상 클래스는 위처럼 메소드를 두어 공통적인 기능을 구현할 수 있습니다. 그리고 추상메소드를 명시해 두어 자식 클래스에서 구현을 강제할 수도 있습니다. 위의 코드에서 자식 클래스에 구현이 강제되는 것은 method2() 메소드 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지 간단히 인터페이스와 추상클래스의 구성요소를 살펴보았습니다. 하지만 저희는 두가지를 어떻게 구분지어 사용해야 하는가를 알 필요가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 예시를 통해 알아봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;예시&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시를 통하여 상황을 하나 살펴보려 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;학교에는 선생님이 있습니다. 선생님은 수업을 가르치며, 한 반의 담임 선생일 수 있고 시간제 강사일 수도 있습니다. 또한 학생들을 지도 합니다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시를 한번 코드로 풀어봅시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;선생님들의 공통점(abstract class)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선생님은 공통적으로 학생들을 지도합니다. 그리고 학생들을 가르치기도 합니다. 하지만 어떤 과목을 가르치는지는 알수가 없습니다. 어떤 과목을 가르치는지 알수가 없으니 구현 클래스에 구현을 위임합시다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우리는 선생님들의 공통점이 무엇인지 알았습니다. 이제 공통점을 추상클래스로 구현해주면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628672339101&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public abstract class Teacher {
    public void guide() {
        System.out.println(&quot;학생들을 지도한다.&quot;);
    }
    public abstract void teach();
}

public class MathTeacher extends Teacher {
    @Override
    public void teach() {
        System.out.println(&quot;수학선생님&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떠한 선생님 이라도 선생님은 학생들을 지도할 수 있습니다. 그리고 각자의 대표 과목을 가지고 있습니다. 이처럼 공통적인 행동을 하는 것은 추상 클래스에 구현하여 공통으로 사용하면 됩니다. 그리고 공통된 정확한 정보가 구현 클래스에서 알 수 있는것이라면 구현을 위임하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;선생님들이 할 수도 있는것(interface)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 선생님들이 할 수도 있는것을 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 설명한 예시에서 선생님들은 한 반의 담임 선생일수도 있으며 시간제 강사일수도 있다고 설명했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;1. 담임선생님&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;담임선생님은 한 반을 이끌어가야 할 책임이 있습니다. 학생들이 등교했는지를 체크해야 할 의무가 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628673923320&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//담임선생님의 역할을 구현하지 않고 정의 해 놓는다.
public interface ClassTeach {
    void classTeach();
    void attendance();
}

public class MathTeacher extends Teacher implements ClassTeach {
    @Override
    public void teach() {
        System.out.println(&quot;수학선생님&quot;);
    }

    @Override
    public void classTeach() {
        System.out.println(&quot;3반 담임선생님&quot;);
    }

    @Override
    public void attendance() {
        System.out.println(&quot;학생들이 등교를 했는지 출석부를 부른다.&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;2. 시간제강사&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;시간제 강사는 학교에 계속 머무르지 않습니다. 자신의 수업시간일 때만 학교에 머무르면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1628674216385&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class ScienceTeacher extends Teacher implements PartTimeTeacher {
    @Override
    public void teach() {
        System.out.println(&quot;과학선생님&quot;);
    }

    @Override
    public void teachingTime() {
        System.out.println(&quot;1시~4시 까지만 강의&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드로의 설명은 이정도만 하려 합니다. 코드가 난잡해 지면 읽기가 힘들고 분석하기 힘들것이라 생각합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 예시에서 결국 차이점은 무엇일까요?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;모든 선생님 class에서 공통적으로 사용할 수 있는가? 선택적으로 구현을 해야하는 것인가?&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두개의 차이점이 있습니다. 선생님은 무조건 적으로 학생을 가르쳐야 하는 공통점이 있으므로 공통화 시킬 수 있어 추상클래스로 만들며 이제 무조건적이 아닌 선택적 구현이 필요한 것을 인터페이스로 정의를 해놓는 것 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 내용은 충분히 억지스러울 수 있습니다. 시간제 강사도 학생의 출석을 부를수 있을 수 있을 수 있습니다. 최대한 짧게 표현하기 위함이니 양해 부탁드립니다.&lt;/p&gt;</description>
      <category>JAVA</category>
      <author>개발자가되고싶어</author>
      <guid isPermaLink="true">https://webprogramcustom.tistory.com/51</guid>
      <comments>https://webprogramcustom.tistory.com/51#entry51comment</comments>
      <pubDate>Wed, 11 Aug 2021 18:48:21 +0900</pubDate>
    </item>
  </channel>
</rss>