<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>blue-sky.log</title>
        <link>https://velog.io/</link>
        <description>Developer-Android-CK</description>
        <lastBuildDate>Sun, 20 Nov 2022 04:45:29 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>blue-sky.log</title>
            <url>https://images.velog.io/images/blue-sky/profile/6928ec1f-353d-48ca-bbbd-f5d0ed23a014/cloud.svg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. blue-sky.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/blue-sky" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[과일 장수 Java/ Kotlin]]></title>
            <link>https://velog.io/@blue-sky/%EA%B3%BC%EC%9D%BC-%EC%9E%A5%EC%88%98-Java-Kotlin</link>
            <guid>https://velog.io/@blue-sky/%EA%B3%BC%EC%9D%BC-%EC%9E%A5%EC%88%98-Java-Kotlin</guid>
            <pubDate>Sun, 20 Nov 2022 04:45:29 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/135808">문제 출처</a></p>
<h3 id="java">Java</h3>
<pre><code class="language-java">import java.util.*;
class Solution {
  public int solution(int k, int m, int[] score) {
        int answer = 0;
        Arrays.sort(score); // [1,1,1,2,2,3,3]

        int [] tScore = new int[score.length];

        for (int i= 0; i&lt;score.length; i++){
            tScore[i] = score[score.length -1 -i];

        }
        int index = 0;
        while (true){
            if (index &gt;= tScore.length || index + m &gt; tScore.length) {  break;}
            answer += tScore[index +m-1] * m;
            index += m;
        }

        return answer;

    }
}</code></pre>
<h3 id="kotlin">Kotlin</h3>
<pre><code class="language-kotlin">class Solution {
    fun solution(k: Int, m: Int, score: IntArray): Int {
        var answer: Int = 0
        val score = score.sorted().reversed()
        var index : Int = 0
        while (true){
            if(index &gt;= score.size || index+m &gt; score.size){
                break
            }
            answer += score[index+ m -1] * m
            index += m
        }
        return answer
    }
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[문자열 밀기 JAVA / Kotlin]]></title>
            <link>https://velog.io/@blue-sky/%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%80%EA%B8%B0-JAVA-Kotlin</link>
            <guid>https://velog.io/@blue-sky/%EB%AC%B8%EC%9E%90%EC%97%B4-%EB%B0%80%EA%B8%B0-JAVA-Kotlin</guid>
            <pubDate>Sun, 13 Nov 2022 06:01:16 GMT</pubDate>
            <description><![CDATA[<p>*<em>JAVA 문자열 밀기 *</em></p>
<ul>
<li><p>subString 은 문자열  파싱하는 해주는 함수다.</p>
</li>
<li><p>*<em>substring(Value) *</em>
ex) &quot;HELLO WORLD&quot; =&gt; substring(6) =&gt; &quot;World&quot;</p>
</li>
<li><p>*<em>substring(Value1, Value2) : *</em>
ex) &quot;HELLO WORLD&quot; =&gt; substring(0,7) =&gt; &quot;HELLO W&quot;</p>
<pre><code class="language-java">class Solution {
  public int solution(String A, String B) {
      int answer = 0;

      String tA = A;
      for ( int i = 0 ; i &lt;A.length(); i++){
          if(tA.equals(B)){
              return answer; 
          }
          String a = tA.substring(tA.length() -1);
          tA = a + tA.substring(0, tA.length()-1);
          ++answer;
      }

      return -1;
  }
}</code></pre>
</li>
<li><p><em>Kotlin 문자열 밀기 *</em></p>
<pre><code class="language-kotlin">class Solution {
   fun solution(A: String, B: String): Int {
       var answer: Int = 0
       var tA: String = A
       for( i in 0..A.length){
           if( tA.equals(B)) return answer
           var a = tA.substring(tA.length-1)
           tA= a + tA.substring(0, tA.length-1)
           ++answer
       }
       return -1
   }
}</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[종이 자르기 Java/ Kotlin
]]></title>
            <link>https://velog.io/@blue-sky/%EC%A2%85%EC%9D%B4-%EC%9E%90%EB%A5%B4%EA%B8%B0-Java-Kotlin</link>
            <guid>https://velog.io/@blue-sky/%EC%A2%85%EC%9D%B4-%EC%9E%90%EB%A5%B4%EA%B8%B0-Java-Kotlin</guid>
            <pubDate>Sun, 13 Nov 2022 04:28:12 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120922?language=java">문제 출처</a></p>
<p>JAVA 첫 번째</p>
<ul>
<li>코드 실행은 맞았지만 제출에서 FAIL❌<pre><code class="language-java">class Solution {
  public int solution(int M, int N) {
      int answer = 0;
      answer = (M-1) + (N-1) * 2;
      return answer;
  }
}</code></pre>
</li>
</ul>
<p>JAVA 두 번째</p>
<ul>
<li><p>규칙성을 다시 파악하여 2*2 했을때 </p>
</li>
<li><p>4*4 했을때 규칙을 파악하여 다시 정의 성공⭕️</p>
<pre><code class="language-java">class Solution {
  public int solution(int M, int N) {
      int answer = 0;
      answer = (M * N) -1;
      return answer;
  }
}</code></pre>
<p>OR</p>
<pre><code class="language-java">class Solution {
  public int solution(int M, int N) {
      int answer = 0;

      if (M &lt; N) {
          answer += M-1;
          answer += (N-1)*M;
      } else {
          answer += N-1;
          answer += (M-1)*N;
      }

      return answer;
  }
}</code></pre>
</li>
</ul>
<h2 id="kotlin">Kotlin</h2>
<pre><code class="language-kotlin">class Solution {
    fun solution(M: Int, N: Int) = (M*N) -1
}</code></pre>
<p>OR</p>
<pre><code class="language-kotlin">import kotlin.math.*
class Solution {
    fun solution(M: Int, N: Int)= (max(M,N) - 1) + max(M,N) * (min(M,N) - 1)
}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[연속된 수의 합 Java/Kotlin]]></title>
            <link>https://velog.io/@blue-sky/%EC%97%B0%EC%86%8D%EB%90%9C-%EC%88%98%EC%9D%98-%ED%95%A9-JavaKotlin</link>
            <guid>https://velog.io/@blue-sky/%EC%97%B0%EC%86%8D%EB%90%9C-%EC%88%98%EC%9D%98-%ED%95%A9-JavaKotlin</guid>
            <pubDate>Sat, 12 Nov 2022 07:50:02 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120923?language=kotlin">문제 출처</a></p>
<h2 id="java">Java</h2>
<pre><code class="language-java">class Solution {
    public int[] solution(int num, int total) {
        int[] answer = new int[num];
        int nSum = num *(1+num)/2;
        int start = (total - nSum)/num; 
        for(int i =1; i&lt;num+1; i++){
            answer[i-1] = i+start;
        }

        return answer;
    }
}

</code></pre>
<h2 id="kotlin">Kotlin</h2>
<pre><code class="language-kotlin">class Solution {
    fun solution(num: Int, total: Int): IntArray {
        var answer: IntArray = IntArray(num)
        var nSum: Int = num *(1+num) /2
        var start : Int = (total - nSum)/num
        for (i in 1..num){
            answer[i-1] = i+start;
        }

        return answer
    }
}</code></pre>
<p>고수의 실력 코딩</p>
<pre><code class="language-kotlin">class Solution {
    fun solution(num: Int, total: Int): IntArray =
    (total / num - (num - 1) / 2).let { t -&gt; IntArray(num) { index -&gt; index + t } }

}</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[다음에 올 숫자 Java / Kotlin]]></title>
            <link>https://velog.io/@blue-sky/%EB%8B%A4%EC%9D%8C%EC%97%90-%EC%98%AC-%EC%88%AB%EC%9E%90-Java-Kotlin</link>
            <guid>https://velog.io/@blue-sky/%EB%8B%A4%EC%9D%8C%EC%97%90-%EC%98%AC-%EC%88%AB%EC%9E%90-Java-Kotlin</guid>
            <pubDate>Sat, 12 Nov 2022 05:55:35 GMT</pubDate>
            <description><![CDATA[<p><a href="https://school.programmers.co.kr/learn/courses/30/lessons/120924?language=java">자세한 문제</a></p>
<p><strong>첫 번째 풀이한 내용 JAVA</strong></p>
<ul>
<li><p>코드 실행 은 맞았지만 테스트 점수에서 Fail</p>
<pre><code class="language-java">class Solution {
  public int solution(int[] common) {
      int answer = 0;

      for (int i =1; i&lt;common.length; i++ ){
          if( common[i]-1 == common[i-1]){
              if( i+1 == common.length){
                  answer = common[common.length-1] + 1;
                  return answer;
              }
          }
          else{
               if( i+1 == common.length){
                   answer = common[common.length-1] * 2;
                  return answer;
               }
          }
      }
      return answer;
  }
}</code></pre>
</li>
<li><p><em>두 번째 풀이한 내용 JAVA*</em></p>
</li>
<li><p>코드가 아름답게 느껴진 적이 오랜만이다</p>
</li>
<li><p>확실히 수학공부를 빡세게 해야겠다. </p>
<pre><code class="language-java">class Solution {
  public int solution(int[] common) {
      int answer = 0;

      if ( (common[1] - common[0] )== (common[2] - common[1])){
          answer = common[common.length-1] + (common[1] -common[0]);
      } else{
          answer = common[common.length-1] * (common[1] / common[0]);
      }
      return answer;
  }
}</code></pre>
</li>
<li><p><em>첫 번째 풀이한 내용 Kotlin*</em></p>
<pre><code class="language-kotlin">class Solution {
   fun solution(common: IntArray): Int {
       var answer: Int = 0

       if( (common[1] - common[0]) ==  (common[2]- common[1])){
           answer = common[common.size-1] + (common[1] - common[0])
       } else{
           answer = common[common.size-1] * (common[1] / common[0])    
       }
       return answer
   }
}</code></pre>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Android Platform Architecture]]></title>
            <link>https://velog.io/@blue-sky/Android-Architecture</link>
            <guid>https://velog.io/@blue-sky/Android-Architecture</guid>
            <pubDate>Sun, 23 Oct 2022 11:56:45 GMT</pubDate>
            <description><![CDATA[<p>안드로이드는 6계층으로 이루워져 있습니다 .</p>
<blockquote>
<p>1.System Apps : Dialer/ Email/  Calendar / Camera
2.Java API Framework  : Content Proivder / View System / Managers
3. Navtive C/C++ Libraries<br>4. Android Runtime
5.Hardware Abstraction Layer(HAL)
6.Linux Kernel
<img src="https://velog.velcdn.com/images/blue-sky/post/9edf6a27-9a00-4827-b3b6-962fc6590728/image.png" alt=""></p>
</blockquote>
<h2 id="🍎linux-kernel">🍎Linux Kernel</h2>
<h3 id="kerenl">Kerenl</h3>
<blockquote>
<p>하드웨어와 응용 프로글매 사이에서 인터페이스를 제공하여  하드웨어의 자원 관리 및 사용 하게 하는 것</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/100a021a-23f2-44bf-a0a0-d8c6affd560a/image.png" alt=""></p>
<p>운영체제는 소프트웨어에 속하며 소프트웨어가 실행되기 위해서는 메모리에 소프트웨어가 올라가야 한다. </p>
<p>하지만 운영체제와 같이 많은 큰 소프트웨어가 모두 메모리에 올라가면 메모리 낭비가 심하게 일어날 것이다. 따라서 OS 는 필요한 부분만 메모리에 올리고 나머지는 필요할 때 메모리를 올린다.</p>
<h3 id="linux-kernel">Linux Kernel</h3>
<blockquote>
<p>안드로이드 런타임은 스레드 및 메모리 관리를 리눅스 커널 계층에서 진행
(메모리 ,보안 ,전원 , 하드웨어 장치 드라이버) </p>
</blockquote>
<h2 id="🍎-hal계층">🍎 HAL계층</h2>
<blockquote>
<p>Java API Framework 하드웨어 기능을 노출하는 표준 인터페이스 제공
(카메라 , 블루투스 오디어 ,센서 등 하드웨어 구성요소 위한 인터페이스 ) </p>
</blockquote>
<p>프레임워크 API가 기기 하드웨어에 액세스하기 위해 호출을 수행하면 Android 시스템이 해당 하드웨어 구성 요소에 대한 라이브러리 모듈을 HAL 계층에서 로드한다.</p>
<h2 id="🍎-native-libraries계층">🍎 Native Libraries계층</h2>
<blockquote>
<p>C/C++ 로 작성된 네이티브 라이브러리 필요로 하는 네이티브 코드로 기반 빌드</p>
</blockquote>
<p>안드로이드는 사앧적으로 작은 용량의 주기억장치와 저전력의 CPU가 탑재된 기기에서 동작하기 때문에 이러한 기기에 최적화된 원시코드로 컴파일 됩니다. </p>
<p>libc 와 libm과 같은 라이브러리 특히 메모리 소비가 적기때문에 안드로이드에 적합합니다. 주로 SQLite , WebKit , OpenGL 같은 안드로이드에 필수적인 네이티브 라이브러리가 들어가 있다.</p>
<ul>
<li>SGL : 2D 그랙픽 담당</li>
<li>Open GL ES : 2D/3D 그래픽 담당</li>
<li>Free Type : 폰트 렌더링</li>
<li>WebKit : 웹 브라우저 엔진</li>
<li>libc : 시스템 C 라이브러리</li>
<li>SQLite : 모바일을 위한 경량화된 데이터 베이스</li>
<li>SSL : Secure Socket Layer 프로토콜</li>
</ul>
<h2 id="🍎-java-api-framework">🍎 Java API Framework</h2>
<blockquote>
<p>안드로이드 프레임워크 사용에 필요한 API들을 이 자바 API 프레임워크 계층에서 제공하고 있다.</p>
</blockquote>
<ul>
<li>Resource Manager : 현지화된 문자열, 그래픽 및 레이아웃 파일과 같은 코드가 아닌 리소스에 대한 액세스 제공</li>
<li>Notification Manager : 모든 앱이 상태 표시줄에 사용자 지정 알림을 표시할 수 있도록 지원</li>
<li>Activity Manager : 앱의 수명 주기를 관리하고 공통 탐색 백 스택 제공</li>
<li>콘텐츠 제공자 : 앱이 주소록 앱과 같은 다른 앱의 데이터에 액세스하거나 자신의 데이터를 공유할 수 있도록 지원</li>
</ul>
<h2 id="🍎-system-apps">🍎 System Apps</h2>
<blockquote>
<p>사용자를 위한 앱으로도 작동하고 개발자가 자신의 앱에서 액세스할 수 있는 주요 기능을 제공하기 위한 용도로 존재한다. </p>
</blockquote>
<p>사전에 설치된 앱 또는 System.img(Android OS AOSP Img) 등 여러가지 용도로 직접 빌드할 필요없이 앱을 호출하여 제공할 수 있게 해준다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[객체지향 SOLID 원칙  (수정중)]]></title>
            <link>https://velog.io/@blue-sky/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-SOLID-%EC%9B%90%EC%B9%99</link>
            <guid>https://velog.io/@blue-sky/%EA%B0%9D%EC%B2%B4%EC%A7%80%ED%96%A5-SOLID-%EC%9B%90%EC%B9%99</guid>
            <pubDate>Sun, 02 Oct 2022 05:31:37 GMT</pubDate>
            <description><![CDATA[<h2 id="원칙">원칙</h2>
<blockquote>
<p>어떠한 이론 및 행동에서 한결같이 <strong>지켜야 하는</strong> <strong>기본적인 규칙 및 법칙</strong></p>
</blockquote>
<p>우리는 삶을 살아가기 위해 주어진 원리/원칙 아래서 생활하고 있습니다.</p>
<p>이러한 원칙을 &quot;왜&quot;? 지켜야 할까요? </p>
<p>좁은 의미로는 사고방식, 신념, 가치관 될 수가 있고</p>
<p>넓은 의미로는 국가의 통치 이념 통치 방법으로 될 수가 있습니다.</p>
<p>즉, 이러한 원칙을 적용하는 이유는 개인의 &quot;삶&quot;과  국민의 &quot;삶&quot;을 <strong>효율적으로 향상</strong>시키 때문입니다.</p>
<h2 id="소프트웨어-관점의-원칙">소프트웨어 관점의 원칙</h2>
<blockquote>
<p>기계의 행위를 쉽게 변경할 수 있도록 하는 것</p>
</blockquote>
<h3 id="왜">왜?</h3>
<p>소프트웨어 : Soft (부드러운 ) Ware(제품)  입니다.</p>
<p>결국 소프트웨어는 부드러움을 가지고 있는 제품이기 때문에 소프트웨어의 본연의 법칙을 추구하려면 반드시 <strong>&quot;부드러워&quot;</strong>야 한다.</p>
<p>변경이 쉽게 할려면,   기획 이나 디자인 쪽에서 기능에 대한 생각을 바꾸면 변경사항을 바꾸는데 어려움이 없어야 합니다.</p>
<p>소프트웨어 개발 비용의 증가는 바로 이러한 형태의 어려움에 있기 때문입니다.</p>
<h2 id="solid-원칙">SOLID 원칙</h2>
<blockquote>
<p>변경에 유연하며 , 이해하기 쉽다 , 많은 소프트웨어에서 사용할 수 있는 컴포넌트의 기반이 된다.</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/40145d9a-b1df-476d-beb3-0f1c8400a23f/image.png" alt=""></p>
<h3 id="좋은-소프트웨어-시스템">좋은 소프트웨어 시스템?</h3>
<p>좋은 소프트웨어 시스템은  Clean Code 로 부터 나옵니다.
극단적으로 음식을 예로 들자면,<br>
좋은 요리사 -&gt; 좋은재료 -&gt; 좋은 음식
좋은 요리사 -&gt; 나쁜재료 -&gt; 좋은 음식 OR 나쁜 음식 
초보 요리사 -&gt; 좋은재료 -&gt; 좋은 음식 OR 나쁜 음식 
초보 요리사 -&gt; 나쁜재료 -&gt; 나쁜 음식</p>
<p>*<em>SOLID는 좋은 요리사로 좋은 재료를 만드는 것을 의미합니다. *</em></p>
<h2 id="solid의-원칙-5가지">SOLID의 원칙 5가지</h2>
<p>** 단일 책임 원칙 **: Single Responsibility Principle(SRP) </p>
<p><strong>개방 폐쇄의 원칙</strong> : Open Close Principle (OCP) </p>
<p><strong>리스코프 교체의 원칙</strong> : Liskov Substitution Principle(LSP)</p>
<p><strong>인터페이스 분리의 원칙</strong> : Interface Segregation Principle(ISP)</p>
<p>*<em>의존 관계 역전의 원칙 *</em>: Dependency Inversion Principle(ISP)</p>
<h3 id="single-responsibility-principle-srp">Single Responsibility Principle (SRP)</h3>
<blockquote>
<p>클래스르 변경하는 이유는 단 한가지 여야 한다.</p>
</blockquote>
<p>&quot;하나의 클래스는은 오직 하나 , 오직 하나의 액터에 대해서만 책임져야 한다.&quot; </p>
<p>모듈 : 소스 파일
액터 : 해당 변경을 요청하는 한 명 이상의 사람들 (클래스 ,모듈)</p>
<p><strong>즉, 하나의 클래스는 하나의 기능을 가지는게 좋다</strong> 입니다.</p>
<h3 id="before-srp">Before SRP</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/cd975e80-67db-4fc9-a9f7-7bc058c3bb4a/image.png" alt=""></p>
<p>Car Class 안에 하나의 클래스안에 하나의 액터만 책임을 저야하는데 총 4개를 책임지고 있다.</p>
<p>이는, SRP 원칙에 위배된다.</p>
<p>만약 , Drive 가 사용하는 코드가 변경이 된다면 Drive 뿐만 아니라 ,Car/ CarWash Mechanic 을 
재컴파일 재배포를 해야합니다.</p>
<p>이처럼 클래스에 많은 책임이 있는 경우 책임 중 하나를 변경하면 사용자가 모르는 사이에 다른 책임에 영향을 줄 수 있으므로 버그가 발생할 가능성이 높아집니다.</p>
<p>또한 응집도 처럼 동일한 기능이 잘 뭉쳐져 있는 것이 제일 좋다 </p>
<h3 id="after-srp">After SRP</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/c4696f06-2f75-4ed5-8a20-f762a0923bfa/image.png" alt=""></p>
<p>이처럼 각 클래스에안에 하나의 액터만 책임을 진행이 된다면
변경이 발생하더라도 다른 관련 없는 동작에 영향을 미치지 않습니다.</p>
<ul>
<li>쉬운 테스트 : 책임이 하나인 클래스는 테스트 케이스가 줄어들기 때문에  테스트가 쉬워진다.</li>
<li>낮은 결합 :  단일 클래스의 기능이 적어져 종속성이 줄어든다.</li>
<li>쉬운 검색 : 작고 잘 조직된 클래스는 검색하기 쉽다.</li>
<li>구현하기 쉬움  : 하나의 책임을 가지고 있기때문에 구현하기가 쉽다.</li>
</ul>
<h3 id="open-close-principle-ocp">Open Close Principle (OCP)</h3>
<blockquote>
<p>소프트웨어 객체는 확장(상속)에는 열러 있어야 하고, 변경에는 닫혀 있어야 한다.</p>
</blockquote>
<p>&quot;기능을 추가할 때 기존의 코드를 변경하지 않고 추가할 수 있어야 한다&quot;</p>
<p>만약 당신이 요구사항을 살짝 확장하는데 소프트웨어를 엄청나게 수정해야 한다면?</p>
<ul>
<li>개발 비용 증가</li>
<li>시간적 요소 증가</li>
<li>흥미 유발 감소 </li>
</ul>
<h3 id="before-ocp">Before OCP</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/9e7ebbc6-ee08-4f48-afb6-5e1c6da5911e/image.png" alt=""></p>
<p>File을 DB에 저장할려면 FileStorage 클래스를 수정해야 합니다.
이는 FileStorage 클래스가 확장과 수정에 대하여 열려있다는 것을 보여주는 것 입니다.</p>
<h3 id="after-ocp">After OCP</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/bba8c248-d344-4b70-bbb3-ee2f623edef4/image.png" alt=""></p>
<p>save() 추상 메소드를 가지고 있는 Firestorage를  추상 클래스를 정의하고 , File 객체를 저장하기 위한 ORACLE , MYSQL 클래스를 만듭니다. 이 클래스는 FileStorage 클래스를 상속하고 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/203f3877-4386-40c0-a6bc-c1652b6b542f/image.png" alt=""></p>
<p>이처럼 추상클래스를 이용해 상속을 하면 FileStorage에 수정 없이 DB를 추가할 수 있게 되어 OCP를 따를수 있습니다.</p>
<h3 id="liskov-substitution-principle-lsp">Liskov Substitution Principle (LSP)</h3>
<blockquote>
<p>서브타입은  언제나 기반 타입으로 교체할 수 있어야 한다</p>
</blockquote>
<p>&quot;상위 타입의 객체를 하위 타입의 객체로 치환해도 상위 타입을 사용하는 프로그램은 정상적으로 동작해야 한다.&quot;
&quot;자식 클래스는 부모 클래스를 대체할 수 있어야 한다.&quot;</p>
<h4 id="대표적인-문제인-rectangle--square-문제다">대표적인 문제인 Rectangle / Square 문제다</h4>
<p>직사각형 -&gt; 정사각형 (x)
정사각형 -&gt; 직사각형 (O)</p>
<pre><code class="language-java">public class Rectangle {
    private int width;
    private int height;

    public void setWidth(final int width) {
        this.width = width;
    }

    public void setHeight(final int height) {
        this.height = height;
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }
}</code></pre>
<h4 id="직사각형-객체를-상속받아서-아래처럼-정사각형-객체를-재정의-할-수-있습니다">직사각형 객체를 상속받아서 아래처럼 정사각형 객체를 재정의 할 수 있습니다.</h4>
<pre><code class="language-java">public class Square extends Rectangle {

    @Override
    public void setWidth(final int width) {
        super.setWidth(width);
        super.setHeight(width);
    }

    @Override
    public void setHeight(final int height) {
        super.setWidth(height);
        super.setHeight(height);
    }
}
</code></pre>
<p>다만, 정사각형은 가로와 세로의 길이가 같으므로 setWidth()나 setHeight()를 호출하면 가로와 세로를 모두 값을 바꿔줘야해서 메소드를 재정의하였습니다.</p>
<pre><code class="language-java">    public void increaseHeight(final Rectangle rectangle) {
        if (rectangle.getHeight() &lt;= rectangle.getWidth()) {
            rectangle.setHeight(rectangle.getWidth() + 1);
        }
    }</code></pre>
<ul>
<li>직사각형의 가로와 세로를 비교한다</li>
<li>세로가 가로보다 짧거나 같다면 가로의 길이에 1을 더한 만큼의 길이를 갖게 만드는 역할한다.</li>
<li>정사각형이 아닌 직사각형에 대해서는 위 메소드가 올바로 작동 합니다.</li>
</ul>
<p><strong>하지만, 정사각형의 경우는 다르다.</strong></br> 정사각형은 항상 가로와 세로의 길이가 같으므로 위 메소드를 실행하면 가로와 세로 모두 1씩 증가한다.</p>
<p>즉, 우리가 원하는 &quot;메소드 실행 후, 직사각형의 길이는 가로보다 세로가 길어야 한다.&quot;는 가정이 깨지게 되는 것입니다. 따라서, <strong>instanceof를 통해 타입 비교를 해야 합니다.</strong></p>
<pre><code class="language-java">    public void increaseHeight(final Rectangle rectangle) {
        if (rectangle instanceof Square) {
            throw new IllegalStateException();
        }

        if (rectangle.getHeight() &lt;= rectangle.getWidth()) {
            rectangle.setHeight(rectangle.getWidth() + 1);
        }
    }</code></pre>
<p>이렇게 해당 도형이 정사각형일 경우 익셉션을 발생시키는 식으로 코드를 수정할 수 있습니다. 
하지만, 이것은 개방 폐쇄 원칙에 어긋나는 코드입니다. 
왜냐하면, increaseHeight()가 확장에는 열려 있지 않기 때문이죠.</p>
<p>즉 , 상속을 할때는 치환을 해도 정상작동이 되도록 만들어야한다. 
만약 그렇지 않을경우에는 상속을 받으면 안된다.</p>
<h3 id="interface-segregation-principleisp">Interface Segregation Principle(ISP)</h3>
<blockquote>
<p>어떤 클래스가 인터페이스를 </p>
</blockquote>
<p>&quot;하나의 일반적인 인터페이스 보다 여러개의 구체적인 인터페이스를 사용해라&quot; </p>
]]></description>
        </item>
        <item>
            <title><![CDATA[언어란 무엇인가  ]]></title>
            <link>https://velog.io/@blue-sky/%EC%96%B8%EC%96%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EC%88%98%EC%A0%95%EC%A4%91</link>
            <guid>https://velog.io/@blue-sky/%EC%96%B8%EC%96%B4%EB%9E%80-%EB%AC%B4%EC%97%87%EC%9D%B8%EA%B0%80-%EC%88%98%EC%A0%95%EC%A4%91</guid>
            <pubDate>Thu, 29 Sep 2022 04:16:00 GMT</pubDate>
            <description><![CDATA[<h3 id="내가-생각하는-언어의-정의">내가 생각하는 언어의 정의</h3>
<blockquote>
<p>사람들이 자신의 생각을 다른 사람들에게 나타내고 전달하기 위해 사용하는 체계.</p>
</blockquote>
<h3 id="📌-언어의-정의는-다양하다">📌 언어의 정의는 다양하다</h3>
<ul>
<li>사람들이 <strong>자신의 생각</strong>을 다른 사람들에게** 나타내고 전달하기 위해** 사용하는 체계.</li>
<li>사물, 행동, 생각, 그리고 상태를 나타내는 체계.</li>
</ul>
<p>-
언어 공동체 내에서 이해될 수 있는 말의 집합.</p>
<h3 id="📍-결국-공통적인-부분은-이해와-전달이-핵심이다">📍 결국, 공통적인 부분은** 이해와 전달**이 핵심이다.</h3>
<h2 id="이해와-전달을-잘-하기-위해서는">이해와 전달을 &quot;잘&quot; 하기 위해서는?</h2>
<h4 id="언어를-디자인하라-책-한구절의-내용">언어를 디자인하라 책 한구절의 내용</h4>
<blockquote>
<p>&quot;<strong>천박한 언어</strong>를 사용하는 사람은 생각의 높이가 <strong>낮고</strong> 인격이 <strong>무너져 있다.</strong>
그러니 다른 사람을 <strong>감동</strong>시킬 수도 없다&quot;</p>
</blockquote>
<p><strong>사고 : &quot;목표에 이르는 방법을 찾으려고 하는 정신 활동&quot;</strong></p>
<p>이 말의 요지는 &quot;언어가 빈약하면 <strong>사고도 더불어 빈약</strong>해진다&quot; 이며 ,
<strong>&quot;사람은 비슷한 사람과 어울린다&quot;</strong>  입니다.</p>
<p>주관적인 개발자 관점에서 보면 &quot;개발&quot; 을 진행할 때 &quot;사고&quot;를 명확히 설정하지 목적성과 목표에 대한 관점이 흐지부지 해진다. 그래서 개발하기 이전에 회사에 대한  <a href="https://velog.io/@yukina1418/%EC%B7%A8%EC%A4%80%EC%83%9D%EC%97%90%EA%B2%8C-%EB%8F%84%EB%A9%94%EC%9D%B8%EC%9D%B4-%EC%A4%91%EC%9A%94%ED%95%9C%EA%B0%80%EC%9A%94">도메인</a> 지식과 시장에 대한 분석도 필요하다.</p>
<p>비슷한 사람과 어울린다는 결국 신입으로 들어갔을 때 사수의 영향을 많이 받<strong>는다. 코드의 품질 , 아키텍쳐 , 커뮤니케이션</strong> 방식 등 닮아가게 된다.</p>
<p>이게 어떻게 보면 <strong>양면의 칼날</strong> 인게 실무를 경험하면서 코드를 배우게 되지만 사수의 </br>방식에 따라 &quot;독&quot;이 될 수도 있고, &quot;득&quot;이 될 수도 있다.</p>
<p>그렇다고 좋은 사수가 있는 곳으로 가라는 것이 아니라 , 코드를 공부하면서 스스로의 자기만의 <strong>언어 정체성</strong>(코드)를 가져가는 것이 중요하다 </p>
<p>나만의 정체성이 있는 <strong>코드를 작성</strong>하고 <strong>코드를 해석</strong>하고 
<strong>다른사람과  코드리뷰하는 과정</strong>에서 가장 나다운 길로 안내해줄 것이다.</p>
<h2 id="언어의-한계란">언어의 한계란?</h2>
<h3 id="비트겐슈타인-언어-철학자">비트겐슈타인 (언어 철학자)</h3>
<blockquote>
<p>&quot;내 언어의 한계는 내 세계의 한계를 의미한다&quot;</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/1c438c12-fccb-4902-a0f8-585e8f007873/image.png" alt=""></p>
<h3 id="c-언어-창시자-bjarne-stroustrup">C++ 언어 창시자 (Bjarne Stroustrup)</h3>
<blockquote>
<p>개발자라면 적어도 5개의 언어를 알아야 한다</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/d39b7dbc-2e17-4bd4-82b6-0a1fdc599a2b/image.png" alt=""></p>
<p>&quot;너가 한개의 언어만 할 줄 안다면 한개의 문화로만 한정하여 생각하게 된다&quot;
&quot;만약 <strong>여러 언어를 배운다면 *<em>폭 넓게 사고하고 *</em>더 나은 사람</strong>이 되게끔 해준다&quot;</p>
<p>개발자라면 &quot;누구나&quot; &quot;문제&quot;에 직면하게 된다. 
이러한 문제 해결을 아마추어 와 프로로 나눠서 보면</p>
<h3 id="문제해결">문제해결</h3>
<h3 id="프로">프로</h3>
<ul>
<li>남들과 다른 언어 및 기존에 없던 생각으로 문제를 접근한다</li>
<li>자신의 객관화(한계 간파) 하여 다른 생각을 찾기 위해 관련된 정보(책) OR 분야의 대가를 찾아간다.</li>
</ul>
<h3 id="아마추어">아마추어</h3>
<ul>
<li>기존의 생각, 틀에 박힌 언어 안에서 뱅뱅 돌면서 대안을 못찾고 , 해결도 안된다. </li>
</ul>
<p>이 상황을 극단적인 예시이긴 하지만 , <strong>초급 개발자는 스스로 상황을 판단하고 정보를 해석할 능력이 부족</strong>하기 때문에 , 
도음을 요청하는 대신 자신의 작성한 코드를 한 줄 씩 살펴보며 고민에 빠집니다.</p>
<ul>
<li>코드베이스</li>
<li>배포 동작 방식</li>
<li>다른 팀에서 호출하는 API 등 </li>
</ul>
<p>이러한 부분은 혼자 고민해도 알기 힘든 부분이며 다른 누구간에게 도움을 요청하는 것이 훨씬 효율적입니다.</p>
<h2 id="무엇이-좋은-개발자를-만드는가">무엇이 좋은 개발자를 만드는가?</h2>
<blockquote>
<p>이 질문은 스스로의 고찰이 필요한 시점이다.</p>
</blockquote>
<h3 id="이-질문을-왜-던질까-why">이 질문을 왜 던질까? Why</h3>
<p>아마 이 질문을 던졌을 때 단순히 <strong>&quot;많은 돈&quot;== &quot;좋은 개발자&quot;</strong> 생각 된다면 ,
 우리는 &quot;비교&quot;라는 단어에 의해 개발자의 &quot;본질&quot;이 흐려진다.( 세상에는 나보다 잘버는 사람이 많으니까)</p>
<p> 주관적인 생각은 개발을 꾸준히 유지하고 &quot;잘&quot; 하기 위해서는 <strong>철학적인 관점으로 스스로 정의를 내릴 필요가 있다.</strong>
 &quot;돈&quot; 이라는 것은 &quot;기준&quot;에 의해 변동성이 있는 의미 이기에<br>&quot;자신의 신념&quot; ,&quot;확고한 의지&quot;가 있는 자신만의 정의가 <strong>스스로 가질 수 있는 귀중한 자산</strong>이다</p>
<h4 id="james-gosling-java-창시자">James Gosling (JAVA 창시자)</h4>
<blockquote>
<p> 삶의 윤리적인 선택에 대해서 생각할 때 내가 내리는 <strong>선택(코딩)이 어떠한 세상을 만드는지 고민</strong>해야한다.</p>
</blockquote>
<h4 id="george-hotz-미국의-유명한-해커">George Hotz (미국의 유명한 해커)</h4>
<blockquote>
<p>프로그래밍은 배우는 것이 아니라 하고 싶은 일을 <strong>코딩으로 해결 할 수 있는 방법을 찾는것</strong> 이다.</p>
</blockquote>
<h4 id="travis-oliphant--numpy---scipy-anaconda-창시자">Travis Oliphant. ( numpy ,  SciPy, Anaconda 창시자)</h4>
<blockquote>
<p>배우고자 하는 의지 와 <strong>호기심</strong>이 있어야 한다. <strong>본인의 다 안다고 생각하지 말것</strong></p>
</blockquote>
<h2 id="마무리">마무리</h2>
<p><strong>&quot;언어를 키워야 하는 이유&quot;</strong></p>
<p>우리가 평상시에 사용하는 언어는 세상을 바라보고 나만의 방식으로 생각하고 표현하기 위해서이다.
언어는 또한 내가 세상을 바라보는 자세이자 태도이고 , 깊이과 관점에 따라 결정이 된다. 또한 사유하는 방식까지 결정하여 언어가 바뀌지 않은면 사고도 바뀌지 않는다. </p>
<p><strong>&quot;해상도 높은 언어를 갖자&quot;</strong></p>
<blockquote>
<p>해상도 : 종이나 스크린 등에 표현된 그림이나 글씨 따위가 표현된 섬세함의 정도</p>
</blockquote>
<ul>
<li>이 언어가 최고더라 </li>
<li>이 언어가 편하더라 </li>
</ul>
<p>이런말은 &quot;누구나&quot; 할 수 있다.  당신이 <strong>원하던 &quot;회사&quot; 면접관에게도</strong> 이러한 방식으로 <strong>면접을 진행</strong>한다면 결과는...
언어의 대한 생각과 이해도가 깊은 사람은 어떠한 개발을 진행할 때도 <strong>효율성,명확성,필요성 여러가지 관점</strong>에서 진행하기에 <strong>회사 개발에 대해서도 큰 이익을 미칠 수 있다.</strong></p>
<p>또한 &quot;어렴풋이 알고 있는 것을 누군가가 언어(기술)로 분명하게 말해주면 이렇게 마음이 편안해진다&quot; - (안녕 사모키타자의 소설)
당신도 느낄 것이다.
기술을 설명할 때  <strong>&quot;어린아이&quot; 가 이해시켜줄 정도로</strong> 쉽게 이해 시켜주는 사람들은 그러한 이해를 시키기위해 <strong>깊은 기술에 대한 해상도가 있기 때문이다</strong></p>
<p>이글을 더 쓰고싶지만 아직 나의 정보의 한계가 있기 때문에 나중에 글을 더 수정할 생각이다
마지막 내가 좋아하는 명언을 남기고 마친다...</p>
<blockquote>
<p>We can&#39;t solve our problems with the same thinking we used when we created them - Albert Einstein
<img src="https://velog.velcdn.com/images/blue-sky/post/0fd5d9a4-f6f2-470d-ac95-6c522ef604ff/image.png" alt=""></p>
</blockquote>
<p>참고 자료 </p>
<ul>
<li><a href="https://www.aladin.co.kr/shop/wproduct.aspx?ItemId=299442312">언어를 디자인 하라 </a></li>
<li><a href="https://velog.io/@yukina1418/%EC%B7%A8%EC%A4%80%EC%83%9D%EC%97%90%EA%B2%8C-%EB%8F%84%EB%A9%94%EC%9D%B8%EC%9D%B4-%EC%A4%91%EC%9A%94%ED%95%9C%EA%B0%80%EC%9A%94">신입이 도메인 지식이 필요한 이유</a></li>
<li><a href="https://youtu.be/ZGSJsaA3ma4">전설을 프로그래머 형님들의 &quot;찐&quot; 개발 훈수</a></li>
<li><a href="https://yozm.wishket.com/magazine/detail/1373/">10 배 이상 뛰어난 개발자가 되는법</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Room]]></title>
            <link>https://velog.io/@blue-sky/Android-Room</link>
            <guid>https://velog.io/@blue-sky/Android-Room</guid>
            <pubDate>Sun, 11 Sep 2022 07:18:33 GMT</pubDate>
            <description><![CDATA[<h3 id="room">Room</h3>
<blockquote>
<p>로컬 데이터 베이스로 오프라인 상태에서도 탐색 하도록 데이터를 케시하는 것</p>
</blockquote>
<p>Room은 원래 의미는 &quot;방&quot; 이다 . 왜 &quot;Room&quot;이라고 지었을까? 
개인적인 의견으로 , 우리는 외부로 위험 및 보호를 하기 위해 자신의 &quot;Room&quot;안에서 지낸다. </p>
<p>이처럼 모바일도 외부로부터의 위험을 보호해야 한다.</p>
<ul>
<li>네트워크가 끊길경우 작업중인 문서 작업 및 기록이 저장해야 된다.</li>
<li>네트워크가 없는 앱일 경우 사용자 모바일 안에서 저장을 해야한다.</li>
</ul>
<h3 id="로컬-데이터-베이스는-무엇일까">로컬 데이터 베이스는 무엇일까?</h3>
<blockquote>
<p>외부 통신 없이  DB를 사용하고 싶을때 유용한 것 </p>
</blockquote>
<p>주로 Room은 상당한 양의 구조화된 데이터를 처리할 때 데이터를 로컬에 유지하면 사용자가 보고 있던 데이터의 작업 및 위치를 알 수 있습니다.</p>
<p>만약 당신이 앱안에서 문서 작업을 하는 도중 앱이 꺼져서 데이터가 다 날라간다면?</p>
<ol>
<li>다시 처음부터 작업한다</li>
<li><strong>로컬 DB에 저장하여 다시 켜서 유지한다</strong>.</li>
</ol>
<p>극단적 예시이지만, 당연히 <strong>2번을 선택 할 것</strong>이다. 
 앱을 사용하면서도 꾸준하게 데이터를 계속 저장할 필요가 있습니다. </p>
<p>안드로이드 에서는  저장하는 방법이  여러 가지 방식으로 저장하지만 ,이 글에서는 Room에 대해서만 언급할 것입니다.</p>
<h3 id="why-use-room">Why use Room?</h3>
<p>기존 오프라인(네트워크 ❌) 일 경우 Android 에서는 가벼운 관계형 DB인 SQLite를 라이브러리에 포함되어 있었습니다. </p>
<p>하지만❗️ SQLite는 다음과 같은 이유로 Room을 권장하게 되었습니다.</p>
<p> <strong>SQL 쿼리에 대해서 올바르게 작성이 되었는지 컴파일 타임에 확인할 수가 있다.</strong> <br>  </p>
<ul>
<li>기존 SQLite는 컴파일 타임에 검증읆 못했다 이를 못할시,  잘못된 Query를 사용했을 때 오류를 직접 업데이트를 해야합니다. </li>
<li>Room은 컴파일 타임에 유효성 검사를 진행하여 이를 예방할 수 있습니다.</li>
</ul>
<p><strong>SQL쿼리와 데이터 객체와의 변환이 자유롭지 않습니다.</strong></p>
<ul>
<li>즉. 사용하기 어렵다는 뜻이다. Room은 이러한 문제들을 자동으로 처리할 수 있도록 도와준다.</li>
</ul>
<h3 id="room-구성요소">Room 구성요소</h3>
<p><strong>Room 은 크게 3가지로 구성되어있습니다.</strong></p>
<ul>
<li>데이터 항목<strong>(Entity)</strong> : 앱 데이터베이스의 테이블을 나타냅니다.</li>
<li>데이터 엑세스 객체<strong>(DAO)</strong> : 엡 DB 안의 쿼리 ,CRUD 등 사용할 수 있는 메소드 제공</li>
<li>데이터베이스 클래스<strong>(Room DB)</strong> :  DB를 보유하고 앱의 영구 데이터 및 기본 연결을 위한 엑세스 포인트 역할</li>
</ul>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/d847252e-7016-41d6-b345-8ce006b41875/image.png" alt=""></p>
<h3 id="데이터-항목-entity">데이터 항목 (Entity)</h3>
<blockquote>
<p>DB 안 테이블의 데이터의 항목을 정의하는 곳입니다.</p>
</blockquote>
<ul>
<li>@Entity  :  해당 클래스의 테이블 이름을 나타내며 테이블 이름을 바꿀 수도 있다.</li>
<li>@PrimaryKey : 테이블 안에 데이터를 구분할 수 있게 하는 기본키다.</li>
<li>@ColumnInfo : 테이블 안애 컬럼입니다. 이름 변경이 가능합니다.</li>
<li>@Ignore : 테이블의 유지하고 싶은 데이터가 있을 경우 사용합니다.</li>
</ul>
<p>*<em>쇼핑몰 회원가입 예시로 테이블을 만들어보자 *</em></p>
<ul>
<li>User라는 Data Class를 만든후 @Entity 를 선언한다</li>
<li>@Primarey는 uid 고유값으로 지정</li>
<li>@ColumnInfo 는 (first_name)으로 변경해서 저장했다.<pre><code class="language-kotlin">@Entity
data class User(
  @PrimaryKey val uid: Int,
  @ColumnInfo(name = &quot;first_name&quot;) val firstName: String?,
  @ColumnInfo(name = &quot;last_name&quot;) val lastName: String?
)</code></pre>
</li>
</ul>
<h3 id="데이터-엑세스-객체dao">데이터 엑세스 객체(DAO)</h3>
<blockquote>
<p>모바일 DB 안에서 CRUD를 하요 상호작용하는 부분이다.</p>
</blockquote>
<p>간단히 말하면 데이터를 요리하는 곳이다. 우리가 요리 할 때 원하는 재료를 가져다 사용하며 필요하지 않거나 썩으면 버리게 된다. </p>
<p>이처럼 데이터를 삽입 , 삭제 , 변경 ,  할 때 사용된다.</p>
<ul>
<li>@Dao : Room이 인터페이스를 Dao로 식별할 수 있도록 하기 위해서</li>
<li>@Insert  : 데이터를 삽입할때 사용된다.</li>
<li>@Select : 데이터를 선택할 때 사용된다.</li>
<li>@Update. : 데이터를 업데이트 할 때 사용된다 </li>
<li>@Delete : 데이터를 삭제할 때 사용된다.</li>
<li>@Query. : 쿼리를 사용하여 원하는 DB를 조회할 수 있다.</li>
</ul>
<p><strong>쇼핑몰 사용할 것들</strong></p>
<ul>
<li><p>전체 사용자 목록을 조회한다. </p>
</li>
<li><p>현재 사용자의 고유 UID (Primary key) 사용하여 데이터 찾기</p>
</li>
<li><p>사용자에 정보에 대해 삽입</p>
</li>
<li><p>사용자 정보 삭제 </p>
<pre><code class="language-kotlin">@Dao
interface UserDao {
  @Query(&quot;SELECT * FROM user&quot;)
  fun getAll(): List&lt;User&gt;

  @Query(&quot;SELECT * FROM user WHERE uid IN (:userIds)&quot;)
  fun loadAllByIds(userIds: IntArray): List&lt;User&gt;

  @Insert
  fun insertAll(vararg users: User)

  @Delete
  fun delete(user: User)
}</code></pre>
</li>
</ul>
<h3 id="데이터베이스-클래스room-db">데이터베이스 클래스(Room DB)</h3>
<blockquote>
<p>DB를 보유할 AppDatabase클래스 정의 하는 곳</p>
</blockquote>
<p>사용자가 생성한 Entity(table)들을  가져와서 구성을 정의한다. </p>
<ul>
<li>entities: [table name::class] 가 들어간다</li>
<li>version : 사용자가 사용하는 버전관리를 위해 사용된다.</li>
<li>추상메소드 정의 :   (Dao Class Name)   를 가져와서 추상 메소드를 정의한다. </li>
</ul>
<pre><code class="language-kotlin"> @Database(entities = [User::class], version = 1)
abstract class AppDatabase : RoomDatabase() {
    abstract fun userDao(): UserDao
}</code></pre>
<h3 id="데이터베이스-사용room-db">데이터베이스 사용(Room DB)</h3>
<pre><code class="language-kotlin"> val db = Room.databaseBuilder(
            applicationContext,
            AppDatabase::class.java, &quot;database-name&quot;
        ).build()</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[ Java 와 Kotlin  그거 뭐가 좋아?]]></title>
            <link>https://velog.io/@blue-sky/Java-vs</link>
            <guid>https://velog.io/@blue-sky/Java-vs</guid>
            <pubDate>Thu, 08 Sep 2022 05:13:13 GMT</pubDate>
            <description><![CDATA[<h2 id="요즘-대세는-kotlin">요즘 대세는 Kotlin</h2>
<p>개발을 하는데 있어서 언어는 언제나 중요한 주제가 된다.
프로그래밍을 해본 사람이라면  누구나 한 번쯤은 언어 선택에 있어서 고민을 한다.</p>
<p>하지만 Kotlin에 대해서 진지하게 왜 사용하는지에 대해 물어보면 </p>
<ul>
<li>가독성이 좋다 </li>
<li>null safe </li>
<li>Java와 호환이 100 % 가능하다 </li>
</ul>
<p>이정도에 그쳤다. 딱 그정도였다. &quot;남들이 쓰니까&quot; 이런 식으로 진행하게 되면 시야가 좁아지고 자신만의 개발 정체성이 사라진다.</p>
<p>이 시간을 통해 JAVA 에 대한 이해와 Kotlin으로 사람들이 사용할려는 이유에 대해 알아보자.</p>
<h2 id="java를-왜-사용을-많이-할까">JAVA를 왜 사용을 많이 할까?</h2>
<p>다양한 분야에서 활발히 사용되고 있다. 
Spring Boot, Android , Hadoop , 게임 , 소형기기 등 </p>
<p>특히 , 현재 한국은 JAVA공화국이라고 부를만큼 많은 기업에서 JAVA를 사용중이다.</p>
<h4 id="왜-많이-사용할까">왜 많이 사용할까?</h4>
<p>유지보수 때문이다. 정부 기관에서<a href="https://velog.io/@jojo_devstory/Spring-%EC%A0%84%EC%9E%90%EC%A0%95%EB%B6%80%ED%94%84%EB%A0%88%EC%9E%84%EC%9B%8C%ED%81%AC%EB%9E%80"> 전자정부프레임워크</a>를 사용하여 획일화된 언어를 추구하여 예산 절감 및 유지보수 때문에 정부에서 요구 사항위주로 만들어야 하기 때문이다.</p>
<h2 id="java-의-탄생">Java 의 탄생</h2>
<p><strong>[Jdk 1.0]</strong>
Java는 1996년 Sun MicroSystems 라는 회사에서 객체지향 프로그래밍으로 만들어 졌는데 원래는 소형기기에 만 사용될 목적으로 개발 되었다.</p>
<p>그리고 원래 JAVA 이름 짓기 전에 초기 이름이 **&quot;Oak&quot; 이다 **</p>
<h3 id="왜-java-원래-이름은-oak-로-지었을까-">*<em>왜? Java 원래 이름은 Oak 로 지었을까? *</em></h3>
<p>그 당시에 Oak는 주로 미국 , 프랑스 ,독일 ,루마미나 등에서 힘의 상징으로 많이 사용되었기 때문이다.</p>
<p>그당시에 팀원들은 새로운 이름을 짓기위에 자리를 모였는데 그 당시에 최초의 커피 가 &quot;JAVA&quot;라는 인도네시아의섬에서 시작 되었다.</p>
<p>때문에 <strong>마켓팅용으로 적합하여 채택했다는 말이 많았다</strong>. 
즉 , 걸그룹 f(x) 처럼 사람들이 평소에 사용하는 단어로 마켓팅을 위한 일종의 전략 같은거였다.
<img src="https://velog.velcdn.com/images/blue-sky/post/4f3942ed-876e-446d-9a13-d5ba39e7d1c2/image.png" alt=""></p>
<h2 id="java-의-특징">Java 의 특징</h2>
<h3 id="배우기-쉬운-객체지향-언어">배우기 쉬운 객체지향 언어</h3>
<p>Java는 사용하기 쉽도록 설계했고 다른 프로그래밍 언어보다 작성, 컴파일, 디버그 및 학습이 쉽습니다. 그리고 모듈식 프로그램과 재사용 가능한 코드를 만들 수 있다.</p>
<h3 id="자동-메모리-관리">자동 메모리 관리</h3>
<p>예전에는 프로그래머가 직접 관리해주는 작업이 필요했기에 메모리가 부족해서 자주 죽는일이  있었다. 이때 Java 는 가비지  컬렉터(GC) 가 직접 메모리를 와서 정리해준다. </p>
<h3 id="독립적이다">독립적이다</h3>
<p>모든 운영체제에서 사용이 가능합니다. Java는 JVM에 위에서 작동하기에 한 번 작성하면 어디서든 실행 및 수정이 가능합니다. </p>
<h2 id="kotlin의-탄생">Kotlin의 탄생</h2>
<p><strong>JetBrains 회사</strong>에서  JVM, Android, JavaScript 및 Native를 대상으로 하는 오픈 소스 정적 유형 프로그래밍 언어 기준으로 탄생했다.</p>
<p>kotlin에는 모든 객체지향구조와 모두 있습니다.  함수형 프로그래밍 방식으로  고차함수 및 함수 유형 람다와 같은 기능에 대한 최고 수준을 지원합니다</p>
<p><a href="https://kotlinlang.org/docs/multiplatform.html">코틀린은 멀티 플랫폼</a>을 지향합니다. 
밑에 보이는 그림은 AOS , IOS , Desktop, web 등 다양하게 활용할 수 있는 사진이다. 
<img src="https://velog.velcdn.com/images/blue-sky/post/961f0012-0048-430b-b231-e91940cd0a94/image.png" alt=""></p>
<p> 현재도 개발 중이며 팀 100명 이상 및 외부 기여자 250명이 함께 진행중이다.
[ Roman Elizarov Jetbrains 수석 언어 디자이너  ]
<img src="https://velog.velcdn.com/images/blue-sky/post/a082bb24-ac56-4e73-ae57-1aee7815b99f/image.png" alt=""></p>
<h2 id="kotlin의-특징">Kotlin의 특징</h2>
<h3 id="null-safe">Null Safe</h3>
<p>기존 Java는 null 참조의 멤버에 접근하면 Null Exception이 발생하여 앱이 죽는 경우가 많습니다. </p>
<p>코틀린의 타입(type) 시스템은 코드에서 NullPointerExeption을 제거하기 위해 Null값이 참조가 안됩니다.</p>
<h3 id="coroutine"><a href="https://velog.io/@blue-sky/%EC%BD%94%EB%A3%A8%ED%8B%B4-1">Coroutine</a></h3>
<p>기존 Thread 에서 사용하는 Callback 방식을 CPS 동작을 활용하여 순차적으로 비동기 처리가 가능합니다. 이에 따라 생기는 직관성과 BoilerBplate의 코드의 양산을 줄일 수 있습니다. </p>
<h3 id="java와의-100--호환성-및-유틸성-메소드-지원">Java와의 100 % 호환성 및 유틸성 메소드 지원</h3>
<p>호환성이 100% 로 된다는 이야기는** 기존에 쓰고 있던 코드를 재활용<strong>이 가능한다는 이야기이다. 동시에 재활용을 통해 코틀린으로 마이그레이션이 가능하다는 이야기이며 이러한 kotlin 언어는 **안정성</strong>이 높아진다는 이야기이다.</p>
<p>유틸성 메소드를 지원한다. 이러한것을 지원하게 되면 코드가 어떠한 구동을 하며 행동을 하는지 본인코드 및 <strong>다른 사람이 코드를 볼때 쉽게 읽히게 됩니다.</strong> </p>
<h3 id="java-와-kotlin이-어떻게-100-호환되는지-그림">[Java 와 Kotlin이 어떻게 100% 호환되는지 그림]</h3>
<p>각각의 Source Code 와Compiler가  ByteCode를 통해 만나고 이를 JVM 를통해 각 운영체제에 맞게 운영된다.</p>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/2887eae5-1bed-4193-926e-2c3e1964cd45/image.png" alt=""></p>
<h2 id="라인-개발자가-말하는-java-보다-kotlin">라인 개발자가 말하는 JAVA 보다 Kotlin</h2>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/2c4e0edb-9841-468d-903f-696f9782d6af/image.png" alt=""></p>
<h3 id="why-use-kotlin">Why use Kotlin?</h3>
<p>&quot;기존에 Java로 짜면 한 열 줄 정도 나오는 코드들이 Kotlin으로 바꾸면 두세 줄로 압축되는 요소들이 많았다&quot; </p>
<p>&quot;Google 에서 메인 개발 언어를 Kotlin으로 정하고 그쪽으로 전폭적으로 밀려는 상황이 나오니 앞으로 당연히 계속 이 언어를 사용해야겠다&quot; </p>
<p><strong>안드로이드는 최신 자바언어를 사용 못한다.</strong> 안드로이드에 JAVA를 만들 때 실제 JAVA가 아니라 Dalvik (JAVA 비슷한) 가 안드로이드에 있고 JAVA API를 그대로 복제한 안드로이드 플랫폼 API 가 있습니다. 근데.. 아주 옛날 JAVA API 만 사용하기 있기 때문에 <strong>JAVA의 일부분만 사용</strong>이 가능하기 때문에** Syntax Sugar<strong>를 사용하지 못한다. 그러므로 생기는 **Boilerplate 코드</strong>가 많이 생긴다.  </p>
<h3 id="kotlin-단점">Kotlin 단점</h3>
<p><strong>대용량 코드를 처리 할 경우 컴파일 속도가 느리다</strong>. 컴파일러 부분에 있는<br> Anotation Processor(전처리기) 부분이 20%가량 느리게 된다.</p>
<p>*<em>Unit Text 가 애매하다 . *</em> Kotlin을 가지고 작업하면 Java 바이트 코트(Class) 나오는데 수정 못하는 final 형식으로 나오게 된다. Unit Text에서 Mocking 기법을 활용하여 변조해서 사용하합니다 </p>
<p>Java 바이트 코드를 변경할 때  final modiifeir가 들어있으면 (변조 불가능) 인데  ByteBuddy(흑마법)라하는 런타임에서 Java 바이트코르를 임의로 변조할 수 있는 기술  못 하는걸 할려할 때  시간이 더들어간다.</p>
<h4 id="mocking-기법">Mocking 기법</h4>
<blockquote>
<p>실제 돌아가는 코드 대신 임의결과물을 반환</p>
</blockquote>
<p>&lt;참고자료&gt;</p>
<ul>
<li><a href="https://youtu.be/qFitd3Ukgcc">라인 개발자 영상 </a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Compose  Canvas  ]]></title>
            <link>https://velog.io/@blue-sky/Android-Canvas</link>
            <guid>https://velog.io/@blue-sky/Android-Canvas</guid>
            <pubDate>Sun, 28 Aug 2022 05:17:52 GMT</pubDate>
            <description><![CDATA[<h1 id="canvas-왜-사용할까">Canvas 왜 사용할까?</h1>
<blockquote>
<p>화면에 표시되는 내용을 정확하게 제어하며 정교한 작업이 필요로 할때 사용</p>
</blockquote>
<h3 id="jetpaco-compsoe-canvas">Jetpaco Compsoe Canvas</h3>
<ul>
<li>Canvas를 더욱 쉽게 사용할 수 있게 되었습니다.</li>
<li>View 를 상속받을 필요 없이 굉장히 쉬운 방법으로 UI 를 그릴 수 있습니다</li>
<li>그래픽 요소의 상태를 최소화하므로 상태의 프로그래밍 실수를 피할 수 있습니다.</li>
<li>항목을 그릴 때 모든 옵션이 구성 가능한 함수의 예상되는 위치에 있습니다.</li>
</ul>
<h2 id="📌canvas-이해가기">📌CanVas 이해가기</h2>
<blockquote>
<p>View는 수백만개 의 픽셀이 하나로 모여 화면을 생성하게됩니다.</p>
</blockquote>
<ul>
<li>그림 (0,0) ~(242,242)으로 시작해서 어떻게 픽셀이 배열되는지 볼 수 있습니다</li>
<li>왼쪽에서 오른족 방향은** x 축을 형성<strong>하고 **위에서 아래 Y축</strong>을 형성합니다.</li>
<li>이런 요소를 사용하여 UI 배치하기 위한 기반을 형성 합니다.
<img src="https://velog.velcdn.com/images/blue-sky/post/1bf67fb5-e28d-465e-b848-362d1ed85393/image.png" alt=""></li>
</ul>
<h2 id="drawline">drawLine</h2>
<h4 id="말-그대로-선을-그려-주는-함수이다">말 그대로 선을 그려 주는 함수이다</h4>
<pre><code class="language-kotlin">Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasWidth = size.width
    val canvasHeight = size.height

    drawLine(
        start = Offset(x = canvasWidth, y = 0f),
        end = Offset(x = 0f, y = canvasHeight),
        color = Color.Blue
    )
}</code></pre>
<p align = "center">
<img src="https://velog.velcdn.com/images/blue-sky/post/42c27b77-5815-4780-ac2c-8a52079569d6/image.png" width = 200 hegiht = 300/></p>

<h2 id="drawcircle">drawCircle</h2>
<h4 id="원을-그려주는-함수이다">원을 그려주는 함수이다.</h4>
<pre><code class="language-kotlin">Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasWidth = size.width
    val canvasHeight = size.height
    drawCircle(
        color = Color.Blue,
        center = Offset(x = canvasWidth / 2, y = canvasHeight / 2),
        radius = size.minDimension / 4
    )
}</code></pre>
<p align = "center">
<img src="https://velog.velcdn.com/images/blue-sky/post/70ebe102-707f-4dad-be53-bf271edb8115/image.png" width = 200 hegiht = 300/></p>

<h2 id="drawrect">drawRect</h2>
<h4 id="직사각형-혹은-정사각형을-그려주는-함수이다">직사각형 혹은 정사각형을 그려주는 함수이다</h4>
<pre><code class="language-kotlin">Canvas(modifier = Modifier.fillMaxSize()) {
        val canvasSize = size
        val canvasWidth = size.width
        val canvasHeight = size.height
        drawRect(
            color = Color.Gray,
            topLeft = Offset(x = canvasWidth / 3F, y = canvasHeight / 3F),
            size = canvasSize / 3F
        )
    }</code></pre>
<p align = "center">
<img src="https://velog.velcdn.com/images/blue-sky/post/3f0437f6-95a6-4f2d-9a57-9bcb30ceb99c/image.png" width = 200 hegiht = 300/></p>

<h2 id="🌳적용하기">🌳적용하기</h2>
<h3 id="🍎-인스타그램-로고-만들어보기">🍎 인스타그램 로고 만들어보기</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/a3b58ca2-597d-46ea-bba0-2fe1a16faffc/image.png" alt=""></p>
<h4 id="인스타그램">인스타그램</h4>
<blockquote>
<p>둥근  직사각형 + 원 + 그라데이션 으로 이루어 져있다.</p>
</blockquote>
<ul>
<li>일정한 사이즈(정사각형)을 유지하기 위해서 size(100.dp)를 사용하였습니다.</li>
<li>위에 그림처럼 (0,0) 부터 좌표가 시작되는 둥근 사각형입니다</li>
<li>가운데 있는 도넛원은 (50,50) Defalut값으로 OffSet(위치) 됩니다.</li>
<li>오른쪽 위에 있는 색칠된 원은 (80,20)에 Offset(위치) 됩니다</li>
</ul>
<p>그리고** 그레디언트<strong>가 필요하며 **둥근 사각형안에 둥근 도넛원을 획 채우기</strong>로 만들어야 합니다. 코드로 한 번 보겠습니다.</p>
<h4 id="drawroundrect">drawRoundRect</h4>
<ul>
<li>둥근 사각형을 그리는 경우 사용됩니다</li>
<li>Brush를 통해   그라디언트 효과를 적용 했습니다.</li>
<li>Stroke 를 사용하여 스타일을 채웠습니다</li>
</ul>
<h4 id="drawcirlce">drawCirlce</h4>
<ul>
<li>빈 원을 만들거나 채워진 원을 만들 수 있습니다.</li>
<li>radius를 통해 원의 크기를 설정합니다.</li>
<li>Default가 (50,50) 이기 때문에 조정할 필요한 경우만 Offset을 설정하여 위치를 옮겨 줍니다.</li>
</ul>
<pre><code class="language-kotlin"> val instaColors = listOf(Color.Yellow, Color.Red, Color.Magenta)
    Canvas(
        modifier = Modifier
            .size(100.dp)
            .padding(16.dp)
    ) {
        drawRoundRect(
            brush = Brush.linearGradient(colors = instaColors),
            cornerRadius = CornerRadius(60f, 60f),
            style = Stroke(width = 15f, cap = StrokeCap.Round)
        )
        drawCircle(
            brush = Brush.linearGradient(colors = instaColors),
            radius = 45f,
            style = Stroke(width = 15f, cap = StrokeCap.Round)
        )
        drawCircle(
            brush = Brush.linearGradient(colors = instaColors),
            radius = 13f,
            center = Offset(this.size.width * .80f, this.size.height * 0.20f),
        )
    }</code></pre>
<h3 id="🍎-페이스북-로고-만들어보기">🍎 페이스북 로고 만들어보기</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/e12ff03c-02c2-418c-9ad2-6f93ee295fce/image.png" alt=""></p>
<h4 id="페이스북">페이스북</h4>
<blockquote>
<p>둥근 사각형 + 텍스트 사용자 글꼴 + 색상</p>
</blockquote>
<ul>
<li><a href="https://www.fontmirror.com/facebook-font">Facebook Font</a> 싸이트에서 OTF 파일을 가져와서 <a href="https://jamssoft.tistory.com/148">asset</a> 패키지를 만들어 넣어준다.</li>
<li>Canvas에 Text를 그릴 수 있는 API가 없기 때문에 LocalText에서 가져와서 그려야 합니다.</li>
<li>paint 변수로 Size와 Color 와 typeface를 가져와서 Canvas안에 넘겨줍니다.<pre><code class="language-kotlin">val assetManager = LocalContext.current.assets
  val paint = Paint().apply {
      textAlign = Paint.Align.CENTER
      textSize = 200f
      color = Color.White.toArgb()
      typeface = Typeface.createFromAsset(assetManager, &quot;FACEBOLF.OTF&quot;)
  }
  Canvas(
      modifier = Modifier
          .size(100.dp)
          .padding(16.dp)
  ) {
      drawRoundRect(
          color = Color(0xFF1776d1),
          cornerRadius = CornerRadius(20f, 20f)
      )
      drawContext.canvas.nativeCanvas.drawText(&quot;f&quot;, center.x + 25, center.y + 90, paint)
  }</code></pre>
</li>
</ul>
<h3 id="🍎-페이스북-메신져">🍎 페이스북 메신져</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/4d4d64d9-a939-4185-bd7b-ae1c008c2c38/image.png" alt=""></p>
<h4 id="메신져">메신져</h4>
<blockquote>
<p>타원형 + 그리디언트 + Path</p>
</blockquote>
<ul>
<li>이 메신져 모양은 말풍성 모양의 타원형이 필요합니다</li>
<li>Path를 사용하여 경로를 시작하는 위치를 설정해야 합니다</li>
<li>그다음 주어진 좌표를 활용하여 말풍선 가장자리를 형성해야 합니다.</li>
<li>밑부분은 음영을 주여 브러시처리를 해야줘야합니다.</li>
</ul>
<pre><code class="language-kotlin">val colors = listOf(Color(0xFF02b8f9), Color(0xFF0277fe))
    Canvas(
        modifier = Modifier
            .size(100.dp)
            .padding(16.dp)
    ) {

        val trianglePath = Path().let {
            it.moveTo(this.size.width * .20f, this.size.height * .77f)
            it.lineTo(this.size.width * .20f, this.size.height * 0.95f)
            it.lineTo(this.size.width * .37f, this.size.height * 0.86f)
            it.close()
            it
        }

        val electricPath = Path().let {
            it.moveTo(this.size.width * .20f, this.size.height * 0.60f)
            it.lineTo(this.size.width * .45f, this.size.height * 0.35f)
            it.lineTo(this.size.width * 0.56f, this.size.height * 0.46f)
            it.lineTo(this.size.width * 0.78f, this.size.height * 0.35f)
            it.lineTo(this.size.width * 0.54f, this.size.height * 0.60f)
            it.lineTo(this.size.width * 0.43f, this.size.height * 0.45f)
            it.close()
            it
        }

        drawOval(
            Brush.verticalGradient(colors = colors),
            size = Size(this.size.width, this.size.height * 0.95f)
        )

        drawPath(
            path = trianglePath,
            Brush.verticalGradient(colors = colors),
            style = Stroke(width = 15f, cap = StrokeCap.Round)
        )

        drawPath(path = electricPath, color = Color.White)

    }</code></pre>
<h2 id="🍎-토스-만들어보기">🍎 토스 만들어보기</h2>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/4af4e24a-7fb4-4fc7-a24a-8f6199d5d229/image.png" alt=""></p>
<h4 id="토스">토스</h4>
<blockquote>
<p>타원형 + 그리디언트 + Path 위에 메신저랑 형태가 흡사하다</p>
</blockquote>
<p>(추가 작업중)</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Coroutine Flow[2]🤔]]></title>
            <link>https://velog.io/@blue-sky/Android-Coroutine-Flow2</link>
            <guid>https://velog.io/@blue-sky/Android-Coroutine-Flow2</guid>
            <pubDate>Thu, 18 Aug 2022 11:50:33 GMT</pubDate>
            <description><![CDATA[<h1 id="✅-flow-vs-stateflow">✅ Flow vs StateFlow</h1>
<h2 id="🍎-기존-flow-사용">🍎 기존 Flow 사용</h2>
<blockquote>
<p>Flow는 데이터의 흐름만 발생하며 데이터가 따로 저장되지 않는다</p>
</blockquote>
<h3 id="이럴-경우">이럴 경우...</h3>
<p>만약 사용자가 홈 화면에 갔다가 <strong>다시 앱을 들어온다면 데이터는 초기화</strong>된다
이렇게 되면 사용자는 봤던 <strong>섹션 인덱스까지 다시 찾아가야 한다는 번거로움</strong>이 생긴다</p>
<h3 id="그래서">그래서..</h3>
<blockquote>
<p>flow의 collect한 데이터를 viewModel에 저장한다.</p>
</blockquote>
<h3 id="하지만">하지만...</h3>
<p>데이터를 저장하고 있으려면 별도의 데이터 홀더 변수를 만들어야하며, 이러한 변수는 <strong>Reactive 하지 않기 때문에 UI에서 따로 Fetching 로직</strong>을 만들어야한다.</p>
<ul>
<li>보일러 플레이트 코드 생성</li>
<li>가독성을 떨어트린다</li>
<li>*<em>Cold Flow(Stream) *</em></li>
</ul>
<p>❄️ <strong>Cold Flow</strong>❗️ ❄️</p>
<ul>
<li><strong>필요에 따라 생성되고 관찰되는 중에만 데이터를 전송</strong>하는 것 </li>
<li>주로  <strong>상태가 변하지 않는 값</strong>을 읽을 때 사용됩니다</li>
<li>주로 <strong>하나의 소비자(Consumer)에게 값을</strong> 보냅니다.</li>
<li>생성된 이후에 <strong>누군가 소비하기 시작하면 데이터를 발행</strong>합니다.</li>
</ul>
<h2 id="🍎-stateflow-사용">🍎 StateFlow 사용</h2>
<blockquote>
<p>데이터 홀더(저장소) 역할을 하면서 Flow의 데이터 스트림 역할을 한다</p>
</blockquote>
<p>즉, 여러개의 flow의 <strong>데이터 홀더(저장소)</strong> 역할을 하며  데<strong>이터 스트림역할</strong>까지 합니다 </p>
<p>밑에 그림을 보면 </p>
<ul>
<li>기존 Flow는 Observer 형식으로 데이터를 구독(emit)해서 collect하고 있습니다.</li>
<li>하지만 StateFlow는 여러개의 Flow가 하나의 StateFlow으로 모여저서 하나의 객체로 만들어집니다.
<img src="https://velog.velcdn.com/images/blue-sky/post/a2b475d8-8175-416d-967d-125c2f30b4a7/image.png" alt=""></li>
</ul>
<h3 id="🍏변환-방법">🍏변환 방법</h3>
<h4 id="📌statein을-사용하여-flow---stateflow--변환하기">📌StateIn을 사용하여 Flow -&gt; StateFlow  변환하기</h4>
<p><strong>stateIn</strong>을 사용해서 변환할 수 있다.</p>
<ul>
<li>scope : StateFlow가 Flow로부터 데이터를 구독받을 CoroutineScope를 명시한다</li>
<li>started: Flow로부터 언제부터 구독을 할지 명시할 수 있다</li>
<li>inintalValue: StateFlow의 초기값을 설정한다.</li>
</ul>
<pre><code class="language-kotlin">class MyViewModel(...) : ViewModel() {
    val result: StateFlow&lt;Result&lt;UiState&gt;&gt; = flow {
        emit(repository.fetchItem())
    }.stateIn(
        scope = viewModelScope, 
        started = WhileSubscribed(5000), 
        initialValue = Result.Loading
    )
}</code></pre>
<h4 id="위에-코드중--whilesubscribedtime는뭘까">위에 코드중  <strong>WhileSubscribed(Time)</strong>는뭘까?</h4>
<p>밑에 그림을 보면 두가지가 나눠져 있다</p>
<ul>
<li>No upstreamFlows cancelled(<strong>가로 회전</strong>) </li>
<li>All  upStreamFlows cancelled After timeout(<strong>홈 버튼</strong>) </li>
</ul>
<p>사용자가 다시** 앱을 켰을때** 빠르게 데이터를 받을려면 다시** Flow를 재시작해서는 안된다. **</p>
<ul>
<li><strong>홈</strong>으로 갔을때는** 베터리 및 다른 자원<strong>를 아끼기 위해 **Flow를 중단</strong>해야하며 </li>
<li><strong>가로 회전</strong>을 했을 경우에는 <strong>빠르게 데이터를 받기 위해 Flow를 중단하면 안된다.</strong></li>
</ul>
<p>이것을 알기 위해서 시간초과(WhileSubscribed)를 사용한다.
<img src="https://velog.velcdn.com/images/blue-sky/post/2560c1b5-36ab-4c40-9be5-3e90562546e7/image.png" alt=""></p>
<p>이렇게 시간에 따라 프로그램을 동작하는것을 알아보았다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Coroutine Flow[1]🤔]]></title>
            <link>https://velog.io/@blue-sky/Android-Coroutine-Flow1</link>
            <guid>https://velog.io/@blue-sky/Android-Coroutine-Flow1</guid>
            <pubDate>Thu, 18 Aug 2022 05:21:59 GMT</pubDate>
            <description><![CDATA[<h2 id="📌flow">📌Flow</h2>
<blockquote>
<p>흐르다 /  어떤 일이 진행이되다 / 분위기를 타다  의미를 가진다.</p>
</blockquote>
<p>우리는 그중에  &quot;데이터의 일이 진행&quot; 되는 과정인 Coroutine Flow를 알아보자</p>
<h1 id="✅-coroutine-flow">✅ Coroutine Flow</h1>
<h3 id="river-flow-in-you---이루마">river flow in you - 이루마</h3>
<p>&quot;Coroutine Flow도 마찬가지로 당신(User) 에게 <strong>데이터가 흐른다</strong>....&quot;</p>
<p>쉽게 말하면  <strong>Flow</strong>를 사용하여 데이터베이스에서** 실시간 업데이트를 수신**할 수 있습니다.</p>
<h2 id="⛽️-데이터베이스db">⛽️ 데이터베이스(DB)</h2>
<p align="center"><img src="https://velog.velcdn.com/images/blue-sky/post/42bbd167-8d72-4201-86f8-290c0fc065cf/image.png" width = 500 height=500/></p>

<p>클린 아키텍쳐로 앱을 만들시에 *<em>Data Layer부분에서 Repostiroy *</em>를 생성하여 *<em>데이터들을 가져오게된다 *</em>. 밑에 그림을 보자 </p>
<h3 id="물data이-필요할때마다-가져오는-방식">물(Data)이 필요할때마다 가져오는 방식</h3>
<ul>
<li>UI -&gt; ViewModel -&gt; Data Layer(Repository) -&gt; ViewModel -&gt; UI</li>
<li><strong>데이터가 필요할 때마다</strong> 일일이 <strong>요청</strong>하여 DB에서 <strong>데이터</strong>를 가져와야 한다.
(suspend fun 으로 사용하여 간편하게 사용할 수 있다)<p align="center"><img src="https://velog.velcdn.com/images/blue-sky/post/cf17ce29-fb53-4821-9d8c-f8f4cb138a7e/image.png" width = 500 height=500/></p>

</li>
</ul>
<blockquote>
<p>❗️ 하지만 이렇게 사용만한다면 최신 데이터를 실시간으로 받아올 수 없다.</p>
</blockquote>
<h3 id="물data이-알아서-관찰해서-가져오는-방식">물(Data)이 알아서 관찰해서 가져오는 방식</h3>
<ul>
<li>밑에 그림 처럼 사용된다면 <strong>데이터가 자동적으로 업데이트</strong>되서 <strong>Flow</strong>를 타고 내려오게 됩니다.</li>
<li>이러한 방식을 ❗️<strong>Reactive</strong>❗️ 라고 말합니다</li>
<li>왜냐하면 observer가 관찰 대상의 변화를 자동 대응<strong>(Reactive</strong>) 하기 때문입니다.</li>
<li>그리고 데이터를 한 방향으로 흐르게 하는것이 좋습니다. <strong>오류할 발생이 적고</strong> 
때문입니다.</li>
</ul>
<h4 id="reactive-programming">Reactive Programming</h4>
<blockquote>
<p>데이터가 변경 될 때 이벤트를 발생시켜 데이터를 계속해서 전달하는 방식</p>
</blockquote>
<p align="center"><img src="https://velog.velcdn.com/images/blue-sky/post/ce5fb813-14b1-4863-914c-efd47753325e/image.png" width = 500 height=500/></p>

<h3 id="데이터를-여러-방향-방식">데이터를 여러 방향 방식</h3>
<ul>
<li>밑에 그림을 보시면 view에서 Auth 정보 /User favaortie / items에 대한 정보가 있습니다.</li>
<li>뷰에서 여러가지 정보를 <strong>여러 방향으로 가져올 경우 버그</strong>가 생길 수도 있습니다<p align="center"><img src="https://velog.velcdn.com/images/blue-sky/post/0d40af31-f5cd-479a-8f09-eb59c9349ba9/image.png" width = 500 height=500/></p>


</li>
</ul>
<h3 id="데이터-단방향-방식">데이터 단방향 방식</h3>
<ul>
<li>밑에 그림처럼 한 Repository에서 여러 Data들을 연결하는 기능을 구현하여 <strong>안정적으로 데이터</strong>를 받을 수 있습니다</li>
<li>사용자가 로그아웃 및 로그인을 하면 그에 <strong>맞는 관(data)을 제거하여 유동적으로 Data를 처리</strong> 할 수 있습니다.
<img src="https://velog.velcdn.com/images/blue-sky/post/b23969c3-ed7e-4031-836d-83cdd184ae21/image.png" alt=""></li>
</ul>
<h2 id="🍎-flow-생성하기">🍎 Flow 생성하기</h2>
<h3 id="flow가-만들어지는-순서">[Flow가 만들어지는 순서]</h3>
<p><img src="https://developer.android.com/static/images/kotlin/flow/flow-entities.png?hl=ko" alt=""></p>
<h3 id="🍏producer생산자">🍏Producer(생산자)</h3>
<blockquote>
<p>Flow에서 <strong>flow{} *<em>블록 내부에서 *</em>emit() 통해 데이터를 생성</strong>합니다.</p>
</blockquote>
<h4 id="📍위치datareomtesource">📍위치(DataReomteSource)</h4>
<p>userMessageDataSource에서 <strong>수시로 앱에온 메세지를 확인</strong>한다면?!</p>
<ul>
<li>flow{} 블록을 선언한다</li>
<li>newsApi 이용하여 데이터를 서버로 부터 받아온다</li>
<li>emit(Producer) 가 데이터를 생성한다</li>
<li>5초(refreshIntervalMs) 마다 반복해서 가져온다<pre><code class="language-kotlin">class UserMessagesDataSource(
  private val newsApi: NewsApi,
  private val refreshIntervalMs: Long = 5000
) {
  val latestNews: Flow&lt;List&lt;ArticleHeadline&gt;&gt; = flow {
      while(true) {
          val latestNews = newsApi.fetchLatestNews()
          emit(latestNews) 
          delay(refreshIntervalMs)
      }
  }
}</code></pre>
</li>
</ul>
<h3 id="🍏intermediary중개자">🍏Intermediary(중개자)</h3>
<blockquote>
<p>생산자가 데이터를 생성하면 중간 연산자는 <strong>데이터를 수정/가공/예외</strong> 처리한다.</p>
</blockquote>
<h4 id="📍위치repository">📍위치(Repository)</h4>
<ul>
<li>map (데이터를 변형한다)</li>
<li>filter(데이터 필터링)</li>
<li>onEach(모든 데이터마다 연산을 각각수행)</li>
</ul>
<p>생산자(newsRemoteDataSource)에서 만든 (lateNews)데이터를 가져와서 
 favorite topics 필터해서 가져온다음 각각(onEach) 최신 뉴스</p>
<pre><code class="language-kotlin">class NewsRepository(
    private val newsRemoteDataSource: NewsRemoteDataSource,
    private val userData: UserData
) {
    val favoriteLatestNews: Flow&lt;List&lt;ArticleHeadline&gt;&gt; =
        newsRemoteDataSource.latestNews
            .map { it -&gt; it.filter { userData.isFavoriteTopic(it)}
            .catch{ e -&gt;
                log.d(&quot;Error Loading reserved event&quot;)
            }

}</code></pre>
<h3 id="🍏consumer소비자">🍏Consumer(소비자)</h3>
<blockquote>
<p>Collect를 이용해 전달된 데이터를 소비합니다. </p>
</blockquote>
<h4 id="📍위치viewmodel">📍위치(ViewModel)</h4>
<ul>
<li><p>뷰모델 Scope안에서 비동기 함수로 실행되어 새로운 데이터를 collect하여 가져옵니다 </p>
<pre><code class="language-kotlin">class LatestNewsViewModel(
  private val newsRepository: NewsRepository
) : ViewModel() {

  init {
      viewModelScope.launch {
          newsRepository.favoriteLatestNews.collect { favoriteNews -&gt;
          //
          }
      }
  }</code></pre>
</li>
</ul>
<p>여기까지는 기초적인  Flow에 대해서 살펴 보았고 다음편에는 Flow에 대한 다른 기능으로 살펴볼 것이다</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android]Component 4대]]></title>
            <link>https://velog.io/@blue-sky/AndroidComponent-4%EB%8C%80</link>
            <guid>https://velog.io/@blue-sky/AndroidComponent-4%EB%8C%80</guid>
            <pubDate>Fri, 12 Aug 2022 09:27:02 GMT</pubDate>
            <description><![CDATA[<h2 id="구성요소">구성요소</h2>
<blockquote>
<p>Activity, Service, BroadCast Receiver , Content Provider</p>
</blockquote>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/61e7d3fa-1f11-408e-8e13-9eaf163841cc/image.png" alt=""></p>
<p>각각 독립적인 형태로 존재하고 , 교유한 기능을 인텐트를 통해 상호작용 합니다</p>
<h3 id="🍎-activity">🍎 Activity</h3>
<p>사용자가 Application 과 상호작용하며 실제로 사용자에게 보이는 화면</p>
<ul>
<li>생명주기(Life Cycle) 관련 메서드들을 재정의하여 원하는 기능들을 구현할 수 있습니다.</li>
<li>하나 이상의 View 또는 ViewGroup을 가지고 있어야 합니다 </li>
</ul>
<h3 id="🍎-service">🍎 Service</h3>
<p>주로 백그라운드에서 앱을 계속 실행하기 위한 목적입니다 </p>
<ul>
<li>시작된 서비스는 작업이 완료될 때까지 해당 서비스를 계속 실행 합니다</li>
<li>인터페이스(UI, 화면)에 방해받지 않고 눈에 보이지 않는 곳에서 작업을 처리합니다</li>
</ul>
<h3 id="🍎-broadcast-receiver">🍎 BroadCast Receiver</h3>
<p>안드로이드 OS로부터 발생하는 각종 이벤트와 정보를 받아와 핸들링 하는 컴포넌트</p>
<ul>
<li>대부분 UI 를 가지고 있지 않으면서 , 디바이스 특수한 상황에 대처하기 위해 사용됩니다</li>
<li>전원 충전 , 비행기 모드 , 애플케이션 설치 등등 </li>
</ul>
<h3 id="🍎-content-provider">🍎 Content Provider</h3>
<p>데이터를 관리하고 다른 애플리케이션의 데이터를 제공하는 데 사용되는 컴포넌트입니다.</p>
<ul>
<li>SQLite DB / Web / 파일 입출력 등을 통해서 데이터를 관리합니다.</li>
<li>갤러리 앱 -&gt; 파일 가져오기 / 현재 위치 가져오기 </li>
<li>사용하기 위해서는 권한획득 해야한다 -&gt; 보안적인 이슈를 고려해야하기 때문</li>
</ul>
<h3 id="🍎-intent">🍎 Intent</h3>
<p>플리케이션 컴포넌트(구성요소) 간에 작업 수행을 위한 정보를 전달하는 역할을 하며 통신수단</p>
<ul>
<li>서로 독립적으로 동작하는 4가지 컴포넌트들 간의 상호 통신을 위한 장치</li>
<li>컴포넌트에 액션(Action), 데이터(Data) 등을 전달</li>
<li>인텐트를 통하여 다른 애플리케이션의 컴포넌트를 활성화</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[[Android] Timber ]]></title>
            <link>https://velog.io/@blue-sky/Android-Timber</link>
            <guid>https://velog.io/@blue-sky/Android-Timber</guid>
            <pubDate>Mon, 08 Aug 2022 02:26:38 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/blue-sky/post/140a6dd0-eb61-4279-9193-23a726b30b55/image.png" alt=""></p>
<blockquote>
<p>Timber는  &quot;목재&quot;라는 뜻이다!?  과연 그럴까? </p>
</blockquote>
<p>Timber라는 노래가 있을정도로 내포한 의미를 자세히 살펴보면
<strong>&quot;Timber&quot;</strong>는 나무가 쓰러질 때 조심하라는 _<strong>경고</strong>_의 뜻이 있다.</p>
<p>그렇듯 Timber -Pitbull 에서는 비틀거리거나 쓰러지는 뜻으로도 사용됩니다
즉, 어떠한 위험을 뜻한다.</p>
<h3 id="사용법">사용법</h3>
<pre><code class="language-kotlin"> // Timber
    implementation &#39;com.jakewharton.timber:timber:$&lt;version&gt;&#39;</code></pre>
<h3 id="초기화">초기화</h3>
<ul>
<li>앱이 시작되자마자 Timber를 초기화해야 합니다. </li>
<li>가장 먼저 시작하는 Acitivity에 아래 메소드를 추가해주세요. </li>
<li>해당 메소드는 물론 onCreate()에서 호출됩니다. </li>
</ul>
<h4 id="일반적으로-사용하는-예시">일반적으로 사용하는 예시</h4>
<pre><code class="language-kotlin">class PokeMonApplication : Application() {
    override fun onCreate() {
        super.onCreate()

        if (BuildConfig.DEBUG) {
            Timber.plant(TimberDebugTree())
        }
    }
}</code></pre>
<h4 id="힐트에-적용한-예시">힐트에 적용한 예시</h4>
<pre><code class="language-kotlin">@HiltAndroidApp
class PokeMonApplication :Application(){

    override fun onCreate() {
        super.onCreate()
        Timber.plant(Timber.DebugTree())
    }
}</code></pre>
<h3 id="mainfest-추가">mainfest 추가</h3>
<pre><code class="language-xml">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;
&lt;manifest xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    package=&quot;com.example.timberexample&quot;&gt;

    &lt;application
        android:allowBackup=&quot;true&quot;
        android:name=&quot;.PokeMonApplication&quot; &lt;!-- 여기만 바꾸면됩니다&gt;
        android:icon=&quot;@mipmap/ic_launcher&quot;
        android:label=&quot;@string/app_name&quot;
        android:roundIcon=&quot;@mipmap/ic_launcher_round&quot;
        android:supportsRtl=&quot;true&quot;
        android:theme=&quot;@style/Theme.TimberExample&quot;&gt;
        &lt;activity android:name=&quot;.MainActivity&quot;
            android:exported=&quot;true&quot;&gt;
            &lt;intent-filter&gt;
                &lt;action android:name=&quot;android.intent.action.MAIN&quot; /&gt;

                &lt;category android:name=&quot;android.intent.category.LAUNCHER&quot; /&gt;
            &lt;/intent-filter&gt;
        &lt;/activity&gt;
    &lt;/application&gt;

&lt;/manifest&gt;
</code></pre>
<h4 id="초기화후-사용법">초기화후 사용법</h4>
<pre><code class="language-kotlin">Timber.d(&quot;TestValue $data값&quot;)
Timber.d(&quot;data값&quot;)
</code></pre>
]]></description>
        </item>
        <item>
            <title><![CDATA[Kotlin 고차함수  (Unit)]]></title>
            <link>https://velog.io/@blue-sky/Kotlin-%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98-Unit</link>
            <guid>https://velog.io/@blue-sky/Kotlin-%EA%B3%A0%EC%B0%A8%ED%95%A8%EC%88%98-Unit</guid>
            <pubDate>Fri, 05 Aug 2022 06:04:33 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>고차 함수를 들어가기 앞서 ...
<strong>Unit의 개념</strong>과  <strong>어떤 방식</strong>으로 사용되는지 알아보자</p>
</blockquote>
<h2 id="java-의-void-와-void">JAVA 의 void 와 Void</h2>
<blockquote>
<p>void &amp;&amp; Void -&gt; 반환 타입이 없으므로 생략한다는 의미입니다 </p>
</blockquote>
<pre><code class="language-java">public static void main(String[] args){
}</code></pre>
<pre><code class="language-kotlin">fun returnTypeVoid(): Void? {
        println(&quot;Trying with Void Return type&quot;)
}</code></pre>
<h2 id="unit-값이-없는-형태">Unit (값이 없는 형태)</h2>
<blockquote>
<p>Unit도 마찬가지로 아무것도 반환하지 않는 변환 타입 입니다</p>
</blockquote>
<pre><code class="language-kotlin">fun printHello(name: String?): Unit{
    if (name != null) {
        println(&quot;hello $name&quot;)
    } else {
        println(&quot;Hi&quot;)
    }
}</code></pre>
<ul>
<li>코틀린은 Unit은  자바의 Void와 비슷하다고 합니다  <ul>
<li>-&gt; 하지만 Unit은 Unit 단 하나의 값만 갖습니다</li>
</ul>
</li>
<li>반환타입이 Unit일 경우네는, return Unit;. return; 모두 선택적으로 작성해도 된다.</li>
</ul>
<h2 id="high-order-function고차함수">High Order Function(고차함수)</h2>
<p>함수 형식의 어떻게 자료형으로 나타낼까요?
(자료형, 자료형..) 패러미터  -&gt; 자료형(반환값)
바로 코드로 봅시다</p>
<pre><code class="language-kotlin">fun main(){
    b(::a)  // 고차함수로 넘길시에 :: 넣어줘야함 
}

fun a (str: String){  //문자열은 받고 반환형이 없는 형태 
    println(&quot;$str 함수 a&quot;)
}
fun b (function : (String) -&gt; Unit){
    function(&quot;b가 호출한&quot;) // a 함수안에 주입될 파라매터 값 
}
// b가 호출한 함수 a 
// main -&gt; b() -&gt; a()</code></pre>
<pre><code class="language-kotlin">fun main(){    
// 람다함수는 그자체가 고차함수이다 별도의 연산자 없이 변수에 담을수 있음
    val c: (String) -&gt; Unit = { str -&gt; println(&quot;$str 람다함수)}
       b(c)
}

fun a (str: String){
    println(&quot;$str 함수 a&quot;)
}
fun b (function : (String) -&gt; Unit){
    function(&quot;b가 호출한&quot;)
}
// b가 호출한 함수 a 
// main -&gt; b() -&gt; a()</code></pre>
<h2 id="실제-사용되는-사례-compose-rally">실제 사용되는 사례 (Compose Rally)</h2>
<p align="center">
<img src="https://velog.velcdn.com/images/blue-sky/post/5addcab4-9fe3-4093-91ee-e46833d77c49/image.gif" width = "300" height= "300"/></p>

<p><a href="https://github.com/whathe-downtown/Compose-Rally">Github Rally Source</a></p>
<h4 id="onclickseeallcounts-을-했을때--일어나는-함수-">onClickSeeAllCounts 을 했을때 { 일어나는 함수() }</h4>
<ul>
<li>compoasble (이안의 값을 받았을때 ) { } 안에 함수 실행</li>
<li>OverViewBody() -&gt;  Compoaslbe Screen</li>
<li>onClickSeeAllCounts  -&gt; SeeAllCounts 버튼을 클릭했을때 일어남</li>
<li>navController.navigate() -&gt; 이동해라 intent랑 비슷함 </li>
</ul>
<pre><code class="language-kotlin"> composable(RallyScreen.Overivew.name){
     OverviewBody(onClickSeeAllCounts = {navController.navigate(RallyScreen.Accounts.name)}
 }</code></pre>
<h4 id="overviewbody-안에-고차함수-값">OverViewBody 안에 고차함수 값</h4>
<ul>
<li>AccountCard() 안에서도 람다 고차함수를 이용해 위로 신호를 올려보냄<pre><code class="language-kotlin">@Composable
fun OverviewBody(
  onClickSeeAllAccounts: () -&gt; Unit = {},
) {
  AccountsCard(onClickSeeAllAccounts, onAccountClick = onAccountClick)
}</code></pre>
</li>
</ul>
<pre><code class="language-kotlin">@Composable
private fun AccountsCard(onClickSeeAll: () -&gt; Unit){
    OverviewScreenCard(
        onClickSeeAll = onClickSeeAll
        )
}</code></pre>
<pre><code class="language-kotlin">@Composable
private fun &lt;T&gt; OverviewScreenCard(
    title: String,
    amount: Float,
    onClickSeeAll: () -&gt; Unit,
    )
    {
    SeeAllButton( ){
             onClick = onClickSeeAll)
             }
    }</code></pre>
<p>정리 하자면 android 고차함수는 여러가지 상황에서 많이 쓰인다 
compose 로 예로 들자면 주로 상태호이스팅 
즉, onClick라는 신호를 받을시에 위로 신호를 보내 함수로 전달해주는대 주로 사용이 된다</p>
<p>순서 
OverviewScreenCard() -&gt; AccountCard() -&gt; OverViewBody() -&gt;navigation compoasable()
<img src="https://velog.velcdn.com/images/blue-sky/post/33d972f4-2d7e-4558-8527-d521697da660/image.gif" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Compose Semantics  ]]></title>
            <link>https://velog.io/@blue-sky/Semantics</link>
            <guid>https://velog.io/@blue-sky/Semantics</guid>
            <pubDate>Wed, 20 Jul 2022 02:03:34 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p>시맨틱(Semantic)이란 코드 조각의 의미를 나타낸다.</p>
</blockquote>
<p>뭐야? 시멘트 바르는거 아니였어?
비슷하긴하지 ...</p>
<p>간단히 말하면, 일정의 틀, 묶음을 나타내서 같이 쓸 수 있게 하는거?!
<img src="https://developer.android.com/static/images/jetpack/compose/a11y-userinfo-name-selected.png?hl=ko" alt="">
<img src="https://developer.android.com/static/images/jetpack/compose/a11y-userinfo-all-selected.png?hl=ko" alt=""></p>
<h2 id="주로-사용">주로 사용</h2>
<blockquote>
<ul>
<li>Touch 영역 </li>
</ul>
</blockquote>
<ul>
<li>클릭 라벨 추가 </li>
<li>시각 장애인을 위한 아이콘에 대한 설명</li>
</ul>
<h2 id="compose-semantics">Compose Semantics</h2>
<ul>
<li>시맨틱 속성을 사용하여 접근성 서비스에 정보를 전달합니다 </li>
<li>사용자에게 표시되는 UI 요소에 관한 정보를 제공합니다</li>
</ul>
<h3 id="코드를-보자-">코드를 보자 ..!</h3>
<h4 id="터치-영역-최소-크기-고려">터치 영역 최소 크기 고려</h4>
<blockquote>
<p>onCheckedChange 매개변수가 null로 설정된 경우 구성요소와 직접 상호작용할 수 없으므로 패딩이 포함되지 않습니다.</p>
</blockquote>
<pre><code class="language-kotlin">@Composable
fun CheckableCheckbox() {
    Checkbox(checked = true, onCheckedChange = {})
}</code></pre>
<p><img src="https://developer.android.com/static/images/jetpack/compose/a11y-checkbox-padding.png?hl=ko" alt=""></p>
<pre><code class="language-kotlin">@Composable
fun NonClickableCheckbox() {
    Checkbox(checked = true, onCheckedChange = null)
}</code></pre>
<p><img src="https://developer.android.com/static/images/jetpack/compose/a11y-checkbox-no-padding.png?hl=ko" alt=""></p>
<h3 id="checkbox로-클릭-구현하기">CheckBox로 클릭 구현하기</h3>
<pre><code class="language-kotlin">@Composable
fun CheckableRow() {
   MaterialTheme {
       var checked by remember { mutableStateOf(false) }
       Row(
           Modifier
                .toggleable(
                    value = checked,
                    role = Role.Checkbox,
                    onValueChange = { checked = !checked }
                )
               .padding(16.dp)
               .fillMaxWidth()
       ) {
           Text(&quot;Option&quot;, Modifier.weight(1f))
           Checkbox(checked = checked, onCheckedChange = null)
       }
   }
}</code></pre>
<p><img src="https://developer.android.com/static/images/jetpack/compose/a11y-parent-clickable.gif?hl=ko" alt=""></p>
<h3 id="클릭-라벨-추가">클릭 라벨 추가</h3>
<h4 id="두-차이점을-비교해-보자">두 차이점을 비교해 보자</h4>
<p>1) Click 이벤트가 들어왔을때 값을 실행(전달)하는 메소드 </p>
<pre><code class="language-kotlin">@Composable
fun ArticleListItem(openArticle: () -&gt; Unit) {
   Row(
       Modifier.clickable(
           // R.string.action_read_article = &quot;read article&quot;
           onClickLabel = stringResource(R.string.action_read_article),
           onClick = openArticle
       )
   ) {
       // ..
   }
}</code></pre>
<p>2) 클릭했을때 Boolean 값을 바꿔  실행하는 메소드 </p>
<pre><code class="language-kotlin">@Composable
fun LowLevelClickLabel(openArticle: () -&gt; Boolean) {
   // R.string.action_read_article = &quot;read article&quot;
   val readArticleLabel = stringResource(R.string.action_read_article)
   Canvas(
       Modifier.semantics {
           onClick(label = readArticleLabel, action = openArticle)
       }
   ) {
       // ..
   }
}</code></pre>
<p>참고자료</p>
<ul>
<li>android <a href="https://developer.android.com/jetpack/compose/accessibility?hl=ko#describe-visual">here</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Handler ✇]]></title>
            <link>https://velog.io/@blue-sky/Handler</link>
            <guid>https://velog.io/@blue-sky/Handler</guid>
            <pubDate>Fri, 15 Jul 2022 12:03:04 GMT</pubDate>
            <description><![CDATA[<p>Android UI 작업은 무!조!권 <strong><em>Main Thread</em></strong> 에서 작업해야 한다.</p>
<p>왜 그럴까?</p>
<h4 id="🍎-main-thread-와--worker-thread가-동시에--textview에-접근할-때">🍎 Main Thread 와  Worker Thread가 동시에  TextView에 접근할 때</h4>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/f695b000-e666-4b73-bb0f-7613ea7d704b/image.png" alt=""></p>
<ul>
<li>동시에 textView 에 접근하게 된다면 교착상태가 발생할 수 있다</li>
<li>MainThread가 일정 시간 멈추면 ANR이 생겨서 앱이 강제종료가 될 수 있다.</li>
</ul>
<h3 id="🍎-왜-ui-는-싱글-쓰레드-모델로-동작할까">🍎 왜 UI 는 싱글 쓰레드 모델로 동작할까?</h3>
<ul>
<li>만약 여러 쓰레드에서 TextView의 텍스를 변경하는 상황이라면 어떤 결과가 나올지 미지수 이기 때문이다. </li>
<li>_** 동작의 무결성**_을 보장 하기 위해 오로지 Main Thread에서만 UI관련 동작 가능</li>
</ul>
<h3 id="🍎-이런-문제를-해결-할려면-handler-등장-">🍎 이런 문제를 해결 할려면? Handler 등장 !!</h3>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/b0c92602-2c7d-49df-aee2-a6c09e2dd06d/image.png" alt=""></p>
<p>Worker Thread에서 Handler를 사용하여 메세지를 전달한다. 전달된 메세지는 Main Thread를 통해  작업을 처리한다.</p>
<h3 id="🍎-main-thread-에서-무거운-작업을-하지마라">🍎 Main Thread 에서 무거운 작업을 하지마라</h3>
<ul>
<li>UI 작업을  Main Thread 함으로 무거운 작업을 할시에 UI 처리가 늦어져서 느려진다.</li>
</ul>
<h3 id="🍎-handler-message-queue-looper">🍎 Handler, Message Queue, Looper</h3>
<ul>
<li>Handler <ul>
<li>특정 메세지를 Looper 의 MessageQue에 넣는다</li>
<li>Looper가 MessageQueue 에서 특정 메세지를 꺼내어 전달하면 이를 처리하는 기능을 수행함</li>
</ul>
</li>
</ul>
<p>*<em>다른 스레드에게 메세지를 전달하려면 *</em></p>
<ul>
<li>수신 대상 스레드에서 생성한 핸들러의 <strong>post나 sendMessage</strong>등의 함수를 사용</li>
<li>수신 대상 스레드의 Message Queue에 message가 저장되기 때문에.</li>
</ul>
<p>결국 , <strong>Thread에서 만든 Handler를 순차적으로 넣어 놓은 것</strong>을 다시 빼서 <strong>실행 시키는 것</strong>이다.
<img src="https://velog.velcdn.com/images%2Fjaeyunn_15%2Fpost%2Fe7c8696f-9a5b-4e8c-9be7-45b9fbde9db5%2Fimage.png" alt=""></p>
<p>🍏 <em>*<em>그래서 *</em></em>
Handler1 가 Main Thread 라면  Handler2,Handler3은 다른 작업 쓰레드이다.
Hadndler 2 or 3 에서  UI 작업을 요청하면 Message Queue 에 쌓이고 
이를 Looper 가 실제 UI작업을 관리하는 handlerMessage를 통해 MainThread에서 순차적으로 실행 시킨다.
Handler의 생성자에 Looper가 전달되는데 이는 모든 Handler가 동일한 Looper를 이용하게 된다.</p>
<p>🍏 <em>*<em>그림 처리 순서 *</em></em>
(Handler1, Handler3, Handler2) -&gt; Message Queue -&gt; Looper(FIFO)처리 -&gt; handlerMessage</p>
<p>잠깐 코드 보자 </p>
<pre><code class="language-java">new Handler(Looper.getMainLooper()).postDelayed(new Runnable() {
    @Override
    public void run() {
        // something..
    }
}, 1000);</code></pre>
<p>위에서 말한대로 Handler 생성자에 Looper를 넣게 된다.
위의 예제는 Delay를 주는 코드이다.</p>
<h3 id="🍎-handler-주요-함수">🍎 Handler 주요 함수</h3>
<ul>
<li><p>Handler.sendMessage(Message msg)
: Message 객체를 message queue에 전달하는 역할</p>
</li>
<li><p>Handler.sendEmptyMessage(int wht)
: Message의 wht 필드를 전달하는 함수</p>
</li>
<li><p>post()
: post()는 Message 객체가 아닌 Runnable 객체를 Message queue에 전달한다.
ex) Handler.post(new Runnable()) // 위에서 본 코드.</p>
</li>
</ul>
<h3 id="🍎-work-thread-에서-post를-요청하면">🍎 Work Thread 에서 post()를 요청하면?</h3>
<pre><code class="language-java">new Thread(new Runnable(){
    @Override
    public void run() {
        WHandler whandler;
        whandler = new WHandler();
        whandler.post(new Runnable(){
            @Override
            public void run() {
                //여기서의 UI 작업은 안된다.
            }
        }
    }    
}</code></pre>
<p>당연히 안된다. UI작업은 메인스레드에서만 가능하기에.
하고싶다면 메인 스레드에서 해야 한다.</p>
<pre><code class="language-java">new Thread(new Runnable(){
    @Override
    public void run() {        
        //    여기서는 UI 작업 불가.
        mainHandler.post(new Runnable(){
            @Override
            public void run() {
                //여기서의 UI 작업은 가능.
            }
        }
    }    
}</code></pre>
<p>mainHandler로 UI작업을 진행한다
Work Thread내부에서 Main Thread의 Handler를 통해 Runnable 객체가 전달한다.
메인 스레드의 Looper가 Runnable 객체를 꺼내서 run()을 실행한다</p>
<p>MainThread
Handler mainHandler = new Handler()</p>
<p>Work Thread
mainHandler.post(new Runnable())</p>
<p><strong>Main Thread의 mainHandler를 통해 run()을 실행하는 격이다.</strong></p>
<h4 id="참고자료">참고자료</h4>
<ul>
<li><a href="https://tinyurl.com/2doegqp8">Handler</a></li>
<li><a href="https://velog.io/@jaeyunn_15/Android-Handler">Handler2</a></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[Compose Navigation🔥 (2)]]></title>
            <link>https://velog.io/@blue-sky/Compose-Navigation-2</link>
            <guid>https://velog.io/@blue-sky/Compose-Navigation-2</guid>
            <pubDate>Sun, 03 Jul 2022 15:51:20 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/blue-sky/post/f8636b9a-054f-4c0a-abad-b1d135b7c843/image.gif" alt=""></p>
<blockquote>
<p>Compose Navigation </p>
</blockquote>
<h2 id="🍎-작동원리">🍎 작동원리</h2>
<p>HomeScreen -&gt; Profile -&gt; Settings -&gt; 뒤로가기 -&gt; HomeScreen -&gt; 뒤로가기 -&gt;  앱종료</p>
<h2 id="🍎-프로젝트">🍎 프로젝트</h2>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/ee805997-db29-4ff0-891b-7b7439fb9ec7/image.png" alt=""></p>
<h3 id="실행">실행</h3>
<p>Build.Gradle 추가</p>
<pre><code class="language-kotlin">dependencies {
    def nav_version = &quot;2.4.2&quot;
    // Navigation
    implementation &quot;androidx.navigation:navigation-compose:$nav_version&quot;
}</code></pre>
<h2 id="🍎-bottombarscreen">🍎 BottomBarScreen</h2>
<ul>
<li>Bottom Navigation에 들어가는 요소를 넣는 클래스입니다 </li>
<li><a href="https://velog.io/@haero_kim/Kotlin-Sealed-Class-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0">sealed class</a>사용하여 상태값을 유동적으로 변경할 수 있습니다</li>
<li>상태값이 바뀌지 않는 서브 클래스 이기에 object 를 사용하였습니다<pre><code class="language-kotlin">sealed class BottomBarScreen(
  val route: String,
  val title: String,
  val icon: ImageVector
){
  object Home: BottomBarScreen(
      route = &quot;Home&quot;,
      title = &quot;Home&quot;,
      icon = Icons.Default.Home
  )
  object Profile: BottomBarScreen(
      route = &quot;Profile&quot;,
      title = &quot;Profile&quot;,
      icon = Icons.Default.Person
  )
  object Settings: BottomBarScreen(
      route = &quot;Settings&quot;,
      title = &quot;Settings&quot;,
      icon = Icons.Default.Settings
  )
}</code></pre>
<h2 id="🍎-bottomnavgraph">🍎 BottomNavGraph</h2>
</li>
<li>NavHostController 정해 위치의 (context)를 받습니다</li>
<li>NavHost <ul>
<li>Compose에서 탐색 그래프입니다 </li>
<li>구성 가능한 대상을 지정하는 탐색 그래프와 NavController를 연결합니다.</li>
</ul>
</li>
<li>startDestination 시작 지점을 정합니다</li>
<li>composable ( route = Case ) { 이케이스에 보여줘야하는 Screen()} 보여줍니다.<pre><code class="language-kotlin">@Composable
fun BottomNavGraph(navController: NavHostController) {
  NavHost(
      navController = navController,
      startDestination = BottomBarScreen.Home.route
  ) {
      composable(route = BottomBarScreen.Home.route){
          HomeScreen()
      }
      composable(route = BottomBarScreen.Profile.route){
          ProfileScreen()
      }
      composable(route = BottomBarScreen.Settings.route){
          SettingScreen()
      }
  }
}</code></pre>
</li>
</ul>
<h2 id="🍎-mainactivity">🍎 MainActivity</h2>
<ul>
<li>MainScreen 호출<pre><code class="language-kotlin">class MainActivity : ComponentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
      super.onCreate(savedInstanceState)
      setContent {
          Samplenavigation2Theme {
              // A surface container using the &#39;background&#39; color from the theme
                  MainScreen()
          }
      }
  }
}</code></pre>
</li>
</ul>
<h2 id="🍎-mainscreen">🍎 MainScreen</h2>
<h3 id="🍏-bottombar">🍏 BottomBar</h3>
<ul>
<li><p>screens 으로 스크린의 목록을 가져옵니다</p>
</li>
<li><p>navBackStackEnty</p>
<ul>
<li>currentBackStackEntryAsState() 함수를 사용하여 현재  collectAsState를 가져옵니다 </li>
</ul>
<p><img src="https://velog.velcdn.com/images/blue-sky/post/4a38d89f-38bc-41f8-b097-00834fdb8f63/image.png" alt=""></p>
</li>
<li><p>가져온 함수를 destination(종착지) 전달합니다 </p>
</li>
<li><p>BottomNavigation 안에 스크린을 각각 AddItem 합니다 </p>
<pre><code class="language-kotlin">@Composable
fun BottomBar(navController: NavHostController) {
  val screens = listOf(
      BottomBarScreen.Home,
      BottomBarScreen.Profile,
      BottomBarScreen.Settings
  )
  val navBackStackEntry by navController.currentBackStackEntryAsState()
  val currentDestination = navBackStackEntry?.destination

  BottomNavigation {
      screens.forEach { screens -&gt;
          AddItem(screen = screens, currentDestination = currentDestination, navController =navController )
      }
  }
}
</code></pre>
</li>
</ul>
<pre><code>### 🍏 AddItem
- RowScope를 사용하여 다양하게 인자를 받을 수 있다.
- screen / currenDestination / navController 각각 매개변수로 받습니다)
- BottomNavigationItem 에 BottomBarscreen 아이템을 넣을것이다 label / icon... 등등
- selected =&gt; currentDestination?.hierachy? 
  - 구조의 시퀀스를 제공합니다. 계층 구조는 이 대상 자체에서 시작 NavDestination.parent하여 루트 탐색 그래프에 도달할 때까지 이 대상의 , 해당 그래프의 부모, 계층 구조가 이어집니다.
- unselectedContentColor -&gt; 불투명도로  바꿉니다.
- onClick 했을때 BottomBarScreen.route에따라 이동합니다.
- &lt;a href=&quot;https://velog.io/@blue-sky/Compose-Navigation&quot;&gt;popUpto&lt;/a&gt;는 여기를 참고 
  - popUpTo 하여 뒤로가기 눌렀을때 launchSingTop 하여 초기 HomeScreen()으로 되돌아오게함
~~~kotlin
@Composable
fun RowScope.AddItem(
    screen: BottomBarScreen,
    currentDestination: NavDestination?,
    navController: NavHostController
) {
    BottomNavigationItem(
        label = {
            Text(text = screen.title)
        },
        icon = {
            Icon(imageVector = screen.icon, contentDescription = &quot;Navigation Icon&quot;)
        },
        selected = currentDestination?.hierarchy?.any {
            it.route == screen.route
        } == true,
        unselectedContentColor = LocalContentColor.current.copy(alpha = ContentAlpha.disabled),
        onClick = {
            navController.navigate(screen.route){
                popUpTo(navController.graph.findStartDestination().id)
                launchSingleTop =true
            }
        }
    )
}</code></pre><h3 id="🍏-mainscreen">🍏 MainScreen</h3>
<ul>
<li><p>rememberNavController()</p>
<ul>
<li>앱의 화면과 각 화면 상태를 구성하는 컴포저블의 백 스택을 추적합니다</li>
</ul>
</li>
<li><p>Scaffold </p>
<ul>
<li><p>Scaffold는 기본 material design ui를 구현할 수 있게 해주는 요소입니다.</p>
<pre><code class="language-kotlin">@Composable
fun MainScreen() {
val navController = rememberNavController()
Scaffold(
    bottomBar = { BottomBar(navController = navController)}
) {
    BottomNavGraph(navController = navController)

}
}</code></pre>
</li>
</ul>
</li>
</ul>
<p>GitHub : <a href="https://github.com/whathe-downtown/ComposeSample/tree/main/samplenavigation2">코드 자료</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DFS/BFS  알아보자 🤔]]></title>
            <link>https://velog.io/@blue-sky/DFSBFS-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90-1</link>
            <guid>https://velog.io/@blue-sky/DFSBFS-%EC%95%8C%EC%95%84%EB%B3%B4%EC%9E%90-1</guid>
            <pubDate>Sun, 03 Jul 2022 08:16:42 GMT</pubDate>
            <description><![CDATA[<p><img src="https://c.tenor.com/MzaHmbn3NZoAAAAC/%EB%B9%A1%EC%B9%A8-%EB%B6%84%EB%85%B8.gif" alt=""></p>
<blockquote>
<p>DFS/BFS 처음 배울 때 (소리 없는 아우성 )</p>
</blockquote>
<h2 id="🍎dfsdeep--first--search">🍎DFS(Deep -First -Search)</h2>
<p><img src="https://blog.kakaocdn.net/dn/xC9Vq/btqB8n5A25K/GyOf4iwqu8euOyhwtFuyj1/img.gif" alt=""></p>
<h4 id="dfs">DFS</h4>
<ul>
<li>깊이 우선 탐색 </li>
<li>미로 찾기  /모든 노드를 방분할 때 사용 </li>
</ul>
<h4 id="작동-원리">작동 원리</h4>
<ul>
<li><p>탐색 시작 _<strong>노드를 스택에 삽입하고 방문 처리</strong>_를 한다.</p>
</li>
<li><p>스택의 최상단 노드에 <em><strong>방문하지 않은 인접 노드</strong>_가 있으면, 그 인접 노드를 스</em><strong>택에 넣고 방문 처리</strong>_를 한다. 방문하지 않은 인접 노드가 없으면 스택에서 최상단 노드를 꺼낸다.</p>
</li>
<li><p>2번의 과정을 더 이상 수행할 수 없을 때까지 반복한다.</p>
<pre><code class="language-python">def dfs(graph, v, visited):
  visited[v] = True
  print(v, end=&#39; &#39;)

  for i in graph[v]:
      if not visited[i]:
          dfs(graph, i, visited)
graph = [
  [],
  [2, 3, 8],
  [1, 7],
  [1, 4, 5],
  [3, 5],
  [3, 4],
  [7],
  [2, 6, 8],
  [1, 7]
]
visited = [False] * 9
</code></pre>
</li>
</ul>
<p>dfs(graph, 1, visited) #  1 2 7 6 8 3 4 5 </p>
<pre><code>![](https://velog.velcdn.com/images/blue-sky/post/974fd9ab-6db4-420b-8c56-868dfd2743d5/image.png)

#### 코드설명
- graph 는 어떻게 이어져있는 나타내주는 리스트이다.
- v 는 인덱스 위치 / visited 를 통해 방문 처리 구분
- 일단 vistied [False,False,False,False,False,False,False,False,False]  넣는다 
- dfs(graph, 1, visited) 재귀함수를 돌면서 방문하지 않은 graph를 찾는다.



## 🍎BFS(Breadth-First-Search)
![](https://blog.kakaocdn.net/dn/c305k7/btqB5E2hI4r/ea7vFo08tkDYo4c8wkfVok/img.gif)
#### BFS
- 너비 우선 탐색
- 최단 경로 할 때 사용
#### 작동원리 
- 탐색 시작 노드를 큐에 삽입하고 방문 처리를 한다.
- 큐에서 노드를 꺼내 해당 노드의 인접 노드 중 방문하지 않은 노드를 모두 큐에 삽입하고 방문 처리를 한다.
- 2번 과정을 더 이상 수행할 수 없을 때까지 반복한다.

~~~python
def bfs(graph, start, visited):
    queue = deque([start])

    visited[start] = True

    while queue:
        v = queue.popleft()
        print(v, end=&#39; &#39;)

        for i in graph[v]:
            if not visited[i]:
                queue.append(i)
                visited[i] = True

graph = [
    [],
    [2, 3, 8],
    [1, 7],
    [1, 4, 5],
    [3, 5],
    [3, 4],
    [7],
    [2, 6, 8],
    [1, 7]
]
visited = [False] * 9

bfs(graph, 1, visited)  # 1 2 3 8 7 4 5 6 </code></pre><p><img src="https://velog.velcdn.com/images/blue-sky/post/838d721a-c531-48a6-80fc-e481d32e8969/image.png" alt=""></p>
<h3 id="코드-설명">코드 설명</h3>
<ul>
<li>방문한 시작 노드를 queue 담아논다 </li>
<li>vistied 배열 인덱스에 True로 바꿔놓는다.</li>
<li>queue 원소가 empty 할 때 까지 반복한다</li>
<li>queue 에서 popleft()하여 v 에 저장하고 </li>
<li>v를 print한다 # 1</li>
<li>해당 원소와 연결된, 아직 방문하지 않은 원소들을 큐에 삽입</li>
</ul>
]]></description>
        </item>
    </channel>
</rss>