<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>하루플스토리</title>
    <link>https://haruple.tistory.com/</link>
    <description>안드로이드 개발자 하루플 입니다
GitHub 놀러와주세요! </description>
    <language>ko</language>
    <pubDate>Tue, 26 May 2026 04:09:14 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>하루플스토리</managingEditor>
    <image>
      <title>하루플스토리</title>
      <url>https://tistory1.daumcdn.net/tistory/2269449/attach/4fff232b5cc34ae694671ba5a24c9136</url>
      <link>https://haruple.tistory.com</link>
    </image>
    <item>
      <title>Android 15 StatusBar, NavigationBar 확장으로 발생하는 문제 해결</title>
      <link>https://haruple.tistory.com/274</link>
      <description>&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;최근 회사 프로젝트를 진행하면서 Android 15 버전을 대응하게 되었는데 간단(?)할 줄 알았으나 생각보다 시간을 써서 문제 해결 과정을 적어봅니다.&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;Android15 부터 더 넓은 화면을 표시하도록 하는 edge to edge 함수가 모든 화면에 적용되고, 구글에서도 더 넓은 화면으로 개발하기를 권장하고 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;527&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2UsMy/btsOxBRxmQK/ItbQR4uuYAri8sgE1fkNX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2UsMy/btsOxBRxmQK/ItbQR4uuYAri8sgE1fkNX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2UsMy/btsOxBRxmQK/ItbQR4uuYAri8sgE1fkNX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2UsMy%2FbtsOxBRxmQK%2FItbQR4uuYAri8sgE1fkNX1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;527&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;527&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상단 StatusBar 영역과, 하단 Navigation Bar 이 투명하게 확장되었습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이로인해 기존 앱 UI에 문제가 생겼습니다.&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d7bPXl/btsOwIwP5zd/cXxMy9OJDLWW3wsdr3FKZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d7bPXl/btsOwIwP5zd/cXxMy9OJDLWW3wsdr3FKZk/img.png&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;2316&quot; data-is-animation=&quot;false&quot; width=&quot;358&quot; height=&quot;917&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d7bPXl/btsOwIwP5zd/cXxMy9OJDLWW3wsdr3FKZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd7bPXl%2FbtsOwIwP5zd%2FcXxMy9OJDLWW3wsdr3FKZk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;2316&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/d2jrNw/btsOwewesZW/0UHg4kLRdanEJMd8xgGRdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d2jrNw/btsOwewesZW/0UHg4kLRdanEJMd8xgGRdk/img.png&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;2316&quot; data-is-animation=&quot;false&quot; width=&quot;330&quot; height=&quot;845&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d2jrNw/btsOwewesZW/0UHg4kLRdanEJMd8xgGRdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd2jrNw%2FbtsOwewesZW%2F0UHg4kLRdanEJMd8xgGRdk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;904&quot; height=&quot;2316&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;Android 14 / Android 15&lt;/figcaption&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;Android 15에서는 StatusBar 부분이 투명해지면서 UI가 전체적으로 올라가게 되었고, 뒤로가기 버튼 등 여러 UI가 StatusBar, NavigationBar와 겹쳐지게 되었습니다.&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Inset 정보를 가져와서 margin이나 padding을 적용해서 해결하도록 권장&lt;/b&gt;&lt;/span&gt;하고 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749642026458&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets -&amp;gt;
    val statusBarHeight = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top
    val navBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
    insets
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저희 프로젝트는 대부분 Activity 하나에 여러개의 Fragment로 이루어져있고, 일부 Compose로 전환된 상태입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드를 Activity와 Fragment에서 사용했을 때 아래의 2가지 문제가 발생했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;1. Fragment 에서 setOnApplyWindowInsetsListener 의 Inset 값이 호출되지 않는 문제 발생.&lt;/span&gt;&lt;br /&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;2. 여러화면에서 동시에 setOnApplyWindowInsetsListener 호출시 가장 마지막에 호출된 리스너만 등록되는 문제 발생.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 더 쉬운 방법으로 statusBar 와 navigationBar height를 가져오는 방법을 알고 있었지만, 앞으로의 구글 업데이트에 요긴하게 대처하고 구글이 권장하는 방법을 따르기 위해 Inset 을 사용하는 방법으로 계속 개발을 진행했습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. StatusBar, NavBar Height 구하는 유틸리티 함수&lt;/h3&gt;
&lt;pre id=&quot;code_1749643600315&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/**
 * Android 15 statusBar, navBar Deprecated
 * 이를 대비하여 최상단, 최하단 뷰에 마진을 추가하기 휘해 높이를 구하는 함수 입니다.
 */
fun onSystemBarInsetsChanged(
    view: View,
    onChanged: (statusBarHeight: Int, navBarHeight: Int) -&amp;gt; Unit
) {
    if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        ViewCompat.setOnApplyWindowInsetsListener(view) { _, insets -&amp;gt;
            val statusBarHeight = insets.getInsets(WindowInsetsCompat.Type.statusBars()).top
            val navBarHeight = insets.getInsets(WindowInsetsCompat.Type.navigationBars()).bottom
            onChanged(statusBarHeight, navBarHeight)
            insets
        }
    } else {
        onChanged(0, 0)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유틸리티 클래스에 statusBar와 navBar Height를 구하는 함수를 먼저 만들었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리스너에서 Inset의 변화를 감지하면 람다함수로 전달하도록 했습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.&amp;nbsp; 뷰에 마진을 더하는 유틸리티 함수 개발&lt;/h3&gt;
&lt;pre id=&quot;code_1749643727217&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private val baseTopMargins = mutableMapOf&amp;lt;View, Int&amp;gt;() // 함수를 여러번 실행해도 높이가 중복으로 증가하지 않도록 첫 마진값 저장

fun applyStatusBarMargin(height:Int, views: List&amp;lt;View&amp;gt;) {
    if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        views.forEach { view -&amp;gt;
            val baseMargin = baseTopMargins.getOrPut(view) { view.marginTop }
            view.updateLayoutParams&amp;lt;ViewGroup.MarginLayoutParams&amp;gt; {
                topMargin = baseMargin + height
            }
        }
    }
}

private val baseBottomMargins = mutableMapOf&amp;lt;View, Int&amp;gt;() // 함수를 여러번 실행해도 높이가 중복으로 증가하지 않도록 첫 마진값 저장

fun applyNavigationBarMargin(height: Int, views: List&amp;lt;View&amp;gt;) {
    if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
        views.forEach { view -&amp;gt;
            val baseMargin = baseBottomMargins.getOrPut(view) { view.marginBottom }
            view.updateLayoutParams&amp;lt;ViewGroup.MarginLayoutParams&amp;gt; {
                bottomMargin = baseMargin + height
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수를 여러번 실행했을 때 View의 마진이 중복으로 늘어나지 않도록 baseMargins 라는 전역변수를 만들어두었습니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. viewModel 에 값 저장&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;viewModel 에 아래와 같이 height를 저장하는 변수를 선언합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749643842254&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val statusBarHeight = MutableLiveData&amp;lt;Int&amp;gt;().apply { value = 0 }
val navBarHeight = MutableLiveData&amp;lt;Int&amp;gt;().apply { value = 0 }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Activity 에 아래와 같이 height 정보를 ViewModel에 저장하도록 합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749643933929&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;onSystemBarInsetsChanged(binding.root) { statusBarHeight, navBarHeight -&amp;gt;
    addProfileVM.statusBarHeight.value = statusBarHeight
    addProfileVM.navBarHeight.value = navBarHeight
}&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. observe로 margin 업데이트&lt;/h3&gt;
&lt;pre id=&quot;code_1749644058561&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;addProfileVM.statusBarHeight.observe(viewLifecycleOwner) {
    applyStatusBarMargin(height = it, views = listOf(binding.ivBack))
}
addProfileVM.navBarHeight.observe(viewLifecycleOwner) {
    applyNavigationBarMargin(height = it, views = listOf(binding.btnNext))
}&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;586&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IpSOz/btsOxsAfJKV/CqDfaiAZcKAPekiGAjKbYk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IpSOz/btsOxsAfJKV/CqDfaiAZcKAPekiGAjKbYk/img.png&quot; data-alt=&quot;NavigationBar에 가려진 RecyclerView&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IpSOz/btsOxsAfJKV/CqDfaiAZcKAPekiGAjKbYk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIpSOz%2FbtsOxsAfJKV%2FCqDfaiAZcKAPekiGAjKbYk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;348&quot; height=&quot;226&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;586&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;NavigationBar에 가려진 RecyclerView&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;RecyclerView의 경우 항목의 최하단에 padding이 추가되어야 Navigation Bar에 가려지지 않으므로 아래 코드를 작성해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1749644128159&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;binding.recyclerView.setPadding(
    binding.recyclerView.paddingLeft,
    binding.recyclerView.paddingTop,
    binding.recyclerView.paddingRight,
    navBarHeight // 하단 padding 추가
)
binding.recyclerView.clipToPadding = false // padding 영역까지 스크롤되도록 설정&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Activity에서만 Inset을 얻어오고, 실제 뷰가 존재하는 Fragment에서 뷰를 업데이트 하는 간단하고 짧은 코드로 모든 화면을 Android 15에 대응하게 되었습니다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;2588&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvhVFk/btsOyaTuoGa/OsIo4NArpbHcGkFmz10dR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvhVFk/btsOyaTuoGa/OsIo4NArpbHcGkFmz10dR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvhVFk/btsOyaTuoGa/OsIo4NArpbHcGkFmz10dR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvhVFk%2FbtsOyaTuoGa%2FOsIo4NArpbHcGkFmz10dR0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;295&quot; height=&quot;845&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;2588&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;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/274</guid>
      <comments>https://haruple.tistory.com/274#entry274comment</comments>
      <pubDate>Wed, 11 Jun 2025 21:22:10 +0900</pubDate>
    </item>
    <item>
      <title>[Swift] 갑자기 iOS를 하게 되면서 Swift 언어 하루컷</title>
      <link>https://haruple.tistory.com/273</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;회사의 사정으로 인해 갑자기 iOS의 업무 일부를 맡게 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그나마 다행인건 Kotlin과 Swift가 유사한 언어라는 점에서 빠르게 학습할 수 있었고,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift를 공부할 때 어떤 부분이 Kotlin과 유사한 문법인지를 찾아보면서 이해를 더 쉽게 할 수 있었다.&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;이제 XCode IDE에 익숙해지고 RXSwift같이 회사 프로젝트에 적용되어 있는 기술들도 찾아볼 예정&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style5&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;var 변경 가능한 변수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;let 변경 불가능한 상수&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본 데이터 타입&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someInt: Int = -100 // 양, 음의 정수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someUInt: UInt = 100 // 양의 정수&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someFloat: Float = 3.14&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someDouble: Double = 3.14&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someCharacter: Character = &quot;a&quot; // 한 글자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someString: String = &quot;하하하&quot;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someAny: Any = 100 // 모든 타입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;var&lt;/b&gt; someAnyObject: AnyObject = SomeClass() // 모든 클래스 타입을 지칭하는 프로토콜&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nil // 데이터 없음&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;함수&lt;/h2&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;/ul&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;func sum(a: Int, b: Int) -&amp;gt; Int {
    return a + b
}

sum(a: 3, b: 5)
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func printMyName(name: String) -&amp;gt; Void {
    print(name)
}

printMyName(name: &quot;동환&quot;)

func printMyName(name: String = &quot;동환&quot;) { // 매개변수 기본값 설정
    print(name)
}
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre class=&quot;autoit&quot;&gt;&lt;code&gt;func maximumIntegerValue() -&amp;gt; Int {
    return Int.max
}
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre class=&quot;go&quot;&gt;&lt;code&gt;func printLog() {
    print(&quot;Test&quot;)
}
&lt;/code&gt;&lt;/pre&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;swift에는 함수의 파라미터로 함수 외부에서 입력하는 전달인자 라는 개념이 있다. 아래 예시로 함수를 사용할 때는 to, from을 사용하고, 함수 내부에서는 friend, me 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;less&quot;&gt;&lt;code&gt;func greeting(to friend: String, from me: String) {
    print(&quot;Hello \\(friend)! I'm\\(me)&quot;)
}

greeting(to: &quot;친구&quot;, from: &quot;동환&quot;)
&lt;/code&gt;&lt;/pre&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;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;func sayHelloToFriends(me: String, friends: String...) -&amp;gt; String {
    return &quot;Hello \\(friends)! I'm \\(me)&quot;
}

sayHelloToFriends(me: &quot;동환&quot;, friends: &quot;친구1&quot;, &quot;친구2&quot;, &quot;친구3&quot;)
&lt;/code&gt;&lt;/pre&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;/ul&gt;
&lt;pre class=&quot;lasso&quot;&gt;&lt;code&gt;func greeting(to friend: String, from me: String) {
    print(&quot;Hello \\(friend)! I'm\\(me)&quot;)
}

// String, String 타입의 greeting 함수를 리턴하는 someFunction 변수
var someFunction: (String, String) -&amp;gt; Void = greeting(to:from:)
someFunction(&quot;친구&quot;, &quot;동환&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;조건문&lt;/h2&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;if (someInteger &amp;lt; 100) {
    print(&quot;100 미만&quot;)
} else if someInteger &amp;gt; 100 { // if문 괄호 없어도 됨
    print(&quot;100 초과&quot;)
} else {
    print(&quot;100&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;zephir&quot;&gt;&lt;code&gt;let someInteger: Int = 100

switch someInteger {
case 0:
    print(&quot;0&quot;)
case 1..&amp;lt;100:
    print(&quot;1~99&quot;)
case 100:
    print(&quot;100&quot;)
case 101...Int.max:
    print(&quot;over 100&quot;)
default: // 예외 상황이 있을 때는 default가 반드시 있어야 함.
    print(&quot;unknown&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;반복문&lt;/h2&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;var integers = [1, 2, 3]
let people = [&quot;yagom&quot;: 10, &quot;eric&quot;: 15, &quot;mike&quot;: 12]

// for 문
for num in integers {
    print(num)
}

// Dictionary for 문 사용
for (name, age) in people {
    print(&quot;\\(name): \\(age)&quot;)
}

// white 문 (괄호 있어도, 없어도 됨)
while integers.count &amp;gt; 1 {
    integers.removeLast()
}

// 다른 언어의 do white과 동일
// do를 사용안한 이유는 swift는 오류 처리에서 do를 사용하기 때문
repeat {
    integers.removeLast()
} while integers.count &amp;gt; 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;옵셔널&lt;/h2&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;nil의 가능성을 명시적으로 표현&lt;/li&gt;
&lt;li&gt;코틀린과 마찬가지로 자료형에 ? 사용&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func someFunction(someOptionalParam: Int?) {
    
}
someFunction(someOptionalParam: nil)

func someFunction(someParam: Int) {
    
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;? : nil 일수도 있음&lt;/li&gt;
&lt;li&gt;! : 값이 반드시 있음. nil이면 에러 발생&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;구조체&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift의 구조체(Struct)는 데이터와 기능을 캡슐화하여 하나의 사용자 정의 데이터 타입을 정의할 수 있는 강력한 도구입니다. Swift의 구조체는 값 타입(Value Type)이며, &lt;b&gt;클래스와 유사한 기능을 많이 제공&lt;/b&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;b&gt;값 타입(Value Type)&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조체는 값 타입으로, 변수나 상수에 할당되거나 함수에 전달될 때 &lt;b&gt;복사&lt;/b&gt;됩니다.&lt;/li&gt;
&lt;li&gt;값 타입은 각 복사본이 독립적으로 존재하며, 하나의 인스턴스를 변경해도 다른 복사본에는 영향을 주지 않습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;속성과 메서드 포함 가능&lt;/b&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;/li&gt;
&lt;li&gt;&lt;b&gt;초기화 메서드 제공&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Swift는 구조체에 대해 자동으로 초기화 메서드(Initializer)를 생성합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로토콜 준수 가능&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;상속 불가&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 저장 속성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조체 내부에 데이터를 저장할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;struct Point {
    var x: Double
    var y: Double
}

let point = Point(x: 3.0, y: 4.0)
print(point.x) // 3.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 계산 속성&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;계산된 값을 반환하는 속성으로, 저장되지 않고 호출될 때마다 계산된다.&lt;/p&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;struct Rectangle {
    var width: Double
    var height: Double

    var area: Double {
        return width * height
    }
}

let rect = Rectangle(width: 5.0, height: 4.0)
print(rect.area) // 20.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 메서드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구조체는 인스턴스 메서드와 타입 메서드를 가질 수 있다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;struct Circle {
    var radius: Double

    func circumference() -&amp;gt; Double {
        return 2 * Double.pi * radius
    }
}

let circle = Circle(radius: 5.0)
print(circle.circumference()) // 31.41592653589793
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 가변 메서드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값 타입에서 메서드 내의 속성을 수정하려면 mutating 키워드를 사용해야 한다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;struct Counter {
    var count = 0

    mutating func increment() {
        count += 1
    }
}

var counter = Counter()
counter.increment()
print(counter.count) // 1
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 타입 속성과 타입 메서드&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;static 키워드를 사용하여 타입 수준에서 동작하는 속성과 메서드를 정의할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;struct Math {
    static let pi = 3.141592653589793

    static func square(_ value: Double) -&amp;gt; Double {
        return value * value
    }
}

print(Math.pi) // 3.141592653589793
print(Math.square(3)) // 9.0
&lt;/code&gt;&lt;/pre&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;&amp;bull; &lt;b&gt;독립적인 값 복사가 필요한 경우&lt;/b&gt;: 값이 변경될 때 다른 복사본에 영향을 주지 않아야 하는 경우.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; &lt;b&gt;상속이 필요하지 않은 경우&lt;/b&gt;: 상속이나 다형성이 필요하지 않다면 구조체를 사용.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; &lt;b&gt;간단한 데이터 모델링&lt;/b&gt;: 좌표(Point), 크기(Size), 범위(Range) 등.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;bull; &lt;b&gt;경량 데이터 처리&lt;/b&gt;: 메모리 효율적으로 데이터 처리.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클래스&lt;/h2&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;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;참조 타입(Reference Type)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스의 인스턴스는 변수에 할당되거나 함수로 전달될 때 참조(Reference)가 복사됩니다.&lt;/li&gt;
&lt;li&gt;같은 인스턴스를 여러 곳에서 참조하면, 한 곳에서 값을 변경할 경우 모든 참조에 영향을 미칩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;상속 가능(Inheritance)&lt;/b&gt;&lt;/li&gt;
&lt;/ol&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;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;초기화 메서드 제공&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스는 초기화 메서드(init)를 정의하여 초기 상태를 설정할 수 있습니다.&lt;/li&gt;
&lt;li&gt;필요에 따라 디이니셜라이저(deinit)를 사용하여 리소스를 해제할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;타입 캐스팅(Type Casting)&lt;/b&gt;:&lt;/li&gt;
&lt;/ol&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;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;값 비교&lt;/b&gt;:&lt;/li&gt;
&lt;/ol&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클래스는 &lt;b&gt;참조 비교&lt;/b&gt;를 사용하여 동일성(identity)을 확인합니다.&lt;/li&gt;
&lt;li&gt;=== 연산자를 사용하여 두 참조가 같은 인스턴스를 가리키는지 확인합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;프로토콜 준수 가능&lt;/b&gt;:&lt;/li&gt;
&lt;/ol&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;초기화와 디이니셜라이저&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;init&lt;/b&gt; : 클래스의 인스턴스를 생성할 때 호출되는 초기화 메서드&lt;/li&gt;
&lt;li&gt;&lt;b&gt;deinit&lt;/b&gt; : 인스턴스가 메모리에서 해제될 때 호출되는 디이니셜라이저&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;class Person {
    var name: String

    init(name: String) {
        self.name = name
        print(&quot;\\(name) is initialized&quot;)
    }

    deinit {
        print(&quot;\\(name) is being deinitialized&quot;)
    }
}

var person: Person? = Person(name: &quot;Alice&quot;)
person = nil // &quot;Alice is being deinitialized&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;열거형&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;enum은 타입이므로 대문자 카멜 케이스를 사용하여 이름 정의&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 case들은 소문자 카멜 케이스 사용&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Weekday {
    case mon // 하나씩 케이스를 만들어도 되고
    case thu
    case wed
    case thu, fri, sat, sun // 하나의 케이스에 여러개를 쓸 수도 있다
}

var day: Weekday = Weekday.mon // 이렇게 사용
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열거형은 switch 구문과 함께 자주 사용된다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func navigate(to direction: Direction) {
    switch direction {
    case .north:
        print(&quot;Move North&quot;)
    case .south:
        print(&quot;Move South&quot;)
    case .east:
        print(&quot;Move East&quot;)
    case .west:
        print(&quot;Move West&quot;)
    }
}

navigate(to: .north) // &quot;Move North&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각 케이스에 기본값(문자열, 정수 등)을 할당할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Weekday: String {
    case monday = &quot;Mon&quot;
    case tuesday = &quot;Tue&quot;
    case wednesday = &quot;Wed&quot;
    case thursday = &quot;Thu&quot;
    case friday = &quot;Fri&quot;
}

print(Weekday.monday.rawValue) // &quot;Mon&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열거형의 원시 값이 Int인 경우, 첫번째 값 이후 자동으로 증가한다.&lt;/p&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum Rank: Int {
    case one = 1
    case two
    case three
}

print(Rank.two.rawValue) // 2
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;열거형에 메서드를 정의할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;processing&quot;&gt;&lt;code&gt;enum TrafficLight {
    case red, yellow, green

    func description() -&amp;gt; String {
        switch self {
        case .red:
            return &quot;Stop&quot;
        case .yellow:
            return &quot;Caution&quot;
        case .green:
            return &quot;Go&quot;
        }
    }
}

let light = TrafficLight.green
print(light.description()) // &quot;Go&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;값 타입과 참조 타입&lt;/h2&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;/ul&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;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;값 타입 예제&lt;/h3&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;struct Point {
    var x: Int
    var y: Int
}

var point1 = Point(x: 10, y: 20)
var point2 = point1 // 독립적인 복사본 생성

point2.x = 30

print(point1.x) // 10 (point1은 변경되지 않음)
print(point2.x) // 30
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;참조 타입 예제&lt;/h3&gt;
&lt;pre class=&quot;gml&quot;&gt;&lt;code&gt;class Point {
    var x: Int
    var y: Int

    init(x: Int, y: Int) {
        self.x = x
        self.y = y
    }
}

let point1 = Point(x: 10, y: 20)
let point2 = point1 // 동일한 참조

point2.x = 30

print(point1.x) // 30 (point1과 point2는 동일한 참조를 공유)
print(point2.x) // 30
&lt;/code&gt;&lt;/pre&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;Apple 프레임워크는 대부분 클래스 사용&lt;/li&gt;
&lt;li&gt;Apple 프레임워크 사용시 구조체/클래스 선택은 우리의 몫&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;클로저&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저(Closure) 는 Swift에서 &lt;b&gt;중괄호&lt;/b&gt; {}&lt;b&gt;로 정의되는 코드 블록&lt;/b&gt;을 의미하며, 익명 함수와 유사한 개념으로 사용됩니다. 클로저는 데이터를 캡슐화하거나 특정 작업을 수행하는 코드를 작성하는 데 유용하며, 변수나 상수처럼 다른 곳으로 전달하거나 저장할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 문법&lt;/p&gt;
&lt;pre class=&quot;clojure&quot;&gt;&lt;code&gt;{ (parameters) -&amp;gt; returnType in
    // 실행 코드
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예시&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;let greet = { (name: String) -&amp;gt; String in
    return &quot;Hello, \\(name)!&quot;
}

print(greet(&quot;Alice&quot;)) // &quot;Hello, Alice!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;클로저 표현식 간소화&lt;/h3&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;매개변수와 반환값 타입 추론&lt;/b&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;let greet = { name in
    &quot;Hello, \\(name)!&quot;
}
print(greet(&quot;Bob&quot;)) // &quot;Hello, Bob!&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;타입을 생략하면 Swift가 타입을 추론한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;매개변수 이름 축약&lt;/b&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let square = { $0 * $0 }

print(square(5)) // 25
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;$0, $1 같은 축약 매개변수 이름을 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;후행 클로저&lt;/b&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4]
let doubled = numbers.map { $0 * 2 }

print(doubled) // [2, 4, 6, 8]
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;클로저가 함수의 마지막 매개변수로 전달될 때, 소괄호 ( ) 밖에 작성할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;비동기 작업&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클로저는 비동기 작업 (예 : 네트워크 요청, 타이머) 에서 콜백으로 자주 사용된다.&lt;/p&gt;
&lt;pre class=&quot;livescript&quot;&gt;&lt;code&gt;func fetchData(completion: @escaping (String) -&amp;gt; Void) {
    DispatchQueue.global().async {
        // 비동기 작업 수행
        let data = &quot;Sample Data&quot;
        DispatchQueue.main.async {
            completion(data)
        }
    }
}

fetchData { data in
    print(&quot;Fetched data: \\(data)&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UI 이벤트 처리&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift UI 및 UIKit에서 버튼 클릭이나 제스처 인식을 처리할 때 클로저를 사용한다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)

@objc func buttonTapped() {
    print(&quot;Button was tapped!&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로퍼티&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 저장 프로퍼티&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;var name: String = &quot;&quot;
var 'class': String = &quot;Swift&quot;
var koreanAge: Int = 0
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 연산 프로퍼티&lt;/p&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;var westernAge: Int {
    get {
        return koreanAge - 1
    }
    set(inputValue) {
        koreanAge = inputValue + 1
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타입 저장 프로퍼티&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;static var typeDescription: String = &quot;학생&quot;
&lt;/code&gt;&lt;/pre&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;get만 있으면 읽기 전용, 쓰기 전용은 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;javascript&quot;&gt;&lt;code&gt;var selfIntroduction: String {
    get {
        return &quot;저는 \\(self.class)반 \\(name)입니다&quot;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set에서 특별히 (inputValue)와 같이 선언하지 않으면 기본적으로 newValue 를 사용하면 된다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;struct Money {
    var currencyRate: Double = 1480
    var dollar: Double = 0
    var won: Double {
        get {
            return dollar * currencyRate
        }
        set {
            dollar = newValue / currencyRate
        }
    }
}

var moneyInMyPoket = Money()
moneyInMyPoket.won = 14800 // 14800
moneyInMyPoket.dollar = 10 // 14800
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로퍼티 감시자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로퍼티 감시자는 willSet과 didSet이라는 두 가지 키워드를 사용하여 정의된다.&lt;/p&gt;
&lt;pre class=&quot;haxe&quot;&gt;&lt;code&gt;var propertyName: Type {
    willSet(newValue) {
        // 값이 설정되기 직전에 호출
    }
    didSet {
        // 값이 설정된 직후에 호출
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;willSet&lt;/b&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;b&gt;직전&lt;/b&gt;에 호출됩니다.&lt;/li&gt;
&lt;li&gt;newValue라는 매개변수로 새 값을 전달받습니다.&lt;/li&gt;
&lt;li&gt;newValue 이름을 생략하면 기본적으로 newValue가 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;didSet&lt;/b&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;b&gt;직후&lt;/b&gt;에 호출됩니다.&lt;/li&gt;
&lt;li&gt;oldValue라는 매개변수로 이전 값을 참조할 수 있습니다.&lt;/li&gt;
&lt;li&gt;oldValue 이름을 생략하면 기본적으로 oldValue가 사용됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본 예제&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;struct Counter {
    var count: Int = 0 {
        willSet(newCount) {
            print(&quot;Count will be set to \\(newCount)&quot;)
        }
        didSet {
            print(&quot;Count was set from \\(oldValue) to \\(count)&quot;)
        }
    }
}

var counter = Counter()
counter.count = 10
// 출력:
// &quot;Count will be set to 10&quot;
// &quot;Count was set from 0 to 10&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;유효성 검사&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 설정할 때 유효성을 확인하거나, 특정 조건을 만족하지 않으면 값을 되돌리는 로직&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;var age: Int = 0 {
    didSet {
        if age &amp;lt; 0 {
            print(&quot;Invalid age, resetting to 0&quot;)
            age = 0
        }
    }
}

age = -5
// &quot;Invalid age, resetting to 0&quot;
print(age) // 0
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;UI 업데이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;UI가 프로퍼티 값에 따라 동적으로 변경되어야 할 때 사용할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;var score: Int = 0 {
    didSet {
        print(&quot;Updating UI: New score is \\(score)&quot;)
    }
}

score = 100
// 출력:
// &quot;Updating UI: New score is 100&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;의존 값 자동 업데이트&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;한 프로퍼티가 다른 프로퍼티에 의존할 경우, 값을 자동으로 업데이트 할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;hsp&quot;&gt;&lt;code&gt;var length: Double = 0.0 {
    didSet {
        area = length * width
    }
}

var width: Double = 0.0 {
    didSet {
        area = length * width
    }
}

var area: Double = 0.0

length = 10.0
width = 5.0
print(area) // 50.0
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;상속&lt;/h2&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;li&gt;스위프트는 다중상속을 지원하지 않는다&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;class Person {
    var name: String = &quot;동환&quot;
    
    func selfIntroduce() {
        print(&quot;저는 \\(name)입니다&quot;)
    }
    
    // final 키워드를 사용하여 재정의를 방지할 수 있습니다
    final func sayHello() {
        print(&quot;hello&quot;)
    }
    
    // 재정의 불가 타입 메서드
    static func typeMethod() {
        
    }
    
    // 재정의 가능 타입 메서드
    class func classMethod() {
        
    }
    
    // 메서드 앖의 final class는 static과 똑같은 역할이므로 재정의 할 수 없다
    final class func finalClassMethod() {
        
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;인스턴스의 생성과 소멸&lt;/h2&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 class=&quot;lasso&quot;&gt;&lt;code&gt;class Person {
    var name: String
    var age: Int
    var nickName: String
    
    init(name: String, age: Int, nickName: String) {
        self.name = name
        self.age = age
        self.nickName
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 프로퍼티의 초기 값이 꼭 필요 없다면 null 허용을 하면 된다&lt;/p&gt;
&lt;pre class=&quot;dart&quot;&gt;&lt;code&gt;var nickName: String?
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;암시적 추출 옵셔널 (kotlin : lateinit)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스 사용에 꼭 필요하지만 초기값을 할당하지 않고자 할 때 사용&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;class Puppy {
    var name: String
    var owner: Person!
    
    init(name: String) {
        self.name = name
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;반드시 있어야 하는 owner에 ! 를 붙여서 반드시 필요함을 알려주고, 나중에 초기화 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;kotlin의 lateinit과 비슷한 것 같다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;옵셔널 체이닝과 nil 병합 연산자&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코틀린과 유사해서 너무 좋다!&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;var guardJob: String
    guardJob = donghwan?.home?.guard?.job ?? &quot;슈퍼맨&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;? 로 nil 인지 아닌지 확인하는 것이 옵셔널 체이닝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;?? 로 nil 이면 &amp;ldquo;슈퍼맨&amp;rdquo; 을 적용하는 것이 nil 병합 연산자&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;타입 캐스팅&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스턴스의 타입을 확인하는 용도.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;is, as 를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&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&gt;is&lt;/td&gt;
&lt;td&gt;객체가 특정 타입인지 확인. 결과는 true 또는 false.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;as&lt;/td&gt;
&lt;td&gt;캐스팅을 수행. 성공해야만 동작하며, 실패 시 런타임 에러 발생&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;as?&lt;/td&gt;
&lt;td&gt;옵셔널 캐스팅. 캐스팅 성공 시 옵셔널 타입으로 반환, 실패 시 nil.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;as!&lt;/td&gt;
&lt;td&gt;강제 캐스팅. 캐스팅 실패 시 런타임 에러 발생.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;타입 확인 (is)&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;class Animal {}
class Dog: Animal {}
class Cat: Animal {}

let pet: Animal = Dog()

if pet is Dog {
    print(&quot;This is a Dog&quot;)
} else if pet is Cat {
    print(&quot;This is a Cat&quot;)
}
// 출력: &quot;This is a Dog&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;안전한 캐스팅 (as?)&lt;/h3&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;let pet: Animal = Dog()

if let dog = pet as? Dog {
    print(&quot;This is a Dog: \\(dog)&quot;)
} else {
    print(&quot;Not a Dog&quot;)
}
// 출력: &quot;This is a Dog: Dog&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;강제 캐스팅 (as!)&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let pet: Animal = Dog()

let dog = pet as! Dog // 강제 캐스팅
print(&quot;This is a Dog: \\(dog)&quot;)
// 출력: &quot;This is a Dog: Dog&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;assert&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;assert 함수는 디버깅 모드에서만 동작한다.&lt;/li&gt;
&lt;li&gt;배포하는 앱에서는 제외된다.&lt;/li&gt;
&lt;li&gt;주로 디버깅 중 조건의 검증을 위해 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;간단한 조건 검사&lt;/h3&gt;
&lt;pre class=&quot;nix&quot;&gt;&lt;code&gt;let age = 25
assert(age &amp;gt;= 0, &quot;Age cannot be negative&quot;)
&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;위 코드에서 age가 음수일 경우 프로그램이 중단되고, 메시지 &quot;Age cannot be negative&quot;가 출력된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;논리적 오류 확인&lt;/h3&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;let number = 10
assert(number % 2 == 0, &quot;Number must be even&quot;)
// 조건이 참이므로 프로그램 계속 실행
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;배열 인덱스 검사&lt;/h3&gt;
&lt;pre class=&quot;sas&quot;&gt;&lt;code&gt;let array = [1, 2, 3]
let index = 2

assert(index &amp;gt;= 0 &amp;amp;&amp;amp; index &amp;lt; array.count, &quot;Index out of bounds&quot;)
// index가 유효한지 확인
print(array[index]) // 정상 실행
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;guard&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;guard를 사용하여 잘못된 값을 전달시 특정 실행 구문을 빠르게 종료한다.&lt;/li&gt;
&lt;li&gt;디버깅 모드 뿐만 아니라 어떤 조건에서도 동작한다.&lt;/li&gt;
&lt;li&gt;guard의 else 블럭 내부에는 특정 코드 블럭을 종료하는 지시어 (return, break 등)가 있어야 한다.&lt;/li&gt;
&lt;li&gt;타입 캐스팅, 옵셔널과도 자주 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 기본 사용&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func checkNumber(_ number: Int) {
    guard number &amp;gt; 0 else {
        print(&quot;Number must be greater than 0&quot;)
        return
    }

    print(&quot;Number is \\(number)&quot;)
}

checkNumber(5)   // 출력: &quot;Number is 5&quot;
checkNumber(-3)  // 출력: &quot;Number must be greater than 0&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 옵셔널 바인딩&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;guard let을 사용하여 옵셔널 값을 안전하게 언래핑할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func greet(name: String?) {
    guard let unwrappedName = name else {
        print(&quot;Name is nil&quot;)
        return
    }
    print(&quot;Hello, \\(unwrappedName)!&quot;)
}

greet(name: &quot;Alice&quot;) // 출력: &quot;Hello, Alice!&quot;
greet(name: nil)     // 출력: &quot;Name is nil&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 여러 조건 검사&lt;/h3&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;func validateUser(age: Int?, name: String?) {
    guard let age = age, age &amp;gt;= 18, let name = name, !name.isEmpty else {
        print(&quot;Invalid user&quot;)
        return
    }

    print(&quot;Welcome, \\(name), age \\(age)&quot;)
}

validateUser(age: 20, name: &quot;Alice&quot;) // 출력: &quot;Welcome, Alice, age 20&quot;
validateUser(age: nil, name: &quot;Bob&quot;)  // 출력: &quot;Invalid user&quot;
validateUser(age: 16, name: &quot;Eve&quot;)  // 출력: &quot;Invalid user&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로토콜&lt;/h2&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;어려운 설명&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift에서 &lt;b&gt;특정 역할을 수행하기 위해 필요한 메서드, 프로퍼티, 또는 기타 요구사항을 정의&lt;/b&gt;하는 청사진(blueprint)입니다. 클래스, 구조체, 열거형은 프로토콜을 채택(Adopt)하고, 정의된 요구사항을 구현(Implement)해야 합니다.&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;어떤 객체가 이런 기능을 제공해야 한다 라는 약속을 정하는 것.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;기본 문법&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;protocol ProtocolName {
    // 메서드, 프로퍼티 요구사항 정의
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜 정의&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;protocol Greetable {
    var name: String { get } // 읽기 가능한 프로퍼티
    func greet()             // 메서드 요구사항
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로토콜 채택 및 구현&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;struct Person: Greetable {
    var name: String

    func greet() {
        print(&quot;Hello, my name is \\(name).&quot;)
    }
}

let person = Person(name: &quot;Alice&quot;)
person.greet() // 출력: &quot;Hello, my name is Alice.&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;코틀린과 비교&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Swift&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;protocol Greetable {
    var name: String { get }
    func greet()
}

struct Person: Greetable {
    var name: String
    func greet() {
        print(&quot;Hello, \\(name)!&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;interface Greetable {
    val name: String
    fun greet()
}

class Person(override val name: String) : Greetable {
    override fun greet() {
        println(&quot;Hello, $name!&quot;)
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;익스텐션&lt;/h2&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;rarr; 코틀린의 확장 함수와 유사함&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;계산 프로퍼티 추가&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;익스텐션 타입으로 기존 타입에 새로운 계산 프로퍼티를 추가할 수 있다.&lt;/p&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;extension Int {
    var squared: Int {
        return self * self
    }
}

let number = 5
print(number.squared) // 출력: 25
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;메서드 추가&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;extension String {
    func isPalindrome() -&amp;gt; Bool {
        return self == String(self.reversed())
    }
}

let word = &quot;racecar&quot;
print(word.isPalindrome()) // 출력: true
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;오류 처리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자 정의 에러를 만들 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Error 타입은 열거형으로 구현되는 경우가 많고, 에러를 정의하고 throw, catch를 통해 에러를 처리한다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. 에러 정의&lt;/h3&gt;
&lt;pre class=&quot;crystal&quot;&gt;&lt;code&gt;enum NetworkError: Error {
    case badURL
    case timeout
    case noInternetConnection
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 에러 발생 (throw)&lt;/h3&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func fetchData(from url: String) throws {
    guard url.starts(with: &quot;http&quot;) else {
        throw NetworkError.badURL
    }
    // 데이터 요청 로직
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. 에러 처리 (do-catch)&lt;/h3&gt;
&lt;pre class=&quot;gradle&quot;&gt;&lt;code&gt;do {
    try fetchData(from: &quot;invalid-url&quot;)
} catch NetworkError.badURL {
    print(&quot;Invalid URL.&quot;)
} catch NetworkError.timeout {
    print(&quot;Request timed out.&quot;)
} catch {
    print(&quot;An unknown error occurred: \\(error).&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;hr data-ke-style=&quot;style1&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;에러 처리 키워드&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;throws&lt;/h3&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;throws는 함수 선언에 붙으며, 반환 타입 전에 작성된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;swift&quot;&gt;&lt;code&gt;func riskyFunction() throws -&amp;gt; String {
    throw NetworkError.timeout
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;try&lt;/h3&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;/ul&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;do {
    try riskyFunction()
} catch {
    print(&quot;An error occurred.&quot;)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;try?&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;에러를 옵셔널 값 nil로 처리한다. 에러가 발생하면 nil이 반환된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;nimrod&quot;&gt;&lt;code&gt;let result = try? riskyFunction() // 에러 발생 시 result는 nil
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;try!&lt;/h3&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;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;let result = try! riskyFunction() // 에러 발생 시 앱이 크래시
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;고차 함수&lt;/h2&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;ex ) map, filter, reduce&lt;/li&gt;
&lt;li&gt;&lt;b&gt;다른 함수를 매개변수로 받거나, 함수를 반환하거나, 둘 다 수행할 수 있는 함수&lt;/b&gt;를 말합니다. Swift는 고차 함수를 통해 더 간결하고 읽기 쉬운 코드를 작성할 수 있도록 다양한 함수형 프로그래밍 기능을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;map&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션의 각 요소를 변환하여 새 배열을 한봔한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5]
let squares = numbers.map { $0 * $0 } // 각 요소를 제곱
print(squares) // [1, 4, 9, 16, 25]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;filter&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;filter 조건을 만족하는 요소만 포함하는 새 배열을 반환한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5]
let evenNumbers = numbers.filter { $0 % 2 == 0 } // 짝수만 포함
print(evenNumbers) // [2, 4]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;reduce&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;초기값과 연산을 사용해 모든 요소를 결합하여 단일 값을 만든다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5]
let sum = numbers.reduce(0) { $0 + $1 } // 합계 계산
print(sum) // 15
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;forEach&lt;/h3&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;let names = [&quot;Alice&quot;, &quot;Bob&quot;, &quot;Charlie&quot;]
names.forEach { print($0) }
// 출력:
// Alice
// Bob
// Charlie
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;compactMap&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;옵셔널 요소를 제거하고, 비-옵셔널 값으로 이루어진 배열을 반환한다.&lt;/p&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;let strings = [&quot;1&quot;, &quot;two&quot;, &quot;3&quot;, &quot;four&quot;]
let numbers = strings.compactMap { Int($0) } // 문자열을 정수로 변환, 실패한 경우 제거
print(numbers) // [1, 3]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;flatMap&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;중첩된 컬렉션을 평평한 단일 컬렉션으로 변환한다.&lt;/p&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let nestedArray = [[1, 2, 3], [4, 5], [6]]
let flatArray = nestedArray.flatMap { $0 }
print(flatArray) // [1, 2, 3, 4, 5, 6]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;sorted&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컬렉션의 요소를 정렬된 새로운 배열로 반환&lt;/p&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;let numbers = [5, 2, 3, 1, 4]
let sortedNumbers = numbers.sorted() // 기본 오름차순 정렬
print(sortedNumbers) // [1, 2, 3, 4, 5]

let descending = numbers.sorted { $0 &amp;gt; $1 } // 내림차순 정렬
print(descending) // [5, 4, 3, 2, 1]
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;고차 함수의 결합&lt;/h3&gt;
&lt;pre class=&quot;angelscript&quot;&gt;&lt;code&gt;let numbers = [1, 2, 3, 4, 5]
let result = numbers
    .filter { $0 % 2 == 0 } // 짝수만 필터링
    .map { $0 * $0 }        // 제곱 계산
print(result) // [4, 16]
&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/IOS</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/273</guid>
      <comments>https://haruple.tistory.com/273#entry273comment</comments>
      <pubDate>Sat, 11 Jan 2025 16:57:22 +0900</pubDate>
    </item>
    <item>
      <title>맥북 파일명 규칙 설정 후 사진 이름 전체 설정하기</title>
      <link>https://haruple.tistory.com/272</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;갤럭시 사진 파일명 규칙 : 20241018_200851.jpg&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A7M3 카메라로 촬영한 파일 명은 아래와 같이 사진 이름에 DSC 뒤에 사진을 찍은 갯수만큼 숫자가 증가하고, 만장을 다 찍어서 숫자가 넘어가야 할 때는 새로운 폴더가 생겨서 1번부터 다시 저장됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;334&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xF5bo/btsKb5iT3nq/pKCIrHA6YcdkGA1M2Cveo0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xF5bo/btsKb5iT3nq/pKCIrHA6YcdkGA1M2Cveo0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xF5bo/btsKb5iT3nq/pKCIrHA6YcdkGA1M2Cveo0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxF5bo%2FbtsKb5iT3nq%2FpKCIrHA6YcdkGA1M2Cveo0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1446&quot; height=&quot;334&quot; data-origin-width=&quot;1446&quot; data-origin-height=&quot;334&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;
&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;맥북 사진 파일명 일괄 변경 방법&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. Homebrew, exittool 설치&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 Homebrew를 사용해서 exiftool을 설치해야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Homebrew가 설치되어 있지 않다면 먼저 Homebrew를 설치하고, 그 후에 exiftool을 설치합니다.&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;Homebrew 설치 명령어&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729402186768&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/bin/bash -c &quot;$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)&quot;&lt;/code&gt;&lt;/pre&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;exiftool 설치 명령어&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1729402240441&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;brew install exiftool&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&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;2. 해당 폴더로 이동&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;터미널에서 해당 디렉토리로 이동합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 바탕화면의 file_name_test 에 위치해 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729402305443&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd Desktop
cd file_name_test&lt;/code&gt;&lt;/pre&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;h4 data-ke-size=&quot;size20&quot;&gt;3. 파일명 변경 명령어&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이제 촬영 날짜를 기반으로 파일명을 변경하는 명령어를 실행합니다. 아래 명령어는 파일명을 YYYYMMDD_HHMMSS 형식으로 변경해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1729402391202&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;exiftool '-FileName&amp;lt;CreateDate' -d %Y%m%d_%H%M%S%%-c.%%e .&lt;/code&gt;&lt;/pre&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;-FileName&amp;lt;CreateDate' : 파일의 촬영 날짜를 파일 명으로 설정&lt;/li&gt;
&lt;li&gt;-d %Y%m%d_%H%M%S%%-c.%%e : 파일명 형식을 YYYYMMDD_HHMMSS로 지정하며, 만약 동일한 파일 명이 있다면 숫자를 추가 (%%-c)&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;354&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbxpvY/btsKddG4N7e/D3jb2M88wfHi5DpsSnVMxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbxpvY/btsKddG4N7e/D3jb2M88wfHi5DpsSnVMxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbxpvY/btsKddG4N7e/D3jb2M88wfHi5DpsSnVMxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbxpvY%2FbtsKddG4N7e%2FD3jb2M88wfHi5DpsSnVMxk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1208&quot; height=&quot;354&quot; data-origin-width=&quot;1208&quot; data-origin-height=&quot;354&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;&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;&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;&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;a href=&quot;https://exiftool.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://exiftool.org/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1736170069985&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;ExifTool by Phil Harvey&quot; data-og-description=&quot;0 (Information&amp;nbsp;Type) AAC, AFCP, AIFF, APE, APP0, APP1, APP11, APP12, APP13, APP14, APP15, APP2, APP3, APP4, APP5, APP6, APP7, APP8, APP9, ASF, Audible, Canon, CanonVRD, Composite, DICOM, DNG, DV, DjVu, Ducky, EXE, EXIF, ExifTool, FITS, FLAC, FLIR, File, F&quot; data-og-host=&quot;exiftool.org&quot; data-og-source-url=&quot;https://exiftool.org/&quot; data-og-url=&quot;https://exiftool.org/&quot; data-og-image=&quot;&quot;&gt;&lt;a href=&quot;https://exiftool.org/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://exiftool.org/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url();&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;ExifTool by Phil Harvey&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;0 (Information&amp;nbsp;Type) AAC, AFCP, AIFF, APE, APP0, APP1, APP11, APP12, APP13, APP14, APP15, APP2, APP3, APP4, APP5, APP6, APP7, APP8, APP9, ASF, Audible, Canon, CanonVRD, Composite, DICOM, DNG, DV, DjVu, Ducky, EXE, EXIF, ExifTool, FITS, FLAC, FLIR, File, F&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;exiftool.org&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 홈페이지에서 exiftool 다운로드&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;exiftool&amp;nbsp;&quot;-FileName&amp;lt;CreateDate&quot;&amp;nbsp;-d&amp;nbsp;%%Y%%m%%d_%%H%%M%%S%%-c.%%e&quot;&amp;nbsp;&quot;C:\path\to\directory&quot;&lt;/p&gt;</description>
      <category>일상/사진</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/272</guid>
      <comments>https://haruple.tistory.com/272#entry272comment</comments>
      <pubDate>Sun, 20 Oct 2024 14:35:34 +0900</pubDate>
    </item>
    <item>
      <title>[6월에 읽은 도서] 적게 벌어도 잘사는 노후 50년</title>
      <link>https://haruple.tistory.com/271</link>
      <description>&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;어느덧 6개월이 흘러 드디어 이번 챌린지의 마지막 책입니다!&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cabP7m/btskifDaAL4/IZvYmxIKHTUx1aFIqMybbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cabP7m/btskifDaAL4/IZvYmxIKHTUx1aFIqMybbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cabP7m/btskifDaAL4/IZvYmxIKHTUx1aFIqMybbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcabP7m%2FbtskifDaAL4%2FIZvYmxIKHTUx1aFIqMybbK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;558&quot; height=&quot;744&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&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;저자의 말로 지금부터 준비해서 100세까지 노후 50년을 돈으로부터 자유롭게 보낼 수 있다고 하는데 27살인 내나이에도 나이 50, 60때가 걱정이긴 하다. 그 이후 50년을 그 전에 번거로 먹고 살아야하니깐..&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;일단 20, 30대라면 현금 흐름표를 작성해보라고 했다.&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;책에서 기본적으로 이런 책들에서 많이 설명하는 많이 버는 것과 지출을 통제하는 것들에 대한 내용들도 재미있었지만 차에 대한 이야기가 유독 재미있었다. 내 주변 친구들은 다들 많이 타고 있어서 그런것 같다. 저자가 이야기 하기로 가치를 두는 지출이라도 지금 지출할지 좀 더 미뤘다가 할지는 결과가 크게 다르다고 한다. 지금까지도 열심히 모아왔으니 차는 결혼할때쯤 뽑도록 해야지&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;노후에 대해서는 크게 생각해보지 않았었는데 이 책을 보면서 그렇게 멀지 않은 것처럼 느껴졌고 체계적으로 준비를 미리 잘해놔야겠다고 생각이 들었다. 20대에 이런 생각을 일찍 가질 수 있어 어찌보면 다행이라는 생각도 들었다. 뭐든 최대한 일찍 준비하면 좋으니깐!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>일상/일상</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/271</guid>
      <comments>https://haruple.tistory.com/271#entry271comment</comments>
      <pubDate>Sat, 17 Jun 2023 00:04:00 +0900</pubDate>
    </item>
    <item>
      <title>엔비디아 차세대 GPU는 TSMC에서 생산</title>
      <link>https://haruple.tistory.com/270</link>
      <description>&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;앞으로의 인공지능 개발에 필요한 GPU의 90%를 엔비디아가 담당하고 있기 때문에 기대감도 많이 반영된 것 같습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 날 하루에 25%가 오르는 기적을 체험했는데요.. 저는 -60%까지 갔다가 +60%가 넘어섰습니다.. 이게뭐지..&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;엔비디아 CEO인 젠슨 황은 컴퓨텍스의 Q&amp;amp;A에서 엔비디아의 차세대 GPU가 TSMC에서 만들어질 것이라고 밝혔습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;TSMC 주가도 요즘 어마어마하게 고공행진 하고 있는데 불을 더 지피겠군요..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/MtSl8/btsit0P0wzX/gDp9PfnCh40E7SEwOgacq1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/MtSl8/btsit0P0wzX/gDp9PfnCh40E7SEwOgacq1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/MtSl8/btsit0P0wzX/gDp9PfnCh40E7SEwOgacq1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FMtSl8%2Fbtsit0P0wzX%2FgDp9PfnCh40E7SEwOgacq1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;960&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;960&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로이터&lt;span&gt; &lt;/span&gt;통신은&lt;span&gt; &lt;/span&gt;이번&lt;span&gt; &lt;/span&gt;주&lt;span&gt; &lt;/span&gt;목요일&lt;span&gt; &lt;/span&gt;타이베이에서&lt;span&gt; &lt;/span&gt;열린&lt;span&gt; Q&amp;amp;A &lt;/span&gt;세션에서&lt;span&gt; &lt;/span&gt;젠슨&lt;span&gt; &lt;/span&gt;황&lt;span&gt; CEO&lt;/span&gt;가&lt;span&gt; &lt;/span&gt;언론에&lt;span&gt; TSMC&lt;/span&gt;에&lt;span&gt; &lt;/span&gt;크게&lt;span&gt; &lt;/span&gt;의존함으로써&lt;span&gt; &lt;/span&gt;안전하다고&lt;span&gt; &lt;/span&gt;느끼며&lt;span&gt; &lt;/span&gt;그의&lt;span&gt; &lt;/span&gt;차세대&lt;span&gt; &lt;/span&gt;칩은&lt;span&gt; TSMC&lt;/span&gt;에서&lt;span&gt; &lt;/span&gt;만들어질&lt;span&gt; &lt;/span&gt;것이라고&lt;span&gt; &lt;/span&gt;말했습니다&lt;span&gt;. &lt;/span&gt;이번&lt;span&gt; &lt;/span&gt;발표는&lt;span&gt; &lt;/span&gt;대만이&lt;span&gt; &lt;/span&gt;중국의&lt;span&gt; &lt;/span&gt;군사적&lt;span&gt; &lt;/span&gt;위협을&lt;span&gt; &lt;/span&gt;받을&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있는&lt;span&gt; &lt;/span&gt;위험에&lt;span&gt; &lt;/span&gt;처해&lt;span&gt; &lt;/span&gt;있는&lt;span&gt; &lt;/span&gt;상황에서&lt;span&gt; &lt;/span&gt;나온&lt;span&gt; &lt;/span&gt;것입니다&lt;span&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&gt; 2023&lt;/span&gt;에서&lt;span&gt; &lt;/span&gt;엔비디아는&lt;span&gt; Hopper-Next &lt;/span&gt;칩이&lt;span&gt; 2024&lt;/span&gt;년에&lt;span&gt; &lt;/span&gt;출시될&lt;span&gt; &lt;/span&gt;것임을&lt;span&gt; &lt;/span&gt;보여주는&lt;span&gt; GPU &lt;/span&gt;로드맵을&lt;span&gt; &lt;/span&gt;공개했으며&lt;span&gt; &lt;/span&gt;아직&lt;span&gt; &lt;/span&gt;정해진&lt;span&gt; &lt;/span&gt;것은&lt;span&gt; &lt;/span&gt;없지만&lt;span&gt; 3nm &lt;/span&gt;프로세스&lt;span&gt; &lt;/span&gt;노드를&lt;span&gt; &lt;/span&gt;사용할&lt;span&gt; &lt;/span&gt;것이라는&lt;span&gt; &lt;/span&gt;루머가&lt;span&gt; &lt;/span&gt;있습니다&lt;span&gt;. &lt;/span&gt;차세대&lt;span&gt; GPU&lt;/span&gt;의&lt;span&gt; &lt;/span&gt;코드네임도&lt;span&gt; Blackwell&lt;/span&gt;이&lt;span&gt; &lt;/span&gt;될&lt;span&gt; &lt;/span&gt;것으로&lt;span&gt; &lt;/span&gt;예상됩니다&lt;span&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&gt;아무래도 3nm 프로세스 노드만큼 작은 nm 단위를 생산해야하기 때문에 수율이 타 업체에서는 높지 않기 때문에 TSMC를 사용하는 것이 아닐까 추측됩니다.&lt;/span&gt;&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;678&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c3AOrv/btsiu0u7yf9/Nzv9WIoyd7VxgJiYKM2Dq1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c3AOrv/btsiu0u7yf9/Nzv9WIoyd7VxgJiYKM2Dq1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c3AOrv/btsiu0u7yf9/Nzv9WIoyd7VxgJiYKM2Dq1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc3AOrv%2Fbtsiu0u7yf9%2FNzv9WIoyd7VxgJiYKM2Dq1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;1280&quot; height=&quot;678&quot; data-origin-width=&quot;1280&quot; data-origin-height=&quot;678&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일주일&lt;span&gt; &lt;/span&gt;전&lt;span&gt;, &lt;/span&gt;엔비디아는&lt;span&gt; &lt;/span&gt;새로운&lt;span&gt; &lt;/span&gt;차원으로&lt;span&gt; &lt;/span&gt;도약한&lt;span&gt; AI &lt;/span&gt;추진&lt;span&gt; &lt;/span&gt;덕분에&lt;span&gt; 1&lt;/span&gt;조&lt;span&gt; &lt;/span&gt;달러&lt;span&gt; &lt;/span&gt;클럽에&lt;span&gt; &lt;/span&gt;가입하게&lt;span&gt; &lt;/span&gt;되었습니다&lt;span&gt;. &lt;/span&gt;그러나&lt;span&gt; &lt;/span&gt;데이터&lt;span&gt; &lt;/span&gt;센터와&lt;span&gt; AI&lt;/span&gt;의&lt;span&gt; &lt;/span&gt;엄청난&lt;span&gt; &lt;/span&gt;성장에도&lt;span&gt; &lt;/span&gt;불구하고&lt;span&gt;, &lt;/span&gt;젠슨&lt;span&gt; &lt;/span&gt;황은&lt;span&gt; &lt;/span&gt;게이머가&lt;span&gt; &lt;/span&gt;잊혀진&lt;span&gt; &lt;/span&gt;것이&lt;span&gt; &lt;/span&gt;아니며&lt;span&gt; &lt;/span&gt;여전히&lt;span&gt; &lt;/span&gt;비즈니스의&lt;span&gt; &lt;/span&gt;주요한&lt;span&gt; &lt;/span&gt;중추라고&lt;span&gt; &lt;/span&gt;안심시켰습니다&lt;span&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;코로나 시국에 엔비디아 주식을 샀었는데 그 당시만 하더라도 엔비디아의 주요 수익원은 게이밍 수요에 따른 GPU나 코인 채굴에 따른 GPU 판매였었습니다. 그러다 코로나가 점점 풀리면서 사람들이 야외 활동을 하기 시작하면서 게이밍 GPU 수요가 감소하기 시작했었습니다. 그리고 3000번대 GPU 3060만 이용해도 애지간한 게임 대부분이 돌아가기 때문에 성능이 상향평준화 되어있어서 높은 수준의 그래픽카드가 필요하지 않아서 더 팔리지 않은 것 같습니다. 거기다 코인 채굴이 막힌 버전으로 출시하며서 GPU 의 가격은 내려가기 시작했습니다. 그런데 이게 인공지능 덕분에 반전을 맞을줄은 몰랐네요.. 다행히 저의 수익률도 반전을 맞았습니다! 얼마나 오래 기다렸던지..ㅜㅜ&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>일상/전자제품</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/270</guid>
      <comments>https://haruple.tistory.com/270#entry270comment</comments>
      <pubDate>Thu, 8 Jun 2023 20:53:50 +0900</pubDate>
    </item>
    <item>
      <title>[Android | Kotlin] 테두리가 있는 TextView 개발하기</title>
      <link>https://haruple.tistory.com/269</link>
      <description>&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;이전 포스팅에서 ProgressBar를 커스텀해서 예쁜 UI로 만들었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;144&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/AvbYX/btsit0vEdzV/K1MU3n8SQq91TlMrwexm6k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/AvbYX/btsit0vEdzV/K1MU3n8SQq91TlMrwexm6k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/AvbYX/btsit0vEdzV/K1MU3n8SQq91TlMrwexm6k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FAvbYX%2Fbtsit0vEdzV%2FK1MU3n8SQq91TlMrwexm6k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;438&quot; height=&quot;115&quot; data-origin-width=&quot;548&quot; data-origin-height=&quot;144&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 단순히 TextView를 ProgressBar 안에 적용해도 되긴 하지만 가독성이 떨어져서 쉽게 읽히지 않았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 테두리가 있는 TextView를 개발해서 위 사진처럼 테두리를 적용하는 방법을 알려드리겠습니다.&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;먼저 일반적인 TextView를 커스텀하는 것 처럼 AppCompatTextView를 상속받는 OutLineTextView 클래스를 만들었습니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;class OutlineTextView : AppCompatTextView {
}&lt;/code&gt;&lt;/pre&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;만약 Activity나 Fragment에서 직접 이 두께와 컬러를 지정하려면 private를 해제하고 사용하면 됩니다.&lt;/p&gt;
&lt;pre class=&quot;actionscript&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;private var stroke = false
private var strokeWidth = 0.0f
private var strokeColor = 0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 XML에서 OutLine 옵션을 지정할 수 있도록 styleable에 각 옵션을 등록해두었습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;private fun initView(context: Context, attrs: AttributeSet?) {
    val type = context.obtainStyledAttributes(attrs, R.styleable.OutlineTextView)
    stroke = type.getBoolean(R.styleable.OutlineTextView_out_line_text_view_has_stroke, false) // 아웃라인 유무
    strokeWidth = type.getFloat(R.styleable.OutlineTextView_out_line_text_view_stroke_width, 0.0f) // 아웃라인 두께
    strokeColor = type.getColor(R.styleable.OutlineTextView_out_line_text_view_stroke_color, -0x1) // 아웃라인 컬러
}&lt;/code&gt;&lt;/pre&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;attrs.xml&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;pgsql&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;&amp;lt;declare-styleable name=&quot;OutlineTextView&quot;&amp;gt;
    &amp;lt;attr name=&quot;out_line_text_view_has_stroke&quot; format=&quot;boolean&quot; /&amp;gt;
    &amp;lt;attr name=&quot;out_line_text_view_stroke_width&quot; format=&quot;float&quot; /&amp;gt;
    &amp;lt;attr name=&quot;out_line_text_view_stroke_color&quot; format=&quot;integer&quot;/&amp;gt;
&amp;lt;/declare-styleable&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 onDraw 함수를 통해 Stroke를 만들어주면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;캔버스를 이용해서 텍스트뷰에 stroke를 그려줄 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;override fun onDraw(canvas: Canvas) {
    if (stroke) {
        val states = textColors
        paint.style = Paint.Style.STROKE
        paint.strokeWidth = strokeWidth
        setTextColor(strokeColor)
        super.onDraw(canvas)
        paint.style = Paint.Style.FILL
        setTextColor(states)
    }
    super.onDraw(canvas)
}&lt;/code&gt;&lt;/pre&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 OutLineTextView 클래스 전체 코드입니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;class OutlineTextView : AppCompatTextView {

    private var stroke = false
    private var strokeWidth = 0.0f
    private var strokeColor = 0

    constructor(context: Context?) : super(context!!) {}
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
        initView(context, attrs)
    }

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
        initView(context, attrs)
    }

    private fun initView(context: Context, attrs: AttributeSet?) {
        val type = context.obtainStyledAttributes(attrs, R.styleable.OutlineTextView)
        stroke = type.getBoolean(R.styleable.OutlineTextView_out_line_text_view_has_stroke, false) // 아웃라인 유무
        strokeWidth = type.getFloat(R.styleable.OutlineTextView_out_line_text_view_stroke_width, 0.0f) // 아웃라인 두께
        strokeColor = type.getColor(R.styleable.OutlineTextView_out_line_text_view_stroke_color, -0x1) // 아웃라인 컬러
    }

    override fun onDraw(canvas: Canvas) {
        if (stroke) {
            val states = textColors
            paint.style = Paint.Style.STROKE
            paint.strokeWidth = strokeWidth
            setTextColor(strokeColor)
            super.onDraw(canvas)
            paint.style = Paint.Style.FILL
            setTextColor(states)
        }
        super.onDraw(canvas)
    }

}&lt;/code&gt;&lt;/pre&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://haruple.tistory.com/269</guid>
      <comments>https://haruple.tistory.com/269#entry269comment</comments>
      <pubDate>Wed, 7 Jun 2023 21:30:32 +0900</pubDate>
    </item>
    <item>
      <title>[Android | Kotlin] 프로그래스바 커스텀 하기</title>
      <link>https://haruple.tistory.com/268</link>
      <description>&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;일반적으로 ProgressBar는 로딩이 얼마나 진행되었는지를 표시하거나 서버와의 통신이 지연되고 있을 때 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 이렇게 서버와의 통신 대신 유저의 경험치를 나타내는 방식을 프로그래스바를 이용해 구현했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uCw85/btsiuKsxbUT/n8l0prwwpO1Dq9ETqxfnLK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uCw85/btsiuKsxbUT/n8l0prwwpO1Dq9ETqxfnLK/img.png&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;2289&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uCw85/btsiuKsxbUT/n8l0prwwpO1Dq9ETqxfnLK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuCw85%2FbtsiuKsxbUT%2Fn8l0prwwpO1Dq9ETqxfnLK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;2289&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KiLhP/btsis0JHseC/6PknEU3a3GA4OXvQXBad0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KiLhP/btsis0JHseC/6PknEU3a3GA4OXvQXBad0k/img.png&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;2289&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KiLhP/btsis0JHseC/6PknEU3a3GA4OXvQXBad0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKiLhP%2Fbtsis0JHseC%2F6PknEU3a3GA4OXvQXBad0k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;840&quot; height=&quot;2289&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;먼저 XML 코드에 ProgressBar UI를 만들어줍니다.&lt;/p&gt;
&lt;pre class=&quot;routeros&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;&amp;lt;ProgressBar
    android:id=&quot;@+id/progress_bar_exp&quot;
    android:max=&quot;100&quot;
    tools:progress=&quot;50&quot;
    style=&quot;@style/Widget.AppCompat.ProgressBar.Horizontal&quot;
    android:progressDrawable=&quot;@drawable/progress_bar_exp&quot;
    android:layout_width=&quot;0dp&quot;
    android:layout_height=&quot;15dp&quot;
    app:layout_constraintTop_toTopOf=&quot;@id/tv_exp_title&quot;
    app:layout_constraintBottom_toBottomOf=&quot;@id/tv_exp_title&quot;
    app:layout_constraintStart_toEndOf=&quot;@id/tv_exp_title&quot;
    app:layout_constraintEnd_toEndOf=&quot;parent&quot;
    android:layout_marginEnd=&quot;30dp&quot;
    android:layout_marginStart=&quot;5dp&quot;
    /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 가로 그래프 형식으로 그려진 프로그래스바를 만들기 위해 &lt;b&gt;ProgressBar.Horizontal&lt;/b&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;progressDrawble에 사용된&lt;b&gt; progress_bar_exp.xml&lt;/b&gt; 을 만들어주어야합니다.&lt;/p&gt;
&lt;pre class=&quot;xml&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;layer-list xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&amp;gt;
    &amp;lt;item android:id=&quot;@android:id/background&quot;&amp;gt;
        &amp;lt;shape&amp;gt;
            &amp;lt;corners android:radius=&quot;10dp&quot; /&amp;gt;
            &amp;lt;solid android:color=&quot;@color/grey_3&quot; /&amp;gt;
        &amp;lt;/shape&amp;gt;
    &amp;lt;/item&amp;gt;
    &amp;lt;item android:id=&quot;@android:id/secondaryProgress&quot;&amp;gt;
        &amp;lt;clip&amp;gt;
            &amp;lt;shape&amp;gt;
                &amp;lt;corners android:radius=&quot;10dp&quot; /&amp;gt;
                &amp;lt;solid android:color=&quot;#B2CCFF&quot; /&amp;gt;
            &amp;lt;/shape&amp;gt;
        &amp;lt;/clip&amp;gt;
    &amp;lt;/item&amp;gt;
    &amp;lt;item android:id=&quot;@android:id/progress&quot;&amp;gt;
        &amp;lt;clip&amp;gt;
            &amp;lt;shape&amp;gt;
                &amp;lt;corners android:radius=&quot;10dp&quot; /&amp;gt;
                &amp;lt;solid android:color=&quot;@color/light_yellow&quot; /&amp;gt;
            &amp;lt;/shape&amp;gt;
        &amp;lt;/clip&amp;gt;
    &amp;lt;/item&amp;gt;
&amp;lt;/layer-list&amp;gt;&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;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 저는 ProgressBar에 단순히 정지된 화면이 아니라 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;채워지는 애니메이션&lt;/b&gt;&lt;/span&gt;을 적용했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래처럼 &lt;b&gt;ObjectAnimator&lt;/b&gt;를 사용해 간단하게 progressBar 가 채워지는 효과를 적용할 수 있습니다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;ObjectAnimator.ofInt(binding.progressBarExp, &quot;progress&quot;, exp.toInt())
    .setDuration(500)
    .start()&lt;/code&gt;&lt;/pre&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;</description>
      <category>개발/Android</category>
      <category>progressbar</category>
      <category>프로그래스바</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/268</guid>
      <comments>https://haruple.tistory.com/268#entry268comment</comments>
      <pubDate>Tue, 6 Jun 2023 20:21:26 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시 Z플립5 유출 정보</title>
      <link>https://haruple.tistory.com/267</link>
      <description>&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;지난 폴드5 유출 정보에 이어 플립5의 유출 정보도 가져왔습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A5vVU/btsiuseB05S/IKKQnTPdURhYTpvpRcdtLK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A5vVU/btsiuseB05S/IKKQnTPdURhYTpvpRcdtLK/img.webp&quot; data-alt=&quot;이미지 출처:&amp;amp;amp;nbsp; Future / Alex Walker-Todd&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A5vVU/btsiuseB05S/IKKQnTPdURhYTpvpRcdtLK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA5vVU%2FbtsiuseB05S%2FIKKQnTPdURhYTpvpRcdtLK%2Fimg.webp&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; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;546&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지 출처:&amp;amp;nbsp; Future / Alex Walker-Todd&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;출시 날짜 및 가격&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;7월 26일에 언팩할 가능성이 있습니다.&lt;/li&gt;
&lt;li&gt;언팩 이후 즉시 출시가 아닌 8월 11일 출시로 예상됩니다.&lt;/li&gt;
&lt;li&gt;가격은 작년과 같이 999달러로 예상됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;디자인과 디스플레이&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;훨씬 더 큰 3.4인치 커버 스크린이 적용될 예정입니다.&lt;/li&gt;
&lt;li&gt;새로운 물방울 힌지 디자인이 적용될 수 있습니다.&lt;/li&gt;
&lt;li&gt;6.7인치 120Hz 폴더블 스크린을 예상하고 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mGNdr/btsiFMP4QrB/1lhy83SpdIOfZ2SWOBWZT1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mGNdr/btsiFMP4QrB/1lhy83SpdIOfZ2SWOBWZT1/img.webp&quot; data-alt=&quot;이미지 출처: Ice Universe/Twitter&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mGNdr/btsiFMP4QrB/1lhy83SpdIOfZ2SWOBWZT1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmGNdr%2FbtsiFMP4QrB%2F1lhy83SpdIOfZ2SWOBWZT1%2Fimg.webp&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; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;546&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;이미지 출처: Ice Universe/Twitter&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;카메라와 배터리&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;작년과 마찬가지로 12MP 카메라 두 개가 탑재될 가능성이 높습니다.&lt;/li&gt;
&lt;li&gt;새롭게 개선된 센서를 적용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;배터리는 3591mAh로 기존보다 더 작아질 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사양 및 특징&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스냅드래곤 8 Gen2와 12GB Ram이 탑재될 가능성이 높습니다&lt;/li&gt;
&lt;li&gt;최대 512GB의 스토리지가 제공됩니다.&lt;/li&gt;
&lt;li&gt;기존 폴드에서는 Dex가 지원되었었지만 플립에서는 지원되지 않았었습니다. 이제 삼성 Dex를 지원하여 PC처럼 사용할 수 있습니다.&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;&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;갤럭시 S 시리즈에서는 항상 현 세대에서 최상위급 카메라를 넣어주는데 Z 시리즈는 물론 폴더블 디스플레이 때문에 단가가 높긴 하겠지만 그래도 출고가 기준으로는 가장 비쌈에도 불구하고 이전 세대 정보의 카메라를 탑재하는게 아쉽네요..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제가 새로운 폴더블 시리즈를 구매할 때는 가장 최상위 카메라를 탑재해주면 좋겠습니다&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1686181717336&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;갤럭시Z폴드5 유출 정보&quot; data-og-description=&quot;안녕하세요, 하루플입니다. 기존 8월에 폴드/플립 시리즈의 언팩이 있었는데 이번에는 조기출시를 한다고 합니다. 아마도 아이폰이 공개되기 전에 최대한 격차를 많이 벌려두려고 하는 것 같습&quot; data-og-host=&quot;haruple.tistory.com&quot; data-og-source-url=&quot;https://haruple.tistory.com/266&quot; data-og-url=&quot;https://haruple.tistory.com/266&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/NUP6A/hySTIMVcX8/wJFvqD6V2JKnKZ8VtWH9Ok/img.jpg?width=800&amp;amp;height=451&amp;amp;face=0_0_800_451,https://scrap.kakaocdn.net/dn/cGFWP0/hySTOGk8hA/Fd2ZyMbyzMaoJAZ4FIbfw1/img.jpg?width=800&amp;amp;height=451&amp;amp;face=0_0_800_451,https://scrap.kakaocdn.net/dn/AFoys/hySVIYO9B2/1DeE5EvppdkTOGm833jXK0/img.jpg?width=1279&amp;amp;height=1279&amp;amp;face=0_0_1279_1279&quot;&gt;&lt;a href=&quot;https://haruple.tistory.com/266&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://haruple.tistory.com/266&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/NUP6A/hySTIMVcX8/wJFvqD6V2JKnKZ8VtWH9Ok/img.jpg?width=800&amp;amp;height=451&amp;amp;face=0_0_800_451,https://scrap.kakaocdn.net/dn/cGFWP0/hySTOGk8hA/Fd2ZyMbyzMaoJAZ4FIbfw1/img.jpg?width=800&amp;amp;height=451&amp;amp;face=0_0_800_451,https://scrap.kakaocdn.net/dn/AFoys/hySVIYO9B2/1DeE5EvppdkTOGm833jXK0/img.jpg?width=1279&amp;amp;height=1279&amp;amp;face=0_0_1279_1279');&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;갤럭시Z폴드5 유출 정보&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요, 하루플입니다. 기존 8월에 폴드/플립 시리즈의 언팩이 있었는데 이번에는 조기출시를 한다고 합니다. 아마도 아이폰이 공개되기 전에 최대한 격차를 많이 벌려두려고 하는 것 같습&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;haruple.tistory.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;</description>
      <category>일상/전자제품</category>
      <category>갤럭시Z플립5</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/267</guid>
      <comments>https://haruple.tistory.com/267#entry267comment</comments>
      <pubDate>Mon, 5 Jun 2023 19:35:25 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시Z폴드5 유출 정보</title>
      <link>https://haruple.tistory.com/266</link>
      <description>&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;기존 8월에 폴드/플립 시리즈의 언팩이 있었는데 이번에는 조기출시를 한다고 합니다.&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;현재까지 유출된 폴드5의 정보입니다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;548&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cE9bT8/btsiutkhwPZ/6yt0FcugJaN5xUXaUfKNO1/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cE9bT8/btsiutkhwPZ/6yt0FcugJaN5xUXaUfKNO1/img.webp&quot; data-alt=&quot;(이미지 출처 : Future / Lance Ulanoff)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cE9bT8/btsiutkhwPZ/6yt0FcugJaN5xUXaUfKNO1/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcE9bT8%2FbtsiutkhwPZ%2F6yt0FcugJaN5xUXaUfKNO1%2Fimg.webp&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; loading=&quot;lazy&quot; width=&quot;970&quot; height=&quot;548&quot; data-origin-width=&quot;970&quot; data-origin-height=&quot;548&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;(이미지 출처 : Future / Lance Ulanoff)&lt;/figcaption&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;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;출시 날짜 및 가격&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;7월 26일에 언팩할 가능성이 있습니다.&lt;/li&gt;
&lt;li&gt;언팩 이후 즉시 출시가 아닌 8월 11일 출시로 예상됩니다.&lt;/li&gt;
&lt;li&gt;Z폴드4와 동일한 가격으로 예상됩니다. (1799달러)&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;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;디자인과 디스플레이&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;새로운 물방울 힌지 디자인을 적용할 수 있습니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;휴대폰에&lt;span&gt; &lt;/span&gt;물방울&lt;span&gt; &lt;/span&gt;모양의&lt;span&gt; &lt;/span&gt;힌지가&lt;span&gt; &lt;/span&gt;적용되어&lt;span&gt; &lt;/span&gt;기기의&lt;span&gt; &lt;/span&gt;양면이&lt;span&gt; &lt;/span&gt;서로&lt;span&gt; &lt;/span&gt;완전히&lt;span&gt; &lt;/span&gt;평평하게&lt;span&gt; &lt;/span&gt;놓일&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있다는&lt;span&gt; &lt;/span&gt;소식도&lt;span&gt; &lt;/span&gt;들었습니다&lt;span&gt;. &lt;/span&gt;이는&lt;span&gt; &lt;/span&gt;이론적으로&lt;span&gt; &lt;/span&gt;폴더블폰의&lt;span&gt; &lt;/span&gt;내구성을&lt;span&gt; &lt;/span&gt;향상시킬&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있습니다&lt;span&gt;. &lt;/span&gt;이는&lt;span&gt; &lt;/span&gt;이후&lt;span&gt; &lt;/span&gt;두&lt;span&gt; &lt;/span&gt;번째&lt;span&gt; &lt;/span&gt;보고서에&lt;span&gt; &lt;/span&gt;의해&lt;span&gt; &lt;/span&gt;뒷받침되었는데&lt;span&gt;, &lt;/span&gt;이&lt;span&gt; &lt;/span&gt;보고서는&lt;span&gt; &lt;/span&gt;현재&lt;span&gt; &lt;/span&gt;모델과&lt;span&gt; &lt;/span&gt;마찬가지로&lt;span&gt; &lt;/span&gt;휴대&lt;span&gt; &lt;/span&gt;전화가&lt;span&gt; &lt;/span&gt;분명히&lt;span&gt; &lt;/span&gt;방수&lt;span&gt; &lt;/span&gt;기능이&lt;span&gt; &lt;/span&gt;있을&lt;span&gt; &lt;/span&gt;것이라고&lt;span&gt; &lt;/span&gt;덧붙였습니다&lt;span&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;시인성 향상을 위해 이전보다 더 밝은 화면이 적용됩니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;디자인은 대부분 Z폴드4와 비슷합니다.&lt;/span&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;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;갤럭시&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; Z &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;폴드&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 5&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;의&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;모습을&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;보여주는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;일련의&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;비공식&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;렌더링을&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;살펴본&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;결과&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이전에&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;출시된&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;삼성&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;갤럭시&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; Z &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;폴드&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 4&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;와&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;매우&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;흡사한&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;모습을&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;하고&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;있는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;것으로&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;보입니다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;. &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;렌더링&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;중&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;일부는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;조금&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;더&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;아래에서&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;확인할&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;수&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;있습니다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;휴대폰으로&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;추정되는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;케이스&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이미지도&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;유출되었는데&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;아래와&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;같은&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;디자인으로&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;보아&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;카메라&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;블록&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;외부로&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;카메라&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;플래시가&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;이동하는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;것이&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;주요&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;시각적&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;변화일&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;수&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;있습니다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;카메라와 배터리&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;50MP 메인 센서가 장착된 프리플 렌즈 후면 카메라&lt;/b&gt;&lt;br /&gt;한 소식통에 따르면 삼성 갤럭시 Z 폴드 5에는 50 MP 메인 센서가 장착된 트리플 렌즈 후면 카메라가 탑재될 것이라고 합니다. 다른 두 개의 센서는 1,200만 화소 초광각과 1,000만 화소 망원이며, 이는 갤럭시 Z 폴드 4와 정확히 일치하므로 카메라에 대한 업그레이드가 많지 않을 수 있습니다.두&lt;span&gt; &lt;/span&gt;번째&lt;span&gt; &lt;/span&gt;소식통은&lt;span&gt; &lt;/span&gt;이제&lt;span&gt; &lt;/span&gt;같은&lt;span&gt; &lt;/span&gt;말을&lt;span&gt; &lt;/span&gt;했고&lt;span&gt; &lt;/span&gt;세&lt;span&gt; &lt;/span&gt;번째&lt;span&gt; &lt;/span&gt;소식통은&lt;span&gt; 50 MP &lt;/span&gt;메인&lt;span&gt; &lt;/span&gt;센서&lt;span&gt;, 12 MP &lt;/span&gt;초광각&lt;span&gt; &lt;/span&gt;및&lt;span&gt; 10 MP &lt;/span&gt;망원이&lt;span&gt; &lt;/span&gt;포함될&lt;span&gt; &lt;/span&gt;것이라고&lt;span&gt; &lt;/span&gt;구체적으로&lt;span&gt; &lt;/span&gt;말했습니다&lt;span&gt;. &lt;/span&gt;그러나&lt;span&gt; &lt;/span&gt;사용되는&lt;span&gt; &lt;/span&gt;센서&lt;span&gt; &lt;/span&gt;중&lt;span&gt; &lt;/span&gt;하나&lt;span&gt; &lt;/span&gt;이상이&lt;span&gt; &lt;/span&gt;새로운&lt;span&gt; &lt;/span&gt;센서가&lt;span&gt; &lt;/span&gt;될&lt;span&gt; &lt;/span&gt;것이며&lt;span&gt;, &lt;/span&gt;이는&lt;span&gt; &lt;/span&gt;사진&lt;span&gt; &lt;/span&gt;품질이&lt;span&gt; &lt;/span&gt;여전히&lt;span&gt; &lt;/span&gt;크게&lt;span&gt; &lt;/span&gt;향상될&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있음을&lt;span&gt; &lt;/span&gt;의미할&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있다고&lt;span&gt; &lt;/span&gt;덧붙였습니다&lt;span&gt;.&lt;/span&gt;&lt;span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;언더 디스플레이 카메라가 개선될 수 있습니다.&lt;/b&gt;&lt;br /&gt;폴드&lt;span&gt; 5&lt;/span&gt;에는&lt;span&gt; &lt;/span&gt;셀카&lt;span&gt; &lt;/span&gt;촬영을&lt;span&gt; &lt;/span&gt;위한&lt;span&gt; &lt;/span&gt;개선된&lt;span&gt; &lt;/span&gt;언더&lt;span&gt; &lt;/span&gt;디스플레이&lt;span&gt; &lt;/span&gt;카메라가&lt;span&gt; &lt;/span&gt;탑재되며&lt;span&gt;, &lt;/span&gt;최대&lt;span&gt; 8K &lt;/span&gt;화질로&lt;span&gt; 30 fps&lt;/span&gt;의&lt;span&gt; &lt;/span&gt;동영상을&lt;span&gt; &lt;/span&gt;촬영할&lt;span&gt; &lt;/span&gt;수&lt;span&gt; &lt;/span&gt;있을&lt;span&gt; &lt;/span&gt;것이라는&lt;span&gt; &lt;/span&gt;소식도&lt;span&gt; &lt;/span&gt;들었습니다&lt;span&gt;.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;배터리의&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;경우&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;아직&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;어떤&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;크기가&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;될지는&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;알려지지&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;않았지만&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;, MyFixGuide&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;에서&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;본&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;인증&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;목록에&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;따르면&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;삼성은&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;아마도&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;상당히&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;느린&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; 25 W &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;충전을&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;고수할&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt; &lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;것입니다&lt;/span&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;.&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;사양 및 특징&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;스냅드래곤 8 Gen2와 12GB Ram이 탑재될 가능성이 높습니다&lt;/li&gt;
&lt;li&gt;최대 1TB의 스토리지가 제공됩니다.&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;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1686181765887&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;갤럭시 Z플립5 유출 정보&quot; data-og-description=&quot;안녕하세요, 하루플입니다. 지난 폴드5 유출 정보에 이어 플립5의 유출 정보도 가져왔습니다. 폴드는 지난 세대와 디자인이 거의 비슷하지만 플립의 디자인은 크게 바뀔 것으로 보입니다. 전면 &quot; data-og-host=&quot;haruple.tistory.com&quot; data-og-source-url=&quot;https://haruple.tistory.com/267&quot; data-og-url=&quot;https://haruple.tistory.com/267&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/H6f6K/hySVEvlLds/yw56A8m8AYdyO0aAXzPV9K/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/c95wnR/hySTJE4xaA/Ckyujgk9m8ScwCevuwC5qk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bQ60QD/hySVOdFbU2/KsVsLzGrpOSBpSvqgsKtLK/img.jpg?width=1279&amp;amp;height=1279&amp;amp;face=0_0_1279_1279&quot;&gt;&lt;a href=&quot;https://haruple.tistory.com/267&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://haruple.tistory.com/267&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/H6f6K/hySVEvlLds/yw56A8m8AYdyO0aAXzPV9K/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/c95wnR/hySTJE4xaA/Ckyujgk9m8ScwCevuwC5qk/img.jpg?width=800&amp;amp;height=450&amp;amp;face=0_0_800_450,https://scrap.kakaocdn.net/dn/bQ60QD/hySVOdFbU2/KsVsLzGrpOSBpSvqgsKtLK/img.jpg?width=1279&amp;amp;height=1279&amp;amp;face=0_0_1279_1279');&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;갤럭시 Z플립5 유출 정보&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요, 하루플입니다. 지난 폴드5 유출 정보에 이어 플립5의 유출 정보도 가져왔습니다. 폴드는 지난 세대와 디자인이 거의 비슷하지만 플립의 디자인은 크게 바뀔 것으로 보입니다. 전면&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;haruple.tistory.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;</description>
      <category>일상/전자제품</category>
      <category>갤럭시Z폴드5</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/266</guid>
      <comments>https://haruple.tistory.com/266#entry266comment</comments>
      <pubDate>Sun, 4 Jun 2023 22:58:30 +0900</pubDate>
    </item>
    <item>
      <title>[Android | Kotlin] Uri로 입력받은 이미지를 줄이는 방법</title>
      <link>https://haruple.tistory.com/265</link>
      <description>&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;스마트폰의 기본 카메라로 사진을 촬영하게 되면 최신 스마트폰의 경우 10~20MB의 용량을 차지하는 경우도 많습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 출시한 갤럭시 S23울트라의 경우 2억화소를 지원하게 되면서 30MB를 넘는 고용량의 사진을 촬영할 수 있게 되었습니다.&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;저같은 경우도 개인 앱 서비스를 개발하다보니 서버 비용에 한계가 있고 업로드 하는 속도도 최적화를 하기 위해서 이미지를 줄이는 방법을 고민했었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;2289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dlrcos/btsiyVteQas/ckeHMfrjepKFwnPkQiWCO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dlrcos/btsiyVteQas/ckeHMfrjepKFwnPkQiWCO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dlrcos/btsiyVteQas/ckeHMfrjepKFwnPkQiWCO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdlrcos%2FbtsiyVteQas%2FckeHMfrjepKFwnPkQiWCO0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;306&quot; height=&quot;2289&quot; data-origin-width=&quot;840&quot; data-origin-height=&quot;2289&quot;/&gt;&lt;/span&gt;&lt;/figure&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;Firebase 용량이 급속도로 차는 것을 확인했습니다..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이대로면 많은 유저가 사용하였을 때 엄청난 요금 폭탄을 맞을 수도 있습니다..&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;126&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qaxsC/btsiFMWNChy/REHNduGcWj2K22ZrfOShs0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qaxsC/btsiFMWNChy/REHNduGcWj2K22ZrfOShs0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qaxsC/btsiFMWNChy/REHNduGcWj2K22ZrfOShs0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqaxsC%2FbtsiFMWNChy%2FREHNduGcWj2K22ZrfOShs0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;573&quot; height=&quot;126&quot; data-origin-width=&quot;622&quot; data-origin-height=&quot;126&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버에 업로드된 사진 용량은 무려 한장당 10MB 입니다.&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;pre class=&quot;reasonml&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;private fun convertResizeImage(imageUri: Uri): Uri {
    val bitmap = MediaStore.Images.Media.getBitmap(requireContext().contentResolver, imageUri)
    val resizedBitmap = Bitmap.createScaledBitmap(bitmap, bitmap.width / 2, bitmap.height / 2, true)

    val byteArrayOutputStream = ByteArrayOutputStream()
    resizedBitmap.compress(Bitmap.CompressFormat.JPEG, 90, byteArrayOutputStream)

    val tempFile = File.createTempFile(&quot;resized_image&quot;, &quot;.jpg&quot;, requireContext().cacheDir)
    val fileOutputStream = FileOutputStream(tempFile)
    fileOutputStream.write(byteArrayOutputStream.toByteArray())
    fileOutputStream.close()

    return Uri.fromFile(tempFile)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 이미지 Uri를 Bitmab 형식으로 변환합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 변환한 Bitmap 이미지의 사진 사이즈를 지정합니다. 저는 1/2 사이즈로 줄여도 앱 사용상 품질에 문제가 없었기 때문에 가로 세로 사이즈를 절반식 줄였습니다. 결과적으로 넓이는 4배가 줄어들게 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 이미지 압축 품질을 설정합니다. 저는 기존의 90%로 압축하도록 하였습니다. (10% 압축률 설정)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 임시폴더인 tempFile에 방금 만든 비트맵 이미지를 저장합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. tempFile에 있는 이미지의 Uri를 리턴합니다.&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;4번에서 저는 tempFile을 사용했는데 일반적으로 사용하는 방법인 비트맵 이미지를 File에 그대로 저장해버리면 갤러리에 필요없는 이미지가 하나 더 생겨버리게 됩니다. 그리고 해당 이미지의 Uri를 가져오게 되는 방식으로 작동하게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 굳이 이미지를 하나 더 갤러리에 생성할 필요가 없기 때문에 temp에 저장하는 형식으로 개발하였습니다.&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;해당 방식으로 이미지의 사이즈를 줄이고 난 후 Firebase에 업로드 된 사진 용량을 확인해보았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;122&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgBhah/btsiBMQm6Bv/dDr7yqnrrObXQEl4uUk3g1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgBhah/btsiBMQm6Bv/dDr7yqnrrObXQEl4uUk3g1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgBhah/btsiBMQm6Bv/dDr7yqnrrObXQEl4uUk3g1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgBhah%2FbtsiBMQm6Bv%2FdDr7yqnrrObXQEl4uUk3g1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;423&quot; height=&quot;122&quot; data-origin-width=&quot;846&quot; data-origin-height=&quot;122&quot;/&gt;&lt;/span&gt;&lt;/figure&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;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/265</guid>
      <comments>https://haruple.tistory.com/265#entry265comment</comments>
      <pubDate>Sun, 4 Jun 2023 22:40:39 +0900</pubDate>
    </item>
    <item>
      <title>심플 소프트웨어 : 소프트웨어 이해하기</title>
      <link>https://haruple.tistory.com/264</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;6장 소프트웨어 이해하기&lt;br /&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;[컴퓨터란 무엇인가?]&lt;/b&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;li&gt;인간이 설정한 목표를 달성하기 위해 일련의 기호 명령을 수행하고 데이터를 비교할 수 있는 모든 물질이 컴퓨터다.&lt;/li&gt;
&lt;li&gt;컴퓨터는 데이터를 비교할 수 있다. 이러한 부분이 인간의 입력을 받는 다른 기계와 구분된다.&lt;/li&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;&lt;b&gt;&lt;br /&gt;[소프트웨어의 구성 요소 구조, 동작, 결과]&lt;/b&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;li&gt;결과부터 거꾸로 작업하는 사람도 있다. 그래도 상관없다. 단, 구조나 저으이된 결과 없이 동작을 수행하려면 혼란스러울 가능성이 높기 때문에 동작부터 시작하는 방법은 권하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;[소프트웨어 개정판 : ISAR 구별하기]&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;구조 , 동작, 결과라는 세 요소를 줄여서 SAR 이라고 부르고, 여기에 입력도 포함시킬 경우 ISAR 이라고 부른다.&lt;/li&gt;
&lt;li&gt;MVC는 소프트웨어를 설계하는 패턴이다. SAR은 모든 소프트웨어에 나타나는 세가지 요소를 가리킨다.&lt;/li&gt;
&lt;/ul&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;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;li&gt;데이터베이스를 쓰는 프로그램이라면 데이터베이스의 구조 계획 (단, 데이터베이스에 있는 실제 데이터는 구조에 속하지 않는다는 점을 주의해야한다.)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;구조는 프로그램 구성 요소 혹은 프로그램의 일부 조각이라고 볼 수 이싿. 함수 이름이나 자료형, 변수 이름과 자료형 클래스 같은 것은 모두 구조다.&lt;/li&gt;
&lt;/ul&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;전체 프로그램의 동작은 매우 이해하기 쉽다. 세무 프로그램은 &amp;lsquo;세금 정산&amp;rsquo;을 하고 계산기는 &amp;lsquo;계산을 한다&amp;rsquo;.&lt;/li&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;결과&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;li&gt;프로그램이 생산하는 것이라면 모두 결과다.&lt;/li&gt;
&lt;li&gt;SAR은 거대한 앱부터 한 줄짜리 스크립트까지 어떤 프로그래밍에든 적용할 수 있는 개념이다. 코드를 작성할 때마다 깊게 생각해야하는 개념은 아니지만 프로그램을 분석하고 이해하는데 도움이 된다. 특히 설계 개선 방법을 고민할 때 큰 도움이 될 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[지식으로서의 소프트웨어]&lt;/b&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;&lt;br /&gt;&lt;b&gt;[기술의 목적]&lt;/b&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;li&gt;이 법칙은 기술의 발전이 선인지 악인지를 밝히는 데도 유용하다. 기술의 발전을 생각하면 때로 심경이 엇갈린다. 기술이란 본질적으로 선하거나 악한 것이 아니다. 하지만 인간의 문제를 해결하려고 할 때 악하게 작용하고, 물질 세계의 문제를 해결하려고 할 때 선하게 작용하는 경향이 있다.&lt;/li&gt;
&lt;li&gt;기술은 우리를 더 나은 인간으로 만들지는 못하지만 우리가 사는 세상이 조금 더 나아지게 만들 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[단순성과 보안]&lt;/b&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;소프트웨어를 안전하게 지키겠다고 소프트웨어 앞에 소규모 군대를 배치할 필요는 없다. 별도의 보호 장치가 필요 없도록 &amp;lsquo;입구&amp;rsquo;수를 줄이고, 그 입구를 간결하고 단순하게 만들어 부당하게 악용하지 못하게 하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[테스트 주도 개발과 관찰 주기]&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;최근에 테스트를 먼저 작성한 뒤에 코드를 작성하는 개발 시스템 TDD의 특성과 작용에 관해 흥미로운 논의가 있었다. 결정을 내리기 전에 관찰부터 해야한다는 것이었다. 소프트웨어 수명 전반에 걸쳐 무언가 관찰해야한다. 이 원칙은 소프트웨어 개발 주기에 광범위하게 적용된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;관찰 &amp;rarr; 결정 &amp;rarr; 실행 (이 주기의 반복)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;ODA 사례 : TDD를 쓸 때는 아래 주기를 따른다
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;문제를 본다 (관찰)&lt;/li&gt;
&lt;li&gt;문제를 해결하기로 한다 (결정)&lt;/li&gt;
&lt;li&gt;테스트를 작성한다 (실행)&lt;/li&gt;
&lt;li&gt;테스트를 보고 API가 괜찮은지 확인한다 (관찰)&lt;/li&gt;
&lt;li&gt;괜찮지 않다면 수정 방법을 정하고 (결정) 테스트를 수정한 후 (실행) API가 괜찮아 보일 때까지 관찰 &amp;rarr; 결정 &amp;rarr; 실행을 반복한다.&lt;/li&gt;
&lt;li&gt;API가 괜찮다면 테스트를 실행하고 통과하는지 본다 (관찰)&lt;/li&gt;
&lt;li&gt;코드를 작성한다 (실행)&lt;/li&gt;
&lt;li&gt;테스트를 실행하여 통과하는지 확인한다 (관찰)&lt;/li&gt;
&lt;li&gt;통과하지 못하면 수정 방법을 정하고 (결정) 코드를 작성하고 (실행) 테스트를 통과하는지 확인한다 (관찰)&lt;/li&gt;
&lt;li&gt;이런 방식으로 다음 작업을 이어간다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[테스트 철학]&lt;/b&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;li&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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;E2E 테스트
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;E2E 테스트는 시스템 로직을 관통하는 하나의 경로를 완료하는 방식으로 진행하는 테스트다. 전체 시스템을 동작시키고 사용자가 입력하는 시작 지점에서 몇 가지 동작을 실행한 후 시스템이 생산하는 결과를 확인하는 것이다.&lt;/li&gt;
&lt;li&gt;이 테스트는 테스트가 많이 부족한 초기에 임시방편으로 쓰기 좋다. 전체 시스템을 조립한 후에 제대로 동작하는지 확인하는 용도로 써도 좋다. 하지만 장기적으로 볼 때 복잡한 시스템에 대해 충분한 지식을 얻을 수 있는 테스트 방식은 아니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;통합 테스트만으로 시스템을 테스트 하는건 적절하지 않다. 컴포넌트의 인터렉션 만으로 전체 시스템을 분석하려면 시스템 작동 방식 전반에 대해 이해하기까지 엄청난 수의 인터랙션을 테스트해야 하기 때문이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;이론적으로는 시스템에 있는 모든 컴포넌트의 동작이 문서에 잘 정의되어 있으면 각 컴포넌트가 문서에 나온 대로 동작하는지 테스트하기만 해도 시스템 전체의 동작을 테스트한 셈이 된다.&lt;/li&gt;
&lt;li&gt;당연한 말이지만 단위 테스트는 시스템 컴포넌트가 합리적으로 잘 분리 되어있고 각 컴포넌트의 동작을 완전히 정의할 수 있을 정도로 단순할 때 가장 큰 효과를 낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/264</guid>
      <comments>https://haruple.tistory.com/264#entry264comment</comments>
      <pubDate>Mon, 29 May 2023 13:26:42 +0900</pubDate>
    </item>
    <item>
      <title>심플 소프트웨어 : 엔지니어링 팀에서 일하기</title>
      <link>https://haruple.tistory.com/263</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;5부 엔지니어링 팀에서 일하기&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;br /&gt;[개발자 생산성 측정하기]&lt;/b&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;li&gt;사실 생산성 측정은 엄청나게 큰 가치를 지닌다. 생산성을 측정하면 준제가 발생한 영역, 생산성이 개선된 영역을 정확히 가려내어 생산성이 좋아진 이들에게 보상을 할 수 있다. 그리고 개발자 생산성을 개선하기 위해 노력하면 이외에도 많은 소득이 따른다.&lt;/li&gt;
&lt;li&gt;그러나 프로그래밍 분야는 다른 직군과 다르다. 생산성을 제조업 분야의 생산성을 측정하는 방식으로 측정할 수는 없다.&lt;/li&gt;
&lt;li&gt;LOC(lines of code)를 생산성의 기준으로 삼겠다는 시도가 꾸준히 존재했다. 그러나 잘못되었다. 컴퓨터 프로그래머는 목수처럼 직업이 아니라 기술이다. 기술 사용 빈도는 생산성을 측정하는 기준이 될 수 없다. 생산성을 확인하려면 그 기술로 생산한 제품을 측정해야한다.&lt;/li&gt;
&lt;li&gt;가장 먼저 프로그램이 사용자에게 어떤 가치를 제공하는지부터 알아내야한다.&lt;/li&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;&lt;b&gt;&lt;br /&gt;[소프트웨어 회사에서 코드 복잡성을 다루는 법]&lt;/b&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;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;li&gt;문제를 해결하는 과정에서 문제에 대한 이해가 더 깊어지는 측면도 있다. 하지만 관리자는 문제를 직접 해결하지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코드 복잡성 관련 문제 대부분은 각 프로그래머가 섬세하게 작업해야 하는 소규모 프로젝트로 해결해야 한다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;1단계 : 문제 목록&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;2단계 : 회의&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;팀 회의를 열고 코드베이스에 접속할 수 있는 컴퓨터와 각자 만든 목록을 가져오게 한다. 회의의 규모는 6~7명 정도가 적당하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;3단계 : 버그 리포트&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;4단계 : 우선순위 선정&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;5단계 : 과제&lt;/b&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;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;6단계 : 계획&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 버그를 정리한 후 언제 고칠지 정해야 한다. 일반적으로 개발자 각자가 사진의 일반적인 업무를 하는 중간에 코드 품질 문제도 정기적으로 손보게 하는게 좋다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;[리팩토링 할때는 기능에 주목하라]&lt;/b&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;li&gt;리팩토링을 위한 리팩토링이란 현재 작업 중인 코드와 아무 상관없는 코드의 한 부분을 보다가 이 부분 설계가 마음에 들지 않는데? 라며 시스템 기능과 전혀 상관없는 코드 일부를 이리저리 옮겨보는 걸 말한다.&lt;/li&gt;
&lt;li&gt;복잡한 코드베이스를 정리하는 핵심 원칙은 항상 기능을 위해 리팩토링 하라는 것이다.&lt;/li&gt;
&lt;li&gt;일단 시간이 지날수록 시스템이 더 나빠지지 않도 더 나아지는 상태로 만드는걸 첫번째 목표로 삼아라.&lt;/li&gt;
&lt;li&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;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;b&gt;[간략하게 살펴보는 오픈소스 커뮤니티]&lt;/b&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;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;li&gt;꾸준히 기여할 수 있는 기여자 확보하기&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;아주 친절한 대도로 눈에 띄게 고마워하라.&lt;/li&gt;
&lt;li&gt;사적으로 부정적인 감정을 품지 마라&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;기여 방법을 환벽하고 정화하게 설명하는 간단한 문서를 만들어두어라.&lt;/li&gt;
&lt;li&gt;문서를 쉽게 찾을 수 있게 하라.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/263</guid>
      <comments>https://haruple.tistory.com/263#entry263comment</comments>
      <pubDate>Sun, 28 May 2023 12:10:34 +0900</pubDate>
    </item>
    <item>
      <title>심플 소프트웨어 : 프로그래머를 위한 원칙</title>
      <link>https://haruple.tistory.com/262</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;1부 프로그래머를 위한 원칙&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;li&gt;올바른 방법을 두고 논쟁이 벌어지면 종종 논의가 산으로 가기도 한다. 이럴 때는 작업중인 분야의 기본 법칙을 이해하고 있는 시니어 엔지니어를 선별하고 기존 논의를 검토하게 하고 표준적이고 타당한 엔지니어링 절차에 따라 올바른 방법을 정하게 하는게 좋다.&lt;/li&gt;
&lt;li&gt;능력자 프로그래머는 평범한 프로그래머보다 자신이 하는 일을 훨씬 더 잘 이해하고 있다. 뛰어난 프로그래머가 되고 싶다면 자신이 하는 일을 제대로 이해하라.&lt;/li&gt;
&lt;li&gt;어느 분야든 기본을 제대로 이해해야 그다음 수준도 쉽게 배운다. 그렇게 한 단계씩 올라가야 한다. 최고로 복잡한 수준에 도달한 후 다시 기초단계를 살펴보면 맨 밑바닥에는 여전히 알아야 할 게 엄청 많다는걸 깨닫는다.&lt;/li&gt;
&lt;li&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;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2부 소프트웨어 복잡성과 원인&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;[복잡성을 키우는 방법 : API 분리]&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API는 &amp;lsquo;언제든 우리가 알려준 대로 우리 프로그램와 안전하고 정확하게 인터랙션 할 수 있다&amp;rsquo;라는 약속이다.&lt;/li&gt;
&lt;li&gt;개발자 입장에서는 오래된 API를 계속 유지보수 하는게 괴로울 수 있다. 이 문제를 피하는 가장 좋은 방법은 나쁜 API를 공개하지 않는 것이다.&lt;/li&gt;
&lt;li&gt;예전 API를 그대로 유지하는 대신 최신 API에 접근할 다른 방법을 제공하는 것도 사용자 입장에서는 괜찮다.&lt;/li&gt;
&lt;li&gt;출시 전에 실제 API가 어떻게 작동해야 할지 합리적인 조치를 취한다는게 핵심이다. 그리고 일단 공개했다면 API를 망가뜨리지 마라.&lt;/li&gt;
&lt;/ul&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;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;/li&gt;
&lt;li&gt;하지만 너무 복잡한 코드를 만들어서 아무도 이해할 수 없다면 다른 프로젝트로 자리를 옮기고 싶어도 유지보수가 불가능 하기 때문에 옮길 수 없을 것이다.&lt;/li&gt;
&lt;li&gt;복잡성은 감옥이고 단순성은 자유다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;3부 단순성과 소프트웨어 설계&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;li&gt;시스템이 복잡해질 수록 미래의 아주 작은 부분조차 정확하게 예측할 수 없다. 시스템이 단순해질수록 먼 미래까지 정확하게 예측할 수 있다. 그래서 시스템을 단순하게 유지하는게 최선이다. 목표를 유연하게 혹은 포괄적으로 처럼 추상적으로 잡지말고 &amp;lsquo;쉽게 이해하고 수정할 수 있게&amp;rsquo; 처럼 구체적으로 잡아야한다.&lt;/li&gt;
&lt;li&gt;엄격한 앱일 수록 더 단순하게 작성할 수 있다. 하지만 엄격한 프로그램은 대체로 실용성이 떨어진다.&lt;/li&gt;
&lt;li&gt;원칙적으로는 개발자가 코드 일부를 수정한 후에 코드의 다른 부분까지 그와 비슷하거나 똑같은 방식으로 작동하도록 수정할 필요가 없어야 한다.&lt;/li&gt;
&lt;li&gt;하나로 통합해야하는 구현체가 많을 때는 한 번에 통합하는 구현체를 두 개로 제한하는 방식으로 점진적 리팩토링을 할 수 있다.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;4부 디버깅&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&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;/li&gt;
&lt;li&gt;프로그래머가 의도한 방식에 따라 의도한 동작을 프로그램이 정확히 수행하는데도 사용자의 기대에 못미친다면 새로운 기능이 필요하다. 이것이 &amp;lsquo;기능&amp;rsquo;과 &amp;lsquo;버그&amp;rsquo;의 차이다.&lt;/li&gt;
&lt;li&gt;버그는 보통 복잡성을 줄이지 못할 때 발생한다. 또 그보다는 드물지만 간단한 대상을 잘못 이해했을 때도 발생한다.&lt;/li&gt;
&lt;li&gt;복잡성과 이해도는 매우 밀접하게 연관되어 있다. 미래에 내가 작성한 코드를 접할 프로그래머가 코드를 이해할 수 있을지, 혹은 쉽게 이해할 수 있을지는 우리도 일부 책임져야 할 문제이다.&lt;/li&gt;
&lt;li&gt;프로그래머라면 프로그래밍과 해당 언어에 대한 기본적인 이해를 갖춘 상태에서 미래에 자신의 코드를 볼 다른 프로그래머가 쉽게 알아볼 수 있는 코드를 쓰겠다는 책임감을 지녀야 한다.
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;코드가 단순할수록 버그가 줄어들 것이다.&lt;/li&gt;
&lt;li&gt;프로그램의 모든 것이 단순해지도록 늘 노력하라.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;소프트웨어 회사의 코드베이스가 관리할 수 없는 지경에 이르는 이유는 문제가 제대로 해결될 때까지 손보지 않아서다. 그래서 소프트웨어 설계를 잘 이해해야하고, 충분한 인력을 동원해서 문제가 다시는 재발하지 않을때까지 제대로 처리해야한다.&lt;/li&gt;
&lt;li&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;/li&gt;
&lt;li&gt;디버깅은 크게 다음 4가지로 볼 수 있다.
&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;li&gt;문제를 일은키는 원인이 무엇인지 알아낼 때까지 데이터를 살펴본다.&lt;/li&gt;
&lt;li&gt;증상이 아닌 원인을 고친다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/262</guid>
      <comments>https://haruple.tistory.com/262#entry262comment</comments>
      <pubDate>Sat, 27 May 2023 16:34:38 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] 8장 효율적인 컬렉션 처리</title>
      <link>https://haruple.tistory.com/261</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;8장 효율적인 컬렉션 처리&lt;/b&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;안드로이드에서도 RecyclerView, ListView 등의 컬렉션을 사용하지 않은 앱은 상상하기 어렵다.&lt;/li&gt;
&lt;li&gt;컬렉션 처리 최적화는 생각보다 어렵지만 굉장히 중요하다. 컬렉션 처리가 성능에 큰 문제를 일으키는 경우도 많다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;하나 이상의 처리 단계를 가진 경우에는 시퀀스를 사용하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Iterable와 Sequence는 정의가 거의 동일하므로 차이를 잊는경우가 많다. 하지만 완전히 다른 목적으로 설계되었기 때문에 완전히 다른 형태로 동작한다. 무엇보다 시퀀스는 lazy로 처리된다.&lt;/li&gt;
&lt;li&gt;최종적인 계산은 toList, count등의 최종 연산이 이루어질 때 수행된다.&lt;/li&gt;
&lt;li&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;li&gt;무한 시퀀스 형태로 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;각각의 단계에서 컬렉션을 만들어 내지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;무거운 객체나 규모가 큰 컬렉션을 여러 단계에 걸쳐서 처리할 때는 시퀀스를 사용하는 것이 좋다. 또한 시퀀스 처리는 Kotlin Sequence Debugger 플러그인을 활용해서 처리 단계를 시각적으로 확인할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;컬렉션 처리 단계 수를 제한하라.&lt;/b&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;li&gt;사실 컬렉션 처리와 관련해서 비효율적인 코드를 작성하는 이유는 그것이 필요엇다고 생각해서가 아니라 어떤 메서드가 있는지 몰라서인 경우가 많다. 따라서 어떤 메서드가 있는지 확인해보는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;성능이 중요한 부분에서는 기본 자료형 배열을 사용하라&lt;/b&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;그런데 코틀린에서 List 와 Set 등의 컬렉션은 제네릭타입이다. 제네릭 타입에는 기본 자료형을 사용할 수 없으므로 래핑된 타입을 사용해야한다.&lt;/li&gt;
&lt;li&gt;하지만 성능이 중요한 경우라면 IntArray와 같이 기본 자료형을 활용하는 배열을 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;mutable 컬렉션 사용을 고려하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;imutable 컬렉션 보다 mutable 컬렉션이 좋은 점은 성능적인 측면에서 더 빠르다는 것이다. immutable 컬렉션에 요소를 추가하려면 새로운 컬렉션을 만들면서 여기에 요소를 추가해야한다.&lt;/li&gt;
&lt;li&gt;컬렉션을 복제하는 처리는 비용이 굉장히 많이 드는 처리이다.&lt;/li&gt;
&lt;li&gt;그래서 이러한 복제 처리를 하지 않는 mutable 컬렉션이 성능적 관점에서 좋다.&lt;/li&gt;
&lt;li&gt;immutable 컬렉션은 안전하다는 측면에서 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/261</guid>
      <comments>https://haruple.tistory.com/261#entry261comment</comments>
      <pubDate>Sun, 30 Apr 2023 13:48:52 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] 7장 비용줄이기</title>
      <link>https://haruple.tistory.com/260</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;7장 비용줄이기&lt;/b&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;&lt;b&gt;불필요한 객체 생성을 피하라&lt;/b&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;예를 들어 JVM에서 같은 문자열을 처리하는 코드가 여러개 있으면 기존의 문자열을 재사용한다.&lt;/li&gt;
&lt;li&gt;매 순간 객체를 생성하지 않고 객체를 재사용하는 간단한 방법은 객체 선언을 사용하는 것이다(싱글톤).&lt;/li&gt;
&lt;li&gt;캐시를 사용하는 팩토리 함수로도 객체를 재사용할 수 있다.&lt;/li&gt;
&lt;li&gt;팩토리 함수는 항상 같은 객체를 리턴하게 만들 수 있다. 값이 한번 계산되면 값을 즉시 구해올 수 있다. 하지만 캐시를 위한 Map을 저장해야 하므로 더 많은 메모리를 사용한다.&lt;/li&gt;
&lt;li&gt;캐시는 언제나 메모리와 성능의 트레이드 오프가 발생하므로, 캐시를 잘 설계하는 것은 쉽지 않다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;지연 초기화&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;무거운 클래스를 만들 때는 지연되게 만드는 것이 좋을 때가 있다. 예를 들어 A클래스에 B, C, D라는 무거운 인스턴스가 필요하다고 가성해보면 한번에 모두 생성하면 A 객체를 생성하는 과정이 굉장히 무거워질 것이다. 내부의 인스턴스를 지연 초기화 하면 A객체를 생성하는 과정을 가볍게 만들 수 있다.&lt;/li&gt;
&lt;li&gt;하지만 단점도 있다. 무거운 객체를 가졌지만 메서드의 호출은 빨라야할 수 있다. 따라서 지연 초기화는 상황에 맞게 사용해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;함수타입 파라미터를 갖는 함수에 inline 한정자를 붙여라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코틀린 표준 라이브러리의 고차 함수를 살펴보면 대부분 inline 한정자가 붙어 있는 것을 볼 수 있다. inline한정의 역할은 컴파일 시점에 &amp;lsquo;함수를 호출하는 부분&amp;rsquo;을 &amp;lsquo;함수의 본문&amp;rsquo;으로 대체하는 것이다.&lt;/li&gt;
&lt;li&gt;inline 한정자를 사용했을 때 장점
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입 아규먼트에 reified 한정자를 붙여서 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;함수 타입 파라미터를 가진 함수가 훨씬 빠르게 동작한다.&lt;/li&gt;
&lt;li&gt;비지역 리턴을 사용할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;모든 함수는 inline 한정자를 붙이면 조금 더 빠르게 동작한다. 함수 호출과 리턴을 위해 점프하는 과정과 백스택을 추적하는 과정이 없기 때문이다.&lt;/li&gt;
&lt;li&gt;하지만 함수 파라티터를 가지지 않는 함수에서는 이러한 차이가 큰 성능차이를 발생시키지 않는다. 그래서 간단한 함수에 inline 한정자를 붙이면 인텔리제이가 경고를 표시한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;inline 한정자는 굉장히 유용한 한정자이지만 모든 곳에 사용할 수가 없다. 재귀적으로 사용하면 무한하게 대체되는 문제가 발생한다. 이러한 문제는 인텔리제이가 오류로 잡지 못하므로 굉장히 위험하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;인라인 클래스의 사용을 고려하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;인라인으로 만들 수 있는 것은 함수뿐만이 아니다. 하ㅔ나의 값을 보유하는 객체도 inline으로 만들 수 있다. 기본 생성자 프로퍼티가 하나인 클래스 앞에 inline을 붙이면 해당 객체를 사용하는 위치가 모두 해당 프로퍼티로 교체된다.&lt;/li&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;&lt;b&gt;더이상 사용하지 않는 객체의 레퍼런스를 제거하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메모리 관리를 자동으로 해주는 프로그래밍 언어에 익숙한 개발자는 객체 해제를 따로 생각하지 않는다. 그렇다고 메모리 관리를 완전히 무시해버리면 메모리 누수가 발생해서 상황에 따라 OutOfMemoryError 가 발생하기도 한다.&lt;/li&gt;
&lt;li&gt;따라서 &amp;lsquo;더 이상 사용하지 않는 객체의 레퍼런스를 유지하면 안된다&amp;rsquo; 라는 규칙 정도는 지켜주는 것이 좋다.&lt;/li&gt;
&lt;li&gt;Activity를 여러 곳에서 자유롭게 접근하기 위해 companion 프로퍼티에 이를 할당해 두는 경우가 있는데 가비지 컬렉터가 해당 객체에 대한 메모리 해제를 할 수 없어서 굉장히 큰 메모리 누수가 발생하게 된다.&lt;/li&gt;
&lt;li&gt;initialize를 null로 설정하기만 하면 가비지 컬렉터가 이를 처리할 수 있다. 하지만 거의 사용되지 않는 객체까지 이런 것을 신경 쓰는 것은 오히려 좋지 않을 수도 있다.&lt;/li&gt;
&lt;li&gt;쓸데없는 최적화가 모든 악의 근원이라는 말도 있지만 오브젝트에 null을 설정하는 것은 그렇게 어려운 일이 아니므로 무조건 하는 것이 좋다.&lt;/li&gt;
&lt;li&gt;특히 많은 변수를 캡처할 수 있는 함수 타입, Any 타입 또는 제네릭 타입과 같이 미지의 클래스일 때는 이러한 처리가 중요하다.&lt;/li&gt;
&lt;li&gt;사실 객체를 수동으로 해제해야 하는 경우는 굉장히 드물다. 일반적으로 스코프를 벗어나면서 어떤 객체를 가리키는 레퍼런스가 제거될 때 객체가 자동으로 제거된다.&lt;/li&gt;
&lt;li&gt;따라서 메모리 문제를 피하는 가장 좋은 방법은 변수를 지역 스코프에 정의하고, companion에 큰 데이터를 저장하지 않는 것이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/260</guid>
      <comments>https://haruple.tistory.com/260#entry260comment</comments>
      <pubDate>Sun, 30 Apr 2023 13:48:12 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] hashCode의 규약을 지켜라</title>
      <link>https://haruple.tistory.com/259</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;sealed한정자&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;sealed한정자는 외부 파일에서 서브 클래스를 만드는 행위 자체를 모두 제한한다. 외부에서 추가적인 서브클래스를 만들 수 없으므로 타입이 추가되지 않을 거라는게 보장된다.&lt;/li&gt;
&lt;li&gt;따라서 when 구문에서 else 처리를 하지 않아도 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;equals를 직접 구현해야 하는 경우&lt;/b&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;li&gt;data 한정자를 붙이는 것을 원하지 않거나, 비교해야하는 프로퍼티가 기본 생성자에 없는 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;hashCode의 규약을 지켜라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;오버라이드 할 수 있는 Any메서드로 hashCode가 있다. hashCode 함수는 수많은 컬렉션과 알고리즘에 사용되는 자료 구조인 해시 테이블을 구축할 때 사용됩니다.&lt;/li&gt;
&lt;li&gt;아주 긴 배열에서 요소가 포함되어 있는지 확인할 때 선형으로 비교하면 꽤 오랜 시간이 필요할 것이다. 성능을 좋게 만드는 해결 방법이 해시 테이블이다.&lt;/li&gt;
&lt;li&gt;해시테이블은 각 요소에 숫자를 할당하는 함수가 필요하다. 이 함수를 &amp;lsquo;해시 함수&amp;rsquo;라고 부르며 같은 요소라면 항상 같은 숫자를 리턴한다.&lt;/li&gt;
&lt;li&gt;해시코드의 규약
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;어떤 객체를 변경하지 않았다면 hashCode는 여러 번 호출해도 그 결과가 항상 같아야 한다.&lt;/li&gt;
&lt;li&gt;equals메서드의 실행 결과로 두 객체가 같다고 나온다면 hashCode 메서드의 호출 결과도 같다고 나와야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코틀린은 equals 구현을 오버라이드 할 때 hashCode도 함께 오버라이드 하는 것을 추천한다. 같은 요소는 반드시 같은 해시코드를 가져야 하기 때문이다.&lt;/li&gt;
&lt;li&gt;equals를 따로 정의했다면 반드시 hashCode도 함께 정의해 주어야 한다.&lt;/li&gt;
&lt;li&gt;equals를 따로 정의하지 않았다면 정당한 이유가 없는 이상 hashCode를 따로 정의하지 않는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CompareTo의 규약을 지켜라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;compareTo 메서드는 Any클래스에 있는 메서드가 아니다. 이는 수학적인 부등식으로 변환되는 연산자이다.&lt;/li&gt;
&lt;li&gt;compareTo는 다음과 같이 동작해야 한다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;비대칭적 동작 : a &amp;ge; b 이고 b &amp;ge; a 라면 a == b 여야 한다.&lt;/li&gt;
&lt;li&gt;연속적 동작 : a &amp;ge; b 이고 b &amp;ge; c 이면 a&amp;ge;c 여야 한다. 이러한 동작을 하지 못하면 요소 정렬이 무한 반복에 빠질 수 있다.&lt;/li&gt;
&lt;li&gt;코넥스적 동작 : 두 요소는 어떤 확실한 관계를 가지고 있어야 한다. 즉, a&amp;ge;b 또는 b&amp;ge;a 중에 적어도 하나는 항상 true 여야 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코틀린에서 compareTo를 따로 정의해야 하는 상황은 거의 없다. 일반적으로 어떤 프로퍼티 하나를 기반으로 순서를 지정하는 것으로 충분하기 때문이다.&lt;/li&gt;
&lt;li&gt;String 끼리 비교하는 등 객체가 자연스러운 순서인지 확실하지 않다면 비교기 (comparator)를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;API의 필수적이지 않는 부분을 확장 함수로 추출하라&lt;/b&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;li&gt;멤버롸 확장의 가장 큰 차이점은 확장은 따로 가져와서 사용해야 한다는 것이다. 그래서 일반적으로 확장은 다른 패키지에 위치한다.&lt;/li&gt;
&lt;li&gt;상속을 목적으로 설계된 요소는 확장 함수로 만들면 안된다.&lt;/li&gt;
&lt;li&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;확장 함수는 virtual이 아니다.&lt;/li&gt;
&lt;li&gt;멤버는 높은 우선 순위를 갖는다.&lt;/li&gt;
&lt;li&gt;확장 함수는 클래스 위가 아니라 타입 위에 만들어진다.&lt;/li&gt;
&lt;li&gt;확장 함수는 클래스 레퍼런스에 나오지 않는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;멤버 확장 함수의 사용을 피하라&lt;/b&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;li&gt;확장 함수의 가시성을 제한하고 싶다면 멤버로 만들지 말고 가시성 한정자를 붙여주면 된다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/259</guid>
      <comments>https://haruple.tistory.com/259#entry259comment</comments>
      <pubDate>Fri, 28 Apr 2023 23:54:38 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] 상속보다는 컴포지션을 사용하라</title>
      <link>https://haruple.tistory.com/258</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;상속보다는 컴포지션을 사용하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;상속은 굉장히 강력한 기능으로 is-a 관계의 객체 계층 구조를 만들기 위해 설계되었다.&lt;/li&gt;
&lt;li&gt;상속은 하나의 클래스만을 대상으로 할 수 있다. 상속을 사용해 행위를 추출하다 보면 많은 함수를 갖는 거대한 Base 클래스를 만들게 되고, 굉장히 깊고 복잡한 계층 구조가 만들어진다.&lt;/li&gt;
&lt;li&gt;상속은 클래스의 모든 것을 가져오므로 불필요한 함수를 갖는 클래스가 만들어 질 수 있다.&lt;/li&gt;
&lt;li&gt;상속은 코드를 이해하기 어렵게 할 수 있다. 슈퍼클래스를 여러번 확인해야할 수 있다.&lt;/li&gt;
&lt;li&gt;그래서 대표적인 대안으로 컴포지션이 있다.&lt;/li&gt;
&lt;li&gt;컴포지션을 사용한다는 것은 객체를 프로퍼티로 갖고, 함수를 호출하는 형태로 재사용하는 것을 의미한다.&lt;/li&gt;
&lt;li&gt;상속은 슈퍼 클래스의 메서드, 제약, 행위 등 모든 것을 가져온다. 따라서 상속은 객체의 계층 구조를 나타낼 때 굉장히 좋은 도구이다. 하지만 일부분을 재사용 하기 위한 목적으로는 적합하지 않다.&lt;/li&gt;
&lt;li&gt;코틀린은 다중 상속을 지원하지 않는다.&lt;/li&gt;
&lt;li&gt;어떤 이유로 상속은 허용하지만 메서드는 오버라이드 하지 못하게 하려면 opne 클래스에 open 메서드를 사용한다.&lt;/li&gt;
&lt;li&gt;open 한 메서드만 오버라이드 하게 할 수 있다.&lt;/li&gt;
&lt;li&gt;일반적으로 OOP에서는 상속보다 컴포지션을 사용하는 것이 좋다. 코틀린에서는 더욱 이런 규칙을 지켜주는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;데이터 집합 표현에 data 한정자를 사용하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;때로는 데이터를 한번에 전달해야 할 때가 있다. 이럴 때 data 한정자를 사용한다.&lt;/li&gt;
&lt;li&gt;data 한정자를 붙이면 toString, equals, hashCode, copy, componentN 함수가 자동으로 생성된다.&lt;/li&gt;
&lt;li&gt;toString : 클래스 이름과 기본 생성자 형태로 모든 프로퍼티와 값을 출력해준다. 로그를 출력할 때나 디버그 할 때 유용하다.&lt;/li&gt;
&lt;li&gt;euqals : 기본 생성자의 프로퍼티가 같은지 확인해준다.&lt;/li&gt;
&lt;li&gt;copy: immutable 데이터 클래스를 만들 때 편리하다. 기본 생성자 프로퍼티가 같은 새로운 객체를 복제한다.&lt;/li&gt;
&lt;li&gt;튜플대신 데이터 클래스 사용하기
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Pair, Triple이 코틀린에 남은 마지막 튜플이다.&lt;/li&gt;
&lt;li&gt;튜플은 데이터 클래스와 같은 역할을 하지만 가독성이 훨씬 나쁘다. 튜플만 보고는 어떤 타입을 나타내는지 예측할 수 없다. 튜플보다 데이터 클래스를 사용하는 것이 더 좋았기 때문에 점차 없어진 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Pair와 Triple은 몇가지 지역적인 목적으로 인해 남아있을 뿐이다.
&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;표준 라이브러리에서 볼 수 있는 것처럼 미리 알 수 없는 aggregate(집합)를 표현할 때&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;이런 경우를 제외하면 무조건 데이터 클래스를 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;연산 또는 액션을 전달할 때는 인터페이스 대신 함수 타입을 사용하라&lt;/b&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;그래서 연산 또는 액션을 전달할 때 메서드가 하나만 있는 인터페이스를 활용한다. 이런 인터페이스를 SAM 이라고 부른다.&lt;/li&gt;
&lt;li&gt;이런 코드를 함수 타입을 사용하는 코드로 변경하면 더 많은 자유를 얻을 수 있다.&lt;/li&gt;
&lt;li&gt;람다 표현식을 사용할 때는 아규먼트 분해도 사용할 수 있다. SAM보다 함수타입을 사용하는 것이 훨씬 더 좋은 이유이다.&lt;/li&gt;
&lt;li&gt;코틀린이 아닌 다른 언어에서 사용할 클래스를 설계할 때만 SAM을 사용하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/258</guid>
      <comments>https://haruple.tistory.com/258#entry258comment</comments>
      <pubDate>Thu, 27 Apr 2023 22:09:19 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] API 안정성을 확인하라</title>
      <link>https://haruple.tistory.com/257</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;API 안정성을 확인하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API가 변경되고, 개발자가 이를 업데이트 했다면 여러 코드를 수동으로 업데이트 해야한다. 많은 요소가 이 API에 의존하고 있다면 이는 큰 문제가 된다.&lt;/li&gt;
&lt;li&gt;라이브러리의 작은 변경은 이를 활용하는 다른 코드들의 많은 부분을 변경하게 할 수 있다. 그래서 이전 라이브러리를 유지하는 경우가 있다.&lt;/li&gt;
&lt;li&gt;오래된 라이브러리는 버그와 취약성이 발생할 수 있기 때문에 안정적인 라이브러리로 업데이트 하는 것을 두려워하면 안된다.&lt;/li&gt;
&lt;li&gt;처음부터 안정적이지 않은 모듈을 많이 공부하는 것보다 안정적인 모듈부터 공부해보는게 좋다.&lt;/li&gt;
&lt;li&gt;API의 일부가 불안정하면 이를 개발자에게 명확히 알려줘야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;외부 API를 wrap 해서 사용하라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;API 설계자가 안전하지 않다고 하거나 우리가 그것을 제대로 신뢰할 수 없다면, 해당 API는 불안정한 것이다. 이러한 불안정한 API를 과도하게 사용하는 것은 굉장히 위험하다.&lt;/li&gt;
&lt;li&gt;어쩔 수 없이 사용해야 한다면 로직과 직접 결합시키지 않는 것이 좋다.&lt;/li&gt;
&lt;li&gt;그래서 불안정하다고 판단되는 외부 라이브러리를 wrap해서 사용한다.&lt;/li&gt;
&lt;li&gt;문제가 있다면 warpper만 변경하면 되므로 API 변경에 쉽게 대응할 수 있다.&lt;/li&gt;
&lt;li&gt;프로젝트의 스타일에 맞춰서 API의 형태를 조정할 수 있다.&lt;/li&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;&lt;b&gt;요소의 가시성을 최소화 하라.&lt;/b&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;li&gt;변경을 가할 때는 기존의 것을 숨기는 것보다 새로운 것을 노출하는 것이 쉽다.&lt;/li&gt;
&lt;li&gt;가시성이 제할될수록 클래스의 변경을 쉽게 추적할 수 있으며, 프로퍼티의 상태를 더 쉽게 이해할 수 있다.&lt;/li&gt;
&lt;li&gt;내부적인 변경 없이 작은 인터페이스를 유지하고 싶다면 가시성을 제한하면 된다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/257</guid>
      <comments>https://haruple.tistory.com/257#entry257comment</comments>
      <pubDate>Tue, 18 Apr 2023 21:59:11 +0900</pubDate>
    </item>
    <item>
      <title>[메이플러] 문의하기</title>
      <link>https://haruple.tistory.com/256</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot_20230415_150157.jpg&quot; data-origin-width=&quot;425&quot; data-origin-height=&quot;435&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cuMpwP/btsakf7M7gB/I9dcFMRxTg3xofsiBKRkkk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuMpwP/btsakf7M7gB/I9dcFMRxTg3xofsiBKRkkk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuMpwP/btsakf7M7gB/I9dcFMRxTg3xofsiBKRkkk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuMpwP%2Fbtsakf7M7gB%2FI9dcFMRxTg3xofsiBKRkkk%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;208&quot; height=&quot;213&quot; data-filename=&quot;Screenshot_20230415_150157.jpg&quot; data-origin-width=&quot;425&quot; data-origin-height=&quot;435&quot;/&gt;&lt;/span&gt;&lt;/figure&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;
&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>블로그/공지사항</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/256</guid>
      <comments>https://haruple.tistory.com/256#entry256comment</comments>
      <pubDate>Sat, 15 Apr 2023 15:06:21 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] 추상화 설계</title>
      <link>https://haruple.tistory.com/255</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;4장 추상화 설계&lt;/b&gt;&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OOP (객체지향 프로그래밍)에서 추상화는 세 가지 주요 개념 중에 하나이다. (추상화, 캡슐화, 상속)&lt;/li&gt;
&lt;li&gt;추상화를 간단하게 표현하면 &amp;lsquo;복잡성을 숨기기 위해 사용되는 단순한 형식&amp;rsquo; 을 의미한다.&lt;/li&gt;
&lt;li&gt;인터페이스는 클래스라는 복잡한 것에서 메서드와 프로퍼티만 추출해서 간단하게 만들었으므로, 클래스의 추상화라고 할 수 있다.&lt;/li&gt;
&lt;li&gt;많은 개발자는 프로그래밍에서 하는 모든 일이 추상화라는 것을 종종 잊는다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;숫자를 입력하면 내부에서 0, 1의 복잡한 형식으로 표현된다.&lt;/li&gt;
&lt;li&gt;문자열은 UTF-8과 같은 복잡한 형식의 집합으로 표현된다.&lt;/li&gt;
&lt;li&gt;이러한 것들이 모두 추상화 되어 있기 때문에 우리가 쉽게 사용할 수 있는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;강력한 프로그래밍 언어들이 당연히 갖고 있는 기능 중 하나는 공통 패턴에 이름을 붙여서 추상화를 만드는 기능이다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;maxOf, lazy 등&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&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;li&gt;만드는 사람에게 변화의 자유를 주기 위해&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;함수 내부의 추상화 레벨을 통일하라&lt;/span&gt;&lt;/b&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;프로그래밍을 간단하게 할 수 있게 엔지니어는 한 언어를 다른 언어로 변환하는 프로그램인 &amp;lsquo;컴파일러&amp;rsquo; 를 만들었다.&lt;/li&gt;
&lt;li&gt;최초의 컴파일 언어는 또 더 나은 프로그래밍 언어를 만드는데 사용되었고 그 언어는 또 더 나은 프로그래밍 언어를 만드는데 사용되었다. 그렇게 C, C++ 등의 높은 레벨 언어들이 등장했다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;변화로부터 코드를 보호하려면 추상화를 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자주 사용하는 하드코딩 된 값을 사용할 때는 상수(const val)로 표현하는 것이 좋다. 숫자로 기입되어 있는 경우 코드를 이해하기 어려워진다.&lt;/li&gt;
&lt;li&gt;상수로 추출하면 이름을 붙일 수 있고, 나중에 해당 값을 쉽게 변경할 수 있다.&lt;/li&gt;
&lt;li&gt;만약 토스트를 출력하는 함수를 showToast() 가 아닌 showMessage()와 같이 더 높은 레벨의 함수로 옮겨보았다. 가장 큰 변화는 이름이다. 큰 차이가 없다고 생각할 수 있는데 이는 컴파일러의 관점이지 사람의 관점에서는 이름이 바뀌면 큰 변화가 일어난 것이다.&lt;/li&gt;
&lt;li&gt;함수는 추상화를 표현하는 수단이며, 함수 시그니처는 이 함수가 어떤 추상화를 표현하고 있는지 알려준다. 따라서 의미 있는 이름은 굉장히 중요하다.&lt;/li&gt;
&lt;li&gt;클래스가 함수보다 더 강력한 이유는 상태를 가질 수 있고 많은 함수를 가질 수 있기 때문이다.&lt;/li&gt;
&lt;li&gt;코틀린 표준 라이브러리를 읽어보면 거의 모든 것이 인터페이스로 표현된다는 것을 확인할 수 있다.&lt;/li&gt;
&lt;li&gt;listOf함수는 List를 리턴한다. 여기서 List는 인터페이스이다. listOf는 팩토리 메서드이다.&lt;/li&gt;
&lt;li&gt;라이브러리를 만드는 사람은 내부 클래스의 가시성을 제한하고 인터페이스를 통해 이를 노출하는 코드를 많이 사용한다.&lt;/li&gt;
&lt;li&gt;코틀린은 멀티 플랫폼 언어이다. listOf를 사용하면 코틀린/JVM, 코틀린/JS, 코틀린/네이티브에 따라서 구현이 다른 리스트를 리턴한다. 최적화 때문이다.&lt;/li&gt;
&lt;li&gt;하지만 어떤 플랫폼을 사용해도 List 인터페이스에 맞춰져있으므로 차이없이 사용할 수 있다.&lt;/li&gt;
&lt;li&gt;추상화에는 단점도 존재한다. 추상화는 자유를 주지만 코드를 이해하고 수정하기 어렵게 만든다.&lt;/li&gt;
&lt;li&gt;추상화는 많은 것을 숨길 수 있는 테크닉이다. 생각할 것을 어느 정도 숨겨야 개발이 쉬워지는 것도 사실이지만 너무 많은 것을 숨기면 결과를 이해하는 것 자체가 어려워진다.&lt;/li&gt;
&lt;li&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;li&gt;프로젝트의 크기&lt;/li&gt;
&lt;li&gt;특징 세트&lt;/li&gt;
&lt;li&gt;도메인 지식&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/255</guid>
      <comments>https://haruple.tistory.com/255#entry255comment</comments>
      <pubDate>Tue, 11 Apr 2023 18:19:25 +0900</pubDate>
    </item>
    <item>
      <title>[이펙티브 코틀린] 일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라</title>
      <link>https://haruple.tistory.com/254</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;일반적인 프로퍼티 패턴은 프로퍼티 위임으로 만들어라&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;대표적인 예로 지연 프로퍼티가 있다. lazy는 이후에 처음 사용하는 요청이 들어올 때 초기화되는 프로퍼티다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;val value by lazy { createValue() }&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;프로퍼티 위임으로 observable패턴을 쉽게 만들 수 있다.&lt;/li&gt;
&lt;li&gt;프로퍼티 위임 메커니즈으로 다양한 패턴을 만들 수 있다. 좋은 예로 뷰, 리소스 바인딩, 의존성 주입, 데이터 바인딩 등이 있다.&lt;/li&gt;
&lt;li&gt;일반적으로 이런 패턴을 사용할 때 자바 등에서는 어노테인션을 활용해야 하지만 코틀린은 프로퍼티 위임을 사용해 간단하고 type-safe하게 구현할 수 있다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;private val button: Button by bindView(R.id.button)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;코틀린 stdlib에서 다음의 프로퍼티 델리게이터를 알아두면 좋다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;lazy&lt;/li&gt;
&lt;li&gt;Delegates.observable&lt;/li&gt;
&lt;li&gt;Delegates.vetoable&lt;/li&gt;
&lt;li&gt;Delegates.notNull&lt;/li&gt;
&lt;/ul&gt;
&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;일반적인 알고리즘을 구현할 때 제네릭을 사용하라&lt;/b&gt;&lt;/span&gt;&lt;/h3&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;대표적인 예로 filter 함수가 있다. filter는 타입 파라미터 T 를 갖는다.&lt;/li&gt;
&lt;li&gt;제네릭은 기본적으로 List&amp;lt;String&amp;gt; 또는 Set&amp;lt;User&amp;gt; 처럼 구체적인 타입으로 컬렉션을 만들 수 있게 클래스와 인터페이스에 도입된 기능이다. 컴파일 과정에서 최종적으로 이런 타입 정보는 사라지지만, 개발 중에는 특정 타입을 사용하게 강제할 수 있다.&lt;/li&gt;
&lt;li&gt;제네릭 제한 : 타입 파라미터의 중요한 기능 중 하나는 구체적인 타입의 서브타입만 사용하게 타입을 제한하는 것이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;b&gt;타입 파라미터의 섀도잉을 피하라&lt;/b&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;class Forest(val name: String) {&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;fun addTree(name: String) {&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 코드 처럼 프로퍼티와 파라미터가 같은 이름을 가질 수 있다. 이렇게 되면 지역 파라미터가 외부 스코프에 있는 프로퍼티를 가린다. 이를 &lt;b&gt;섀도잉&lt;/b&gt; 이라고 한다.&lt;/li&gt;
&lt;li&gt;섀도잉은 클래스 타입 파라미터와 함수 타입 파라미터 사이에서도 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;이는 심각한 문제가 될 수 있고, 개발자가 스스로 문제를 찾아내기도 힘들다.&lt;/li&gt;
&lt;li&gt;만약 독립적인 파라미터를 의도한다면 이름을 아예 다르게 다는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;공통 모듈을 추출해서 여러 플랫폼에서 재사용하라&lt;/span&gt;&lt;/b&gt;&lt;/h3&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;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/254</guid>
      <comments>https://haruple.tistory.com/254#entry254comment</comments>
      <pubDate>Mon, 10 Apr 2023 22:17:10 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 안드로이드스튜디오 다양한 형식의 자료형 Intent 활용 방법</title>
      <link>https://haruple.tistory.com/253</link>
      <description>&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;여러 클래스간 데이터 공유는 Application을 활용하거나 ViewModel을 활용하는 등 여러가지 방법이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적으로 Activity에서 Activity 혹은 Fragment간 데이터 전송을 위해 Intent를 사용합니다.&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;흔히 사용하는 기본적인 자료형인 String, Boolean, Int 등은 Intent를 활용해서 다른 클래스로 쉽게 데이터를 전송할 수 있습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;일반 자료형 전송 방법&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1680787343777&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val intent = Intent(this, OtherClass::class.java)
intent.putExtra(&quot;NUMBER_KEY&quot;, number)
startActivity(intent)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 전송할 클래스에 putExtra 로 데이터를 넣어줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;흔히 사용하는 일반적인 자료형은 대부분 putExtra로 작동이 가능합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680787401710&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val number = intent.getIntExtra(&quot;NUMBER_KEY&quot;, 0)&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;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;List 데이터 전송 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래는 StringList를 전송하는 방법입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680787123029&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val categoryList = listOf(&quot;apple&quot;, &quot;banana&quot;, &quot;orange&quot;)

val intent = Intent(this, OtherActivity::class.java)
intent.putStringArrayListExtra(&quot;CATEGORY_LIST&quot;, ArrayList(categoryList))
startActivity(intent)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;전송할 클래스에서 &quot;CATEGORY_LIST&quot;를 Key로 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;StringList를 전송할 때는 putStringArrayListExtra 를 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1680787193312&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val categoryList = intent.getStringArrayListExtra(&quot;CATEGORY_LIST&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 전송 받는 클래스에서는 위와 같이 getStringArrayListExtra 사용하면 됩니다.&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;데이터 클래스 전송 방법&lt;/b&gt;&lt;/h2&gt;
&lt;pre id=&quot;code_1680787649921&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class LoginData(
    val LoginID: String,
    val LoginPW: String
) : Serializable&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 data class에 Serializable을 상속받습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680787718952&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val intent = Intent(this, OtherActivity::class.java)
intent.putExtra(&quot;MY_DATA_CLASS_KEY&quot;, myDataClass)
startActivity(intent)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마찬가지로 putExtra 를 사용하고 dataClass를 넣어줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680787772628&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val loginData = intent.getSerializableExtra(&quot;MY_DATA_CLASS_KEY&quot;) as LoginData&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터를 전송받을 클래스에서 getSerializableExtra를 사용해서 입력받습니다.&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>intent</category>
      <category>kotlin</category>
      <category>안드로이드스튜디오</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/253</guid>
      <comments>https://haruple.tistory.com/253#entry253comment</comments>
      <pubDate>Thu, 6 Apr 2023 22:30:58 +0900</pubDate>
    </item>
    <item>
      <title>[3월에 읽은 도서] 부동산 투자 필독서 30</title>
      <link>https://haruple.tistory.com/252</link>
      <description>&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/csZY1q/btr6BBNJOzr/9HhlQ21LqNj62cKkBjqYi0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/csZY1q/btr6BBNJOzr/9HhlQ21LqNj62cKkBjqYi0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/csZY1q/btr6BBNJOzr/9HhlQ21LqNj62cKkBjqYi0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcsZY1q%2Fbtr6BBNJOzr%2F9HhlQ21LqNj62cKkBjqYi0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;389&quot; height=&quot;519&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/figure&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;
&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-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Jk0uZ/btr6tV7AzMZ/9ZmENi44yTCWs8r3vSfr71/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Jk0uZ/btr6tV7AzMZ/9ZmENi44yTCWs8r3vSfr71/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Jk0uZ/btr6tV7AzMZ/9ZmENi44yTCWs8r3vSfr71/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJk0uZ%2Fbtr6tV7AzMZ%2F9ZmENi44yTCWs8r3vSfr71%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bvYm7o/btr6tV0Tryh/ZkMo0ojxfj5SFbOagwC0SK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bvYm7o/btr6tV0Tryh/ZkMo0ojxfj5SFbOagwC0SK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bvYm7o/btr6tV0Tryh/ZkMo0ojxfj5SFbOagwC0SK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbvYm7o%2Fbtr6tV0Tryh%2FZkMo0ojxfj5SFbOagwC0SK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/figure&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;누구는 경매로, 아파트로, 청약으로, 재건축으로, 빌라, 상가 등 엄청 많은 방법으로 투자를 성공했는데 얕게 보기 좋았다.&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;한 권에 30권의 내용을 담다보니 한 단락이 짧기 때문에 보기가 편하고 재미있었다.&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;그리고 이거 다 보고 든 생각&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;이걸 출판한 사람은 또 수익을 얻어가네 라는 생각ㅋㅋㅋ&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;</description>
      <category>일상/일상</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/252</guid>
      <comments>https://haruple.tistory.com/252#entry252comment</comments>
      <pubDate>Tue, 28 Mar 2023 23:53:40 +0900</pubDate>
    </item>
    <item>
      <title>[Android] 이펙티브 코틀린 3장 재사용성</title>
      <link>https://haruple.tistory.com/251</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;3장 재사용성&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;안드로이드 뷰를 만드는 작업은 굉장히 간단하다. 이는 안드로이드가 복잡한 코드를 API로 간단하게 만들어주기 때문이다.&lt;/li&gt;
&lt;li&gt;누군가 이러한 것을 한번 만들어 놓으면, 필요할 때 활용할 수 있는 것. 이것이 바로 프로그래밍 언어의 핵심 특징이라고 할 수 있는 재사용성이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;knowledge를 반복하여 사용하지 말라&lt;/b&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;프로그래밍에서 knowledge는 넓은 의미로 &amp;lsquo;의도적인 정보&amp;rsquo;를 뜻한다.&lt;/li&gt;
&lt;li&gt;로직 : 프로그램이 어떠한 식으로 동작하는지와 프로그램이 어떻게 보이는지&lt;/li&gt;
&lt;li&gt;공통 알고리즘 : 원하는 동작을 하기 위한 알고리즘&lt;/li&gt;
&lt;li&gt;knowledge반복은 프로젝틑의 확장성을 막고 쉽게 깨지게 만든다.&lt;/li&gt;
&lt;li&gt;단일 책임 원칙 : 코드를 추출해도 되는지를 확인할 수 있는 원칙으로 SOLID 원칙 중 하나이다. &amp;lsquo;클래스를 변경하는 이유는 단 한가지여야 한다&amp;rsquo; 라는 의미이다.&lt;/li&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;&lt;b&gt;일반적인 알고리즘을 반복해서 구현하지 말라.&lt;/b&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;이미 있는 stdlib의 확장함수를 사용하는 것이 좋다. (indexOf, subString, coerceIn, sortedBy 등)&lt;/li&gt;
&lt;li&gt;이러면 코드 작성 속도가 빨라지고 가독성이 높아진다. 그리고 직접구현할 때 발생할 수 있는 실수를 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;표준 라이브러리인 stdlib은 확장함수를 이용해서 만들어진 굉장히 거대한 유틸리티 라이브러리이다.&lt;/li&gt;
&lt;li&gt;stdlib의 함수를 하나하나 살펴보는 것은 굉장히 어려울 수 있지만 가치가 있는 일이다. 만약 자세히 살펴보지 않으면 계속해서 같은 함수를 여러개 만들 게 될 것이다.&lt;/li&gt;
&lt;li&gt;동일한 결과를 얻는 함수를 여러번 만드는 것은 잘못된 일이다.&lt;/li&gt;
&lt;li&gt;stdlib에 없는 알고리즘은 직접 프로젝트 내부에 확장함수로 정의하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <category>Android</category>
      <category>안드로이드스튜디오</category>
      <category>이펙티브코틀린</category>
      <category>재사용성</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/251</guid>
      <comments>https://haruple.tistory.com/251#entry251comment</comments>
      <pubDate>Mon, 20 Mar 2023 22:02:22 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 안드로이드스튜디오 뷰 사이즈를 조절하는 애니메이션</title>
      <link>https://haruple.tistory.com/250</link>
      <description>&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;이번에는 뷰 사이즈를 조절하는 코드 두가지를 알려드리겠습니다.&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;pre class=&quot;kotlin&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;fun View.animateViewWidth(duration: Long, startWidth: Int, endWidth: Int) {
    val animation = object : Animation() {
        override fun applyTransformation(interpolatedTime: Float, t: Transformation) {
            val newWidth = (startWidth + (endWidth - startWidth) * interpolatedTime).toInt()
            val params = this@animateViewWidth.layoutParams as ViewGroup.LayoutParams
            params.width = newWidth
            this@animateViewWidth.layoutParams = params
        }
    }
    animation.duration = duration
    this@animateViewWidth.startAnimation(animation)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 때는 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;binding.textView.animateViewWidth()&lt;/b&gt;&lt;/span&gt; 이렇게 사용하면 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 코드의 width를 height로 바꿔서 높이를 바꾸는 애니메이션을 적용할 수 있습니다.&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;아래는 ValueAnimator를 이용해 뷰 가로 사이즈를 변경하는 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작동 결과는 위 코드와 동일합니다. 두가지 중 더 보기 쉬운 코드로 작성하면 될 것 같습니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; style=&quot;background-color: #2b2b2b; color: #a9b7c6;&quot;&gt;&lt;code&gt;fun View.animateViewWidth(duration: Long, startWidth: Int, endWidth: Int) {
    val valueAnimator = ValueAnimator.ofInt(startWidth, endWidth)
    valueAnimator.addUpdateListener { animation -&amp;gt;
        val newWidth = animation.animatedValue as Int
        val params = this@animateViewWidth.layoutParams as ViewGroup.LayoutParams
        params.width = newWidth
        this@animateViewWidth.layoutParams = params
    }
    valueAnimator.duration = duration
    valueAnimator.start()
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>개발/Android</category>
      <category>ValueAnimator</category>
      <category>뷰 사이즈 조절</category>
      <category>안드로이드스튜디오</category>
      <category>애니메이션</category>
      <category>코틀린</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/250</guid>
      <comments>https://haruple.tistory.com/250#entry250comment</comments>
      <pubDate>Tue, 14 Mar 2023 22:35:12 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드에서 맥으로 사진 쉽게 옮기는 방법 (Dropship)</title>
      <link>https://haruple.tistory.com/249</link>
      <description>&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;Dropship&lt;/b&gt;이라는 소프트웨어를 내놓았는데 꽤나 편했습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;애플이 에어드랍으로 사용자를 확보할 때 갤럭시에도 똑같이 퀵 쉐어 라는 기능이 존재하지만 솔직히 사람들이 거의 모르는 것 같습니다. 저처럼 전자제품 좋아하는 사람이나 알지 전체 사용자 비율로 따졌을때는 5%는 되려나..? 하지만 에어드랍은 거의 대부분의 IOS 사용자가 알고 있습니다.&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;그리고 이전에 개발되어 있던 드랍쉽은 갤럭시에서 갤럭시끼리는 공유가 쉽지만, IOS로 옮기려면 QR 코드를 공유해야 하는 등 번거로운 과정이 있었습니다. 그래서인지 삼성에서 새로운 공유 소프트웨어 Dropship을 개발했습니다.&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;이 Dropship은 웹 기반 공유 프로그램이기 때문에 맥 뿐만 아니라 웹을 켤 수 있는 모든 OS 환경에서는 다 공유가 가능합니다.&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;아 그리고 이건 같은 안드로이드여도 LG나 중국 안드로이드 폰은 해당하지 않고 오로지 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;갤럭시에서만 가능한 방법&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/De13l/btr2ws0F344/37DoiRh7kK8WjGiPgbgcr1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/De13l/btr2ws0F344/37DoiRh7kK8WjGiPgbgcr1/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/De13l/btr2ws0F344/37DoiRh7kK8WjGiPgbgcr1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDe13l%2Fbtr2ws0F344%2F37DoiRh7kK8WjGiPgbgcr1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dcTycW/btr2wujS6Bz/oIS3TIZRkGikS8P1cMkBY1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dcTycW/btr2wujS6Bz/oIS3TIZRkGikS8P1cMkBY1/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dcTycW/btr2wujS6Bz/oIS3TIZRkGikS8P1cMkBY1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdcTycW%2Fbtr2wujS6Bz%2FoIS3TIZRkGikS8P1cMkBY1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;갤럭시 스토어에서 Dropship을 다운로드&lt;/b&gt;&lt;/span&gt;합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;23.03.06 기준으로는 Dropship이 플레이스토어에는 업로드 되어 있지 않네요.&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqkhSB/btr2sFUh4Ts/mGTfTH6EiGGP8utXRk1JSk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqkhSB/btr2sFUh4Ts/mGTfTH6EiGGP8utXRk1JSk/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqkhSB/btr2sFUh4Ts/mGTfTH6EiGGP8utXRk1JSk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqkhSB%2Fbtr2sFUh4Ts%2FmGTfTH6EiGGP8utXRk1JSk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qAB1I/btr2sXmSWTk/FRf87ph9th6RgSbt8Ez4K1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qAB1I/btr2sXmSWTk/FRf87ph9th6RgSbt8Ez4K1/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qAB1I/btr2sXmSWTk/FRf87ph9th6RgSbt8Ez4K1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqAB1I%2Fbtr2sXmSWTk%2FFRf87ph9th6RgSbt8Ez4K1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4N3pG/btr18DJ3gd8/vYirnqdwcWxOvKMOXuDCV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4N3pG/btr18DJ3gd8/vYirnqdwcWxOvKMOXuDCV0/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4N3pG/btr18DJ3gd8/vYirnqdwcWxOvKMOXuDCV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F4N3pG%2Fbtr18DJ3gd8%2FvYirnqdwcWxOvKMOXuDCV0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이후 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;'파일 보내기'&lt;/b&gt;&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;저는 오늘 먹은 매운실비김치를 전송해보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJh3vF/btr18C5ofc9/VF1xfigmibuDvIIg81jRB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJh3vF/btr18C5ofc9/VF1xfigmibuDvIIg81jRB1/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJh3vF/btr18C5ofc9/VF1xfigmibuDvIIg81jRB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJh3vF%2Fbtr18C5ofc9%2FVF1xfigmibuDvIIg81jRB1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CIQqO/btr2rD3wliD/RpilNkSHsD0XcYLU65CkM0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CIQqO/btr2rD3wliD/RpilNkSHsD0XcYLU65CkM0/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CIQqO/btr2rD3wliD/RpilNkSHsD0XcYLU65CkM0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCIQqO%2Fbtr2rD3wliD%2FRpilNkSHsD0XcYLU65CkM0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/A8McC/btr2wtSOPXI/T19DeY5wMuwnhSY3nX3E60/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/A8McC/btr2wtSOPXI/T19DeY5wMuwnhSY3nX3E60/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/A8McC/btr2wtSOPXI/T19DeY5wMuwnhSY3nX3E60/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FA8McC%2Fbtr2wtSOPXI%2FT19DeY5wMuwnhSY3nX3E60%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 별로 보안이 중요한 파일이 아니면 Dropship 설정을 누르지 않고 그냥 바로 다음을 눌러서 전송하면 되고, 보안이 필요하다 싶으면 Dropship 설정을 누르세요.&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;&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;&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;사진을 스마트폰으로 공유한 다음 맥이나 기타 기기로 와서 Dropship 사이트로 들어갑니다.&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;a href=&quot;https://g2sh.me/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://g2sh.me/&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678110375533&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;Dropship&quot; data-og-description=&quot;드랍쉽 - 무엇이든 누구에게든!&quot; data-og-host=&quot;g2sh.me&quot; data-og-source-url=&quot;https://g2sh.me/&quot; data-og-url=&quot;https://g2sh.me/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dXg5vp/hyRRGAD7It/2Aq9rJ6gNNOPo9lRD3ZYp1/img.png?width=1063&amp;amp;height=603&amp;amp;face=0_0_1063_603&quot;&gt;&lt;a href=&quot;https://g2sh.me/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://g2sh.me/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dXg5vp/hyRRGAD7It/2Aq9rJ6gNNOPo9lRD3ZYp1/img.png?width=1063&amp;amp;height=603&amp;amp;face=0_0_1063_603');&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;Dropship&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;드랍쉽 - 무엇이든 누구에게든!&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;g2sh.me&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;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YdQUf/btr2vVolCwv/uX5ISzkKAZzJYeNFjJXkZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YdQUf/btr2vVolCwv/uX5ISzkKAZzJYeNFjJXkZk/img.png&quot; data-origin-width=&quot;1774&quot; data-origin-height=&quot;1084&quot; data-is-animation=&quot;false&quot; style=&quot;width: 57.2834%; margin-right: 10px;&quot; data-widthpercent=&quot;57.96&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YdQUf/btr2vVolCwv/uX5ISzkKAZzJYeNFjJXkZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYdQUf%2Fbtr2vVolCwv%2FuX5ISzkKAZzJYeNFjJXkZk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1774&quot; height=&quot;1084&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/SndQo/btr2hJDfCNa/W7APYZKJSKrBjq6P6DlrH1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/SndQo/btr2hJDfCNa/W7APYZKJSKrBjq6P6DlrH1/img.png&quot; data-origin-width=&quot;1700&quot; data-origin-height=&quot;1432&quot; data-is-animation=&quot;false&quot; style=&quot;width: 41.5538%;&quot; data-widthpercent=&quot;42.04&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/SndQo/btr2hJDfCNa/W7APYZKJSKrBjq6P6DlrH1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FSndQo%2Fbtr2hJDfCNa%2FW7APYZKJSKrBjq6P6DlrH1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1700&quot; height=&quot;1432&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기에서 파일 받기를 선택하고 Dropship 좌표를 입력합니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;1460&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/byfVle/btr134Bcqbs/kX1NiXXSX3KSiiMKcrChf1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/byfVle/btr134Bcqbs/kX1NiXXSX3KSiiMKcrChf1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/byfVle/btr134Bcqbs/kX1NiXXSX3KSiiMKcrChf1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbyfVle%2Fbtr134Bcqbs%2FkX1NiXXSX3KSiiMKcrChf1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1756&quot; height=&quot;1460&quot; data-origin-width=&quot;1756&quot; data-origin-height=&quot;1460&quot;/&gt;&lt;/span&gt;&lt;/figure&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;size16&quot;&gt;갤럭시에서 맥으로 전송하는 과정이 아주 번거로웠었는데 뭐.. 완전 편한건 아니지만 그래도 나름 방법이 생겼다는 것에 만족하고 잘 쓰고 있습니다!&lt;/p&gt;</description>
      <category>일상/전자제품</category>
      <category>dropship</category>
      <category>맥</category>
      <category>사진공유</category>
      <category>안드로이드</category>
      <category>파일공유</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/249</guid>
      <comments>https://haruple.tistory.com/249#entry249comment</comments>
      <pubDate>Wed, 8 Mar 2023 20:55:32 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 안드로이드스튜디오 RecyclerView 스크롤시 데이터가 섞이는 문제 해결방법</title>
      <link>https://haruple.tistory.com/248</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;RecyclerView를 구현하고 데이터가 많아지면 스크롤 시 문제가 발생한다.&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;RecyclerView를 아래로 스크롤 하면 최상단에 있는 보이지 않게 된 시점의 뷰를 제일 아래로 끄집고 내려온다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존 ListView의 성능을 개선하기 위해 이렇게 한 점은 좋은데 문제는 그 끄집고 온 뷰를 그대로 보여준다는 것이다.&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;예를 들어 총 50개의 데이터가 있고 화면에는 5개의 데이터만 보이는 상황이다. 그럼 안드로이드는 뷰를 아마 5~6개를 재활용 해가면서 리스트를 구현할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 나는 어떤 버튼을 클릭 시 리스트 전체를 우측으로 애니메이션 시켜 보겠다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;1172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTFHi0/btr2tnltKf6/923nxkkxRl6kI5YlVm4AYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTFHi0/btr2tnltKf6/923nxkkxRl6kI5YlVm4AYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTFHi0/btr2tnltKf6/923nxkkxRl6kI5YlVm4AYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTFHi0%2Fbtr2tnltKf6%2F923nxkkxRl6kI5YlVm4AYK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;178&quot; height=&quot;1172&quot; data-origin-width=&quot;600&quot; data-origin-height=&quot;1172&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;1164&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/I671u/btr2xUbCU8k/400LjSRG13UNfdy0zFqz4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/I671u/btr2xUbCU8k/400LjSRG13UNfdy0zFqz4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/I671u/btr2xUbCU8k/400LjSRG13UNfdy0zFqz4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FI671u%2Fbtr2xUbCU8k%2F400LjSRG13UNfdy0zFqz4K%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;171&quot; height=&quot;1164&quot; data-origin-width=&quot;618&quot; data-origin-height=&quot;1164&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;1194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bZXTp2/btr2aH6OvEV/IkkbBuKI71LiUF83pMMoK0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bZXTp2/btr2aH6OvEV/IkkbBuKI71LiUF83pMMoK0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bZXTp2/btr2aH6OvEV/IkkbBuKI71LiUF83pMMoK0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbZXTp2%2Fbtr2aH6OvEV%2FIkkbBuKI71LiUF83pMMoK0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;176&quot; height=&quot;343&quot; data-origin-width=&quot;612&quot; data-origin-height=&quot;1194&quot;/&gt;&lt;/span&gt;&lt;/figure&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;결국 스크롤 하면 위, 아래 뷰들은 애니메이팅 되지 않은 채로 나타나게 된다.&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;h2 data-ke-size=&quot;size26&quot;&gt;해결방법&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. NestedScrollView&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;XML의 리사이클러뷰 주변에 NestedScrollView를 감싸게 되면 리스트 전체를 생성하게 된다. 예시로 든 50개라면 50개가 다 그려지게 된다. 하지만 리사이클러뷰를 사용하는 목적이 뷰를 재활용함으로써 성능 향상을 얻는 것인데 이러면 리스트뷰랑 다를게 없다. 만약 아래 방법으로 해결이 되지 않으면서 데이터의 갯수가 확실히 적은 경우라면 사용해도 되겠지만 애지간하면 쓰지 않는게 좋다.&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. getItemViewType&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 간단한 방법으로는 getItemViewType을 오버라이드 해서 어댑터 클래스에 넣어주면 된다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;override fun getItemViewType(position: Int): Int {
    return position
}&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;3. onBindViewHolder&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;onBindViewHolder는 새롭게 생성된 뷰가 있을 경우 호출되는 함수&lt;/b&gt;&lt;/span&gt;이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 내가 오른쪽으로 애니메이션을 했는지 안했는지 전역 변수를 만들고 해당 변수의 Boolean 값에 따라 뷰를 바로 처리하면 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;when (isAnimating) {&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp; &amp;nbsp;true -&amp;gt; 뷰를 오른쪽으로 그리기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;&amp;nbsp; &amp;nbsp;false -&amp;gt; 아무 행동 하지 않기&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;}&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 하면 보이지 않는 뷰가 생성될 때 즉시 onBindViewHolder가 호출되면서 내가 원하는 대로 뷰가 그려질 것이다.&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;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뭐.. 여차저차 해결은 했지만 누가 지금 보이는 뷰만 컨트롤 하고 뒤죽박죽 뷰가 섞이길 원한다고 이렇게 만들었는지 모르겠지만 이런 문제는 RecyclerView 라이브러리 자체를 업데이트 해서 그냥 해결해주면 좋겠다. 그래야 개발자들 코드도 더 깔끔해질테니까..&lt;/p&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/248</guid>
      <comments>https://haruple.tistory.com/248#entry248comment</comments>
      <pubDate>Tue, 7 Mar 2023 20:33:49 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드스튜디오 xml 프리뷰가 표시되지 않는 문제</title>
      <link>https://haruple.tistory.com/247</link>
      <description>&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;개발하면서 xml 프리뷰가 표시되지 않는 문제 때문에 골머리를 앓고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발 결과를 바로 확인할 수 없다보니 화면 개발 속도가 크게 떨어지는 것도 문제고, xml 코드 양이 비대해지면 작업이 거의 불가능한 수준까지 오게 됩니다.&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;xml 프리뷰가 나타나지 않는 특정 상황이 있습니다. 제가 파악한 상황은 다음과 같습니다.&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;1. 안드로이드스튜디오 IDE의 특정 버전에서만 발생합니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;FireFox에서는 발생하지 않는데 최신 버전인 Electric Eel 에서는 발생합니다.&lt;/b&gt;&lt;/span&gt; 마찬가지로 여러 버전을 테스트 해보았는데 어떤건 되고 어떤건 안되고.. 중구난방입니다. IDE 버전을 바꾸면 그래들 버전을 수정해야하고 그에 맞게 라이브러리 버전을 낮추어야 하기 때문에 제 프로젝트에서는 문제가 발생했습니다. 어쩔수 없이 Electric Eel 에서 프리뷰 없이 개발중인데 IDE 버전을 단순히 낮춰서 해결이 가능하다면 가장 좋을 것 같습니다.&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;2. constraint 레이아웃을 복잡하게 여러 계층을 엮어서 xml을 개발한 경우 발생합니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 레이아웃을 여러 계층으로 엮으면 앱 성능 저하 문제도 발생할 뿐더러 프리뷰가 보이지 않았습니다. 단순히 레이아웃을 2~3개 겹친 정도가 아니라 여러 계층을 엮고 뷰가 많을 경우 발생합니다. 저도 정확한 뷰와 레이아웃 갯수는 모르겠지만 복잡한 경우 주로 발생하는 것을 확인했습니다.&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;3. 하나의 프로젝트에서도 어떤 xml은 프리뷰가 동작하고 어떤 xml은 프리뷰가 동작하지 않습니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모든 xml 프리뷰가 동작하지 않는 것은 아니고 위 2번과 동일한 이유로 뷰가 별로 존재하지 않는 xml이거나 복잡하지 않은 ui면 잘 표시 됩니다.&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;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;4. 특정 라이브러리를 사용하였을 때 발생합니다.&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를들어 &lt;u&gt;일반적인 EditText를 넣었을 때는 잘 작동하다가 AppCompatEditText를 넣으면 xml 프리뷰가 없어집니다.&lt;/u&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;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;해결 방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 구글링하면서 파악한 문제 해결 방법입니다. 저는 IDE 버전을 수정하니 해결이 되긴 했었지만 1번에서 말한 것과 같이 낮은 버전의 IDE를 사용할 수 없는 환경이라 여전히 해결하지 못한 상황입니다. 나머지 해결 방법은 작동하지 않았지만 혹시 같은 문제를 겪고 있는 분이 계신다면 아래 방법을 시도해보세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;XML 구문 확인: XML 구문에 오류가 있으면 미리 보기가 표시되지 않을 수 있습니다. XML 코드에 표시되는 모든 오류를 수정해야 합니다.&lt;/li&gt;
&lt;li&gt;레이아웃 파일 확인: 미리 보려는 레이아웃 파일이 프로젝트의 올바른 디렉토리에 있는지 확인하십시오. 레이아웃 파일이 잘못된 위치에 있는 경우 Android 스튜디오에서 레이아웃 파일을 찾지 못할 수 있습니다.&lt;/li&gt;
&lt;li&gt;Instant Run 비활성화: Instant Run은 때때로 미리보기에 문제를 일으킬 수 있는 Android Studio의 기능입니다. Instant Run을 비활성화하고 미리보기가 작동하는지 확인하십시오. 이렇게 하려면 파일 &amp;gt; 설정 &amp;gt; 빌드, 실행, 배포 &amp;gt; Instant Run으로 이동하고 &quot;Enable Instant Run&quot; 옆의 확인란을 선택 취소합니다.&lt;/li&gt;
&lt;li&gt;SDK 및 빌드 도구 버전 확인: 프로젝트에 올바른 SDK 및 빌드 도구 버전이 설치되어 있는지 확인하십시오. 파일 &amp;gt; 프로젝트 구조 아래의 프로젝트 설정에서 이를 확인할 수 있습니다.&lt;/li&gt;
&lt;li&gt;캐시 무효화 및 다시 시작: 경우에 따라 Android Studio의 잘못된 캐시로 인해 미리보기에 문제가 발생할 수 있습니다. File &amp;gt; Invalidate Caches / Restart로 이동하여 &quot;Invalidate and Restart&quot;를 선택하십시오. 이렇게 하면 캐시가 지워지고 Android Studio가 다시 시작됩니다.&lt;/li&gt;
&lt;li&gt;Android Studio 업데이트: 이전 버전의 Android Studio를 사용 중인 경우 최신 버전으로 업데이트해보세요. 경우에 따라 최신 릴리스에서 버그와 문제가 수정됩니다. 또는 다운그레이드 해보세요.&lt;/li&gt;
&lt;li&gt;다른 장치 또는 에뮬레이터 사용해 보기: 경우에 따라 미리 보기가 특정 장치 또는 에뮬레이터에서 작동하지 않을 수 있습니다. 다른 기기나 에뮬레이터로 전환해 보고 미리보기가 작동하는지 확인하세요.&lt;/li&gt;
&lt;/ol&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;이 문제와 관련해서 JetBrain에 영어로 문의를 넣은 상태입니다. 빨리 해결이 되면 좋겠네요...&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>xml 프리뷰</category>
      <category>안드로이드스튜디오</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/247</guid>
      <comments>https://haruple.tistory.com/247#entry247comment</comments>
      <pubDate>Mon, 6 Mar 2023 22:03:51 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 대형 화면 플랫폼 최적화</title>
      <link>https://haruple.tistory.com/246</link>
      <description>&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;안드로이드는 화면 크기가 IOS에 비해 매우 다양합니다. 개발하는 회사도 삼성 뿐만 아니라 엄청나게 많은 안드로이드 스마트폰 제조사가 있고, 그에따라 아주 다양한 스마트폰의 비율이 존재합니다. 스마트폰의 화면 크기가 점점 커지고 있고 멀티 윈도우 멀티 디스플레이, PIP 모드를 비롯한 여러 디스플레이 모드를 지원합니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Tier 3(기본) &amp;mdash; 대형 화면 지원&lt;/b&gt;: 사용자가 중요한 흐름을 완료할 수 있지만 최적의 사용자 환경은 제공되지 않습니다. 앱이 전체 화면(또는 멀티 윈도우 모드에서 전체 창)을 실행하지만 앱 레이아웃이 이상적이지 않을 수 있습니다. 앱이 레터박스 처리되지 않으며 호환성 모드로 실행되지 않습니다 앱이 키보드, 마우스, 트랙패드를 포함한 외부 입력 장치를 기본적으로 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c14HGn/btr2gjiCQB1/2AI7MvvkMMiKg5Q5yVKVDk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c14HGn/btr2gjiCQB1/2AI7MvvkMMiKg5Q5yVKVDk/img.png&quot; data-alt=&quot;인스타그램&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c14HGn/btr2gjiCQB1/2AI7MvvkMMiKg5Q5yVKVDk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc14HGn%2Fbtr2gjiCQB1%2F2AI7MvvkMMiKg5Q5yVKVDk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;314&quot; height=&quot;392&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;인스타그램&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;인스타그램의 경우 Tier3도 지원하지 않게 되어있습니다. 인스타그램의 경우 사진이 폴드의 비율에 맞게 적용되면 사진만 화면에 꽉차버리는 문제가 발생합니다. 그래서 인스타그램은 양 사이드에 레터박스가 나타납니다. 이러한 특수한 이유가 있는게 아니라면 레터박스가 발생되지 않도록 개발해합니다.&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;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Tier 2(우수) &amp;mdash; 대형 화면 최적화&lt;/b&gt;: 앱이 모든 화면 크기 및 기기 구성에 맞게 레이아웃 최적화를 구현하며 외부 입력 장치에 관한 고급 지원을 제공합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nrauo/btr1YKPgWII/k7FjreYQK3O9rVZQScur10/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nrauo/btr1YKPgWII/k7FjreYQK3O9rVZQScur10/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nrauo/btr1YKPgWII/k7FjreYQK3O9rVZQScur10/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fnrauo%2Fbtr1YKPgWII%2Fk7FjreYQK3O9rVZQScur10%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;321&quot; height=&quot;401&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;Tier 1(최고) &amp;mdash; 대형 화면 차별화&lt;/b&gt;: 앱이 태블릿, 폴더블, ChromeOS용으로 설계된 사용자 환경을 제공합니다. 필요한 경우 앱은 멀티태스킹, 폴더블 상태, 드래그 앤 드롭, 스타일러스 입력을 지원합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/crV2uC/btr16iLqNKp/htw8S26v4vZ1QVphYn9kOk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/crV2uC/btr16iLqNKp/htw8S26v4vZ1QVphYn9kOk/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/crV2uC/btr16iLqNKp/htw8S26v4vZ1QVphYn9kOk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcrV2uC%2Fbtr16iLqNKp%2Fhtw8S26v4vZ1QVphYn9kOk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zoiE0/btr133tYMLx/36sPjBTsRwMFWKN4ARYkYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zoiE0/btr133tYMLx/36sPjBTsRwMFWKN4ARYkYK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-filename=&quot;111.png&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zoiE0/btr133tYMLx/36sPjBTsRwMFWKN4ARYkYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzoiE0%2Fbtr133tYMLx%2F36sPjBTsRwMFWKN4ARYkYK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삼성증권 앱과 카카오톡은 기존 바형 앱과 폴더블 앱의 UI가 다릅니다. 폴더블의 커다란 화면을 잘 이용할 수 있도록 분할 화면 지원을 제공합니다. 한번에 여러 정보를 볼 수 있어 유용한 UI입니다. 폴더블 유저까지 타겟팅 하는 앱을 개발하려면 폴더블 전용 Fragment를 만들어서 폴더블인 경우 해당 Fragment를 실행하도록 하는 방법으로 개발할 수 있습니다.&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;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;앱이 모든 Android 기기에서 우수한 사용자 환경을 제공할 수 있도록 하려면 Tier 2 요구사항을 충족해야 합니다. 대형 화면에서 앱을 돋보이게 하려면 Tier 1을 완료해야합니다.&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;아래는 참고한 안드로이드 공식 문서입니다.&lt;/span&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1678023983163&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;대형 화면 앱 품질 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;Android 기기는 화면 크기가 다양한 스마트폰, 태블릿, Chromebook, 폴더블 기기 등 여러 폼 팩터로 출시됩니다. Android는 멀티 윈도우, 멀티 디스플레이, 멀티 인스턴스, PIP 모드를 비롯한 여러 디스플&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/docs/quality-guidelines/large-screen-app-quality?hl=ko&quot; data-og-url=&quot;https://developer.android.com/docs/quality-guidelines/large-screen-app-quality?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/x65gG/hyRQrRDsL0/b1RAZM6L2YpxBBnyFv41aK/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/docs/quality-guidelines/large-screen-app-quality?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/docs/quality-guidelines/large-screen-app-quality?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/x65gG/hyRQrRDsL0/b1RAZM6L2YpxBBnyFv41aK/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&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;대형 화면 앱 품질 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Android 기기는 화면 크기가 다양한 스마트폰, 태블릿, Chromebook, 폴더블 기기 등 여러 폼 팩터로 출시됩니다. Android는 멀티 윈도우, 멀티 디스플레이, 멀티 인스턴스, PIP 모드를 비롯한 여러 디스플&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>개발/Android</category>
      <category>개발</category>
      <category>갤럭시 폴드</category>
      <category>대형 화면</category>
      <category>안드로이드</category>
      <category>폴더블 스마트폰</category>
      <category>화면 최적화</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/246</guid>
      <comments>https://haruple.tistory.com/246#entry246comment</comments>
      <pubDate>Sun, 5 Mar 2023 22:47:09 +0900</pubDate>
    </item>
    <item>
      <title>[kotlin] 안드로이드스튜디오 Activity에서 Activity 트랜지션 애니메이션 적용</title>
      <link>https://haruple.tistory.com/245</link>
      <description>&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;이전에 Fragment에서 Fragment로 이동할 때 복합 트랜지션 애니메이션을 개발했었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 Activity에서 Activity로 이동할 때 트랜지션 화면 전환 애니메이션을 개발해보겠습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1677934577331&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Kotlin] 안드로이드스튜디오 Fragment에서 Fragment 복합 트랜지션 (여러 애니메이션 동시 적용)&quot; data-og-description=&quot;안녕하세요, 하루플입니다. Activity에서 Activity로 화면을 전환을 할 때와 Fragment에서 Fragment로 전환할 때의 방법이 다릅니다. 해당 방법은 Fragment 전환에만 해당하는 방법입니다. 저는 위/아래로 움&quot; data-og-host=&quot;haruple.tistory.com&quot; data-og-source-url=&quot;https://haruple.tistory.com/244&quot; data-og-url=&quot;https://haruple.tistory.com/244&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/wmI3h/hyRQqduJgP/IsJWqgobEhUDkuSa9kTa0k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bzTWbV/hyRORjsC3p/gp0gdDVeqODng2x1B3ikU0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/grIRH/hyRQxcCjbx/jKVw0LubkFf6TGbogBkSwK/img.jpg?width=1279&amp;amp;height=1279&amp;amp;face=0_0_1279_1279&quot;&gt;&lt;a href=&quot;https://haruple.tistory.com/244&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://haruple.tistory.com/244&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/wmI3h/hyRQqduJgP/IsJWqgobEhUDkuSa9kTa0k/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bzTWbV/hyRORjsC3p/gp0gdDVeqODng2x1B3ikU0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/grIRH/hyRQxcCjbx/jKVw0LubkFf6TGbogBkSwK/img.jpg?width=1279&amp;amp;height=1279&amp;amp;face=0_0_1279_1279');&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;[Kotlin] 안드로이드스튜디오 Fragment에서 Fragment 복합 트랜지션 (여러 애니메이션 동시 적용)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;안녕하세요, 하루플입니다. Activity에서 Activity로 화면을 전환을 할 때와 Fragment에서 Fragment로 전환할 때의 방법이 다릅니다. 해당 방법은 Fragment 전환에만 해당하는 방법입니다. 저는 위/아래로 움&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;haruple.tistory.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;이전 Fragment에서는 &amp;lt;set/&amp;gt; 함수에 &amp;lt;objectAnimator/&amp;gt;를 사용해 복합 트랜지션(여러 애니메이션 동시 적용)을 개발했었습니다. 하지만 Activity의 &amp;lt;set/&amp;gt; 내부에 &lt;span&gt;&amp;lt;objectAnimator/&amp;gt;를 적용할 수 없어 복합 트랜지션을 적용할 수 없었습니다. 어쩔수없이 단일 애니메이션으로 개발을 했는데요, Activity 전환간에도 동시 애니메이션을 적용할 수 있는 방법을 아시는 분은 댓글로 알려주시면 감사드리겠습니다.&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&gt;단일 애니메이션 개발은 훨씬 간단해지는데요, 단순히 &amp;lt;alpha/&amp;gt; 함수만으로도 Fade in - out 표현이 가능해집니다.&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;size14&quot;&gt;&lt;b&gt;&lt;span&gt;transition_fade_in.xml&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677934824173&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    &amp;lt;alpha
        android:fromAlpha=&quot;0.0&quot;
        android:toAlpha=&quot;1.0&quot;
        android:fillAfter=&quot;true&quot;
        android:duration=&quot;250&quot;
        /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;&lt;span&gt;transition_fade_out.xml&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1677934852403&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    &amp;lt;alpha
        android:fromAlpha=&quot;1.0&quot;
        android:toAlpha=&quot;0.0&quot;
        android:duration=&quot;250&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&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;해당 함수에 intent만 넣으면 원하는 액티비티로 이동할 수 있도록 했습니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;fun changeActivity(intent: Intent) {
    startActivity(intent)
    overridePendingTransition(R.anim.transition_fade_in, R.anim.transition_fade_out)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;startActivitiy 뒤에 overridePenddingTranstion을 사용해 트랜지션 애니메이션을 적용할 수 있습니다.&lt;/p&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/245</guid>
      <comments>https://haruple.tistory.com/245#entry245comment</comments>
      <pubDate>Sun, 5 Mar 2023 11:07:06 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 안드로이드스튜디오 Fragment에서 Fragment 복합 트랜지션 (여러 애니메이션 동시 적용)</title>
      <link>https://haruple.tistory.com/244</link>
      <description>&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;Activity에서 Activity로 화면을 전환을 할 때와 Fragment에서 Fragment로 전환할 때의 방법이 다릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 방법은 Fragment 전환에만 해당하는 방법입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저는 &lt;u&gt;&lt;b&gt;위/아래로 움직이면서 동시에 Fade in / Fade out 되는 애니메이션을 적용&lt;/b&gt;&lt;/u&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;먼저 트랜지션 애니메이션을 적용하기 위한 xml을 만들어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;여러 애니메이션을 한번에 적용하기 위해서는 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&amp;lt;set/&amp;gt;&lt;/span&gt;&lt;/b&gt;으로 사용할 애니메이션을 묶어주어야 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;transition_fade_in.xml&lt;/p&gt;
&lt;pre id=&quot;code_1677933871470&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&amp;gt;

    &amp;lt;objectAnimator
        android:propertyName=&quot;translationY&quot;
        android:valueFrom=&quot;50&quot;
        android:valueTo=&quot;0&quot;
        android:duration=&quot;250&quot;
        android:startOffset=&quot;500&quot;
        android:interpolator=&quot;@android:anim/accelerate_decelerate_interpolator&quot;/&amp;gt;

    &amp;lt;objectAnimator
        android:propertyName=&quot;alpha&quot;
        android:valueFrom=&quot;0.0&quot;
        android:valueTo=&quot;0.0&quot;
        android:duration=&quot;250&quot;
      /&amp;gt;

    &amp;lt;objectAnimator
        android:propertyName=&quot;alpha&quot;
        android:valueFrom=&quot;0.0&quot;
        android:valueTo=&quot;1.0&quot;
        android:duration=&quot;250&quot;
        android:startOffset=&quot;500&quot;
        /&amp;gt;

&amp;lt;/set&amp;gt;&lt;/code&gt;&lt;/pre&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;size14&quot;&gt;transition_fade_out.xml&lt;/p&gt;
&lt;pre id=&quot;code_1677933906084&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&amp;gt;

    &amp;lt;objectAnimator
        android:propertyName=&quot;translationY&quot;
        android:valueFrom=&quot;0&quot;
        android:valueTo=&quot;50&quot;
        android:duration=&quot;250&quot;
        android:interpolator=&quot;@android:anim/accelerate_decelerate_interpolator&quot;/&amp;gt;

    &amp;lt;objectAnimator
        android:propertyName=&quot;alpha&quot;
        android:valueFrom=&quot;1.0&quot;
        android:valueTo=&quot;0.0&quot;
        android:duration=&quot;250&quot;
        /&amp;gt;

    &amp;lt;objectAnimator
        android:propertyName=&quot;alpha&quot;
        android:valueFrom=&quot;0.0&quot;
        android:valueTo=&quot;0.0&quot;
        android:duration=&quot;250&quot;
        android:startOffset=&quot;500&quot; /&amp;gt;

&amp;lt;/set&amp;gt;&lt;/code&gt;&lt;/pre&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;lt;alpha/&amp;gt; 를 사용해서 단순히 트랜지션을 적용할 수 있는 방법이 널리 쓰이고 있지만 복합적으로 여러 애니메이션을 동시에 적용할 수는 없습니다. 동시에 애니메이션을 사용하기 위해서는 &amp;lt;set/&amp;gt;을 사용 후 &amp;lt;objectAnimator/&amp;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;애니메이션 xml 코드를 생성한 후에 프래그먼트를 전환할 액티비티에 아래의 코드를 작성해줍니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677934172669&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    fun changeFragment(fragment: Fragment) {
        supportFragmentManager.beginTransaction().run { 
            setCustomAnimations(R.anim.frg_transition_fade_in, R.anim.frg_transition_fade_out, R.anim.frg_transition_fade_in, R.anim.frg_transition_fade_out)
            addToBackStack(supportFragmentManager.backStackEntryCount.toString())
            commit()
        }
    }&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;</description>
      <category>개발/Android</category>
      <category>kotlin</category>
      <category>안드로이드스튜디오</category>
      <category>애니메이션</category>
      <category>트랜지션</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/244</guid>
      <comments>https://haruple.tistory.com/244#entry244comment</comments>
      <pubDate>Sat, 4 Mar 2023 21:54:57 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 안드로이드스튜디오 BroadcastReceiver</title>
      <link>https://haruple.tistory.com/242</link>
      <description>&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;이전에 AlramManager에 대해서 알아보았습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AlramManger를 쓸 때 BroadcaseReceiver를 상속받은 클래스를 활용해야 스마트폰을 재부팅 했을 때나 앱이 종료된 상태에서도 알림을 받을 수 있습니다. 이 BroadcaseReceiver에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1677307216314&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class NotificationReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context?, intent: Intent?) {
        // Create a notification
        val notification = NotificationCompat.Builder(context!!, &quot;channel_id&quot;)
            .setContentTitle(&quot;Notification Title&quot;)
            .setContentText(&quot;Notification Text&quot;)
            .setSmallIcon(R.drawable.notification_icon)
            .setPriority(NotificationCompat.PRIORITY_DEFAULT)
            .build()

        // Show the notification
        val notificationManager =
            context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
        notificationManager.notify(0, notification)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 코드에서는 BreoadcaseReceiver를 확장하는 NotificationReceiver 라는 클래스를 만들었습니다. 이 클래스는 AlarmManager에 의해 알림 처리를 담당하게 됩니다.&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;onReceive() 함수는 BroadcaseReceiver가 Intent를 수신할 때 호출됩니다. 즉, 알림을 트리커 하는데 사용됩니다. 함수는 먼저 NotificationCompat.Builder 클래스를 사용하여 알림을 생성합니다. 알림에는 제목, 내용 및 작은 아이콘을 넣을 수 있습니다. 그리고 알림의 우선 순위를 PRIORITY_DEFAULT로 설정합니다.&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;알림을 만든 후 함수는 NotificationManager 클래스를 사용해 알림을 표시합니다. 알림에는 ID 0 을 할당했고 나중에 필요한 경우 이 ID 를 사용해 취소하는데 사용할 수 있습니다.&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;이제 Broadcast Receiver에 대해 자세히 살펴보겠습니다.&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;Broadcast Receiver는 애플리케이션이 시스템 전체의 브로드캐스트 알림을 수신하고 이에 응답할 수 있도록 하는 Android 구성 요소입니다. 브로드캐스트를 사용하여 사용자가 화면을 끄거나 배터리가 낮아지는 등 다양한 시스템 이벤트를 앱에 알릴 수 있습니다.&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;BroadcastReceiver가 Intent를 호출되는 onReceive() 함수를 재정의해서 원하는 기능을 수행할 수 있습니다. 인텐트에는 수행할 작업과 브로드 캐스트와 관련된 정보가 포함됩니다.&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;BroadcastReceiver를 사용하려면 매니페스트 파일에서 해당 클래스를 선언해야합니다. BroadcastReceiver는 다음과 같은 다양한 용도로 사용할 수 있습니다.&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;li&gt;수신한 SMS 메세지 또는 전화 통화&lt;/li&gt;
&lt;li&gt;AlramManager를 사용해 백그라운드 작업 트리거&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;&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>AlramManager</category>
      <category>BroadcastReceiver</category>
      <category>안드로이드스튜디오</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/242</guid>
      <comments>https://haruple.tistory.com/242#entry242comment</comments>
      <pubDate>Sun, 26 Feb 2023 17:08:34 +0900</pubDate>
    </item>
    <item>
      <title>[2월에 읽은 도서] 전쟁은 일어나지 않는다는 착각</title>
      <link>https://haruple.tistory.com/243</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;444&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ndyJl/btr0RQCbmbz/H6yeBgP4DrGOc1QgoVfks1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ndyJl/btr0RQCbmbz/H6yeBgP4DrGOc1QgoVfks1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ndyJl/btr0RQCbmbz/H6yeBgP4DrGOc1QgoVfks1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FndyJl%2Fbtr0RQCbmbz%2FH6yeBgP4DrGOc1QgoVfks1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;208&quot; height=&quot;308&quot; data-origin-width=&quot;300&quot; data-origin-height=&quot;444&quot;/&gt;&lt;/span&gt;&lt;/figure&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;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&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;p data-ke-size=&quot;size16&quot;&gt;공화주의적 민주 정부는 오직 시민의 권리를 보호하기 위해서만 힘과 권력을 사용한다. 민주 정부에서 전쟁 여부를 결정하려면 국민의 동의가 필요하다. 전쟁의 피해와 고통은 온전히 국민에게 가기 때문에 신중할 수밖에 없다.&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;/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;아프가니스탄 전쟁이 20년 만에 허망하게 끝났다. 아프가니스탄 정부는 이슬람 무장 조직 탈레반에 항복하고, 아슈라프 가니 대통령은 카불이 함락되기도 전에 사퇴하고 다른 나라로 도망갔다. 이런 나라를 과연 국가라고 할 수 있는가?&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;/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;전쟁은 의도하지 않게 새로운 역사적 인물을 만들어낸다. 볼로디미르 젤렌스키가 우크라이나 대통령이 아니었다면 러시아의 우크라이나 침공은 현재와 같은 방식으로 진행되지 않았을 것이다. 우크라이나에 대한 그의 책임과 용기는 자신에게 철수를 제안한 미국 정보 관리들에게 &amp;ldquo;나는 탈 것이 아니라 탄약이 필요하다&amp;rdquo;라고 말한데서 잘 드러난다. 우크라이나 전쟁이 어떻게 끝날지는 미지수이지만, 젤렌스키의 등장이 전쟁의 성격과 과정을 규정했음을 부인할 수는 없다.&lt;/p&gt;</description>
      <category>일상/일상</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/243</guid>
      <comments>https://haruple.tistory.com/243#entry243comment</comments>
      <pubDate>Sun, 26 Feb 2023 00:00:27 +0900</pubDate>
    </item>
    <item>
      <title>[Kotlin] 안드로이드스튜디오 AlramManager 기능 및 사용방법</title>
      <link>https://haruple.tistory.com/241</link>
      <description>&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;Android 플랫폼은 AlramManager API를 포함해 백그라운드 작업을 관리하기 위한 여러 API를 제공합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번에는 AlramManger API를 이용해 백그라운드 작업을 예약하고 실행하는데 사용할&amp;nbsp; 수 있는 방법을 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;AlramManager&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AlramManager API는 개발자가 애플리케이션에서 백그라운드 작업을 예약하고 실행할 수 있도록 하는 Android 플랫폼의 구성 요소입니다. 특정 간격 또는 특정 시간에 작업을 예약하고 실행하는 간단하고 효율적인 방법을 제공합니다. 새 데이터 또는 알림 확인, 정기 유지 관리작업 수행, 백그라운드 서비스 실행 등 다양한 작업을 수행할 수 있습니다.&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;AlramManager API의 가장 일반적으로 사용되는 내장 기능 중 일부입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;set()&lt;/b&gt;&lt;/span&gt; : 특정 시간 또는 특정 간격 후에 실행될 작업을 예약하는 데 사용합니다. 개발자는 set() 함수를 사용하기 위해 알람의 종류, 알람이 발생해야 하는 시간, 알람이 발생할 때 실행한 PendingIntent를 인자 값으로 제공해야 합니다.&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;span style=&quot;background-color: #f6e199;&quot;&gt;setRepeating()&lt;/span&gt;&lt;/b&gt; : 특정 간격으로 실행할 작업을 예약하는데 사용됩니다. 알람의 종류, 알람이 발생해야 하는 간격, 알람이 처음 발생해야 하는 시간, 알람 발생 시 실행한 PendingIntent를 제공해야 합니다. 정확한 시간에 알람이 울려야 하는 경우 사용합니다.&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;span style=&quot;background-color: #f6e199;&quot;&gt;setInexactRepeating()&lt;/span&gt;&lt;/b&gt; : setRepeating 함수와 유사하지만 시스템이 알람의 정확한 타이밍을 조정해 시스템 리소스를 최적화 할 수 있습니다. (배터리 타임 최적화 등)&amp;nbsp; 인자 값은 setRepeating과 동일하게 제공하면 됩니다. 정확한 시간에 알람이 울리지 않을 수 있지만 시슨템 최적화를 위해 안드로이드에서 권장하는 방법입니다.&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;background-color: #f6e199;&quot;&gt;&lt;b&gt;cancel()&lt;/b&gt;&lt;/span&gt; : 이전에 예약된 알람을 취소하는데 사용합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 예시에서는 NotificationReceiver와 Menifest 작성에 대해서는 생략하였습니다. 단순히 AlramManager의 기능을 알아보기 위한 포스팅입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1) 특정 시간에 실행되도록 작업 예약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;set() 함수를 사용해 특정 시간에 실행될 작업을 예약합니다. 작업은 지정된 시간에 사용자에게 알림을 표시합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677303391746&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val notificationIntent = Intent(this, NotificationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, 0)
val currentTime = System.currentTimeMillis()
val triggerTime = currentTime + 10000 //알림 작동 시간 테스트로 10초 후로 지정
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.set(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;알람이 실행되어야 하는 시간을 계산하고(예시에서는 10초 후) AlramManger의 인스턴스를 가져옵니다. 마지막에 set() 함수를 사용해 지정된 시간에 알람이 울리도록 예약합니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;2) 특정 간격으로 실행되도록 작업 예약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setRepeating()함수를 사용하여 특정 간격으로 실행될 작업을 예약합니다. 작업은 30분 마다 사용자에게 알림을 표시합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677303593109&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val notificationIntent = Intent(this, NotificationReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, notificationIntent, 0)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setRepeating(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis(),
    AlarmManager.INTERVAL_HALF_HOUR,
    pendingIntent
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setReapeating의 AlramManager.INTERVAL_HALF_HOUR를 수정해 원하는 시간마다 알림을 표시하도록 수정할 수 있습니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;3) 부정확한 간격으로 실행되도록 작업 예약&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setInexactRapeating() 함수를 사용해 부정확한 간격으로 실행되도록 작업을 예약할 수 있습니다. 작업은 네트워크 호출을 수행해 6시간마다 새 데이터를 확인합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1677303716908&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val networkIntent = Intent(this, NetworkReceiver::class.java)
val pendingIntent = PendingIntent.getBroadcast(this, 0, networkIntent, 0)
val alarmManager = getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmManager.setInexactRepeating(
    AlarmManager.RTC_WAKEUP,
    System.currentTimeMillis(),
    AlarmManager.INTERVAL_HALF_DAY,
    pendingIntent
)&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AlramMangerAPI의 기능 및 Android에서 백그라운드 작업을 예약하고 실행하는 데 사용할 수 있는 방법을 살펴보았습니다. 새로운 데이터를 확인하든, 정기적인 유지 관리 작업을 수행하든 백그라운드 서비스를 실행하든 관계 없이 AlramManager API를 사용하면 이러한 작업을 쉽게 관리하고 실행할 수 있습니다.&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;figure id=&quot;og_1677303161588&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;반복 알람 예약 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;반복 알람 예약 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 알람(AlarmManager 클래스 기반)을 사용하면 애플리케이션이 사용되지 않을 때 시간 기반 작업을&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/training/scheduling/alarms?hl=ko&quot; data-og-url=&quot;https://developer.android.com/training/scheduling/alarms?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/iMYY3/hyRJRKGQhl/bl3yglCyIF5iy0HbAuRMjk/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/training/scheduling/alarms?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/training/scheduling/alarms?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/iMYY3/hyRJRKGQhl/bl3yglCyIF5iy0HbAuRMjk/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&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;반복 알람 예약 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;반복 알람 예약 컬렉션을 사용해 정리하기 내 환경설정을 기준으로 콘텐츠를 저장하고 분류하세요. 알람(AlarmManager 클래스 기반)을 사용하면 애플리케이션이 사용되지 않을 때 시간 기반 작업을&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/241</guid>
      <comments>https://haruple.tistory.com/241#entry241comment</comments>
      <pubDate>Sat, 25 Feb 2023 14:44:21 +0900</pubDate>
    </item>
    <item>
      <title>이펙티브 코틀린 : 예외를 활용해 코드에 제한을 걸어라</title>
      <link>https://haruple.tistory.com/240</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;예외를 활용해 코드에 제한을 걸어라&lt;/b&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;li&gt;문제가 있을 경우 함수가 예상하지 못한 동작을 하지 않고 예외를 throw 한다. 예상하지 못한 동작을 하는건 예외를 throw하는 것보다 굉장히 위험하며, 상태를 관리하는 것이 굉장히 힘들다.&lt;/li&gt;
&lt;li&gt;Argument
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 제한 걸때는 argument를 사용한다.&lt;/li&gt;
&lt;li&gt;require함수로 제한을 확인하고 제한을 만족하지 못할 경우 예외를 throw 한다.&lt;/li&gt;
&lt;li&gt;require 함수는 조건을 만족하지 못할 때 무조건 IllegalArgument Exception을 발생시키므로 제한을 무시할 수 없다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;check
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;check 함수는 require과 비슷하지만 지정된 예측을 만족하지 못할 때 IllegalStateException을 throw 한다.&lt;/li&gt;
&lt;li&gt;상태가 올바른지 확인할 때 사용한다.&lt;/li&gt;
&lt;li&gt;사용자가 코드를 제대로 사용할거라고 믿고 있는 것 보다는 항상 문제 상황을 예측하고, 문제 상황에 예외를 throw하는 것이 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;assert
&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;assert함수는 프로덕션 환경에서는 오류가 발생하지 않고 테스트 할 때만 활성화 되므로 오류가 발생해도 사용자가 알아차릴 수 없다.&lt;/li&gt;
&lt;li&gt;이 코드가 정말 심각한 오류라면 check 함수를 사용하는게 좋다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;결과 부족이 발생할 경우 Null과 Failure를 사용해라&lt;/b&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;이럴 때 null 또는 Failure를 리턴하거나 예외를 throw 한다.&lt;/li&gt;
&lt;li&gt;여기서 예외를 throw 하는 방법은 좋지 않다. 예외는 정보를 전달하는 방법으로 사용해서는 안된다. 잘못된 특별한 상황을 나타내야 한다.&lt;/li&gt;
&lt;li&gt;충분히 예측할 수 있는 범위의 오류는 null 과 failure를 사용하고, 예측하기 어려운 예외적인 범위의 오류는 예외를 throw 해서 처리하는게 좋다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/240</guid>
      <comments>https://haruple.tistory.com/240#entry240comment</comments>
      <pubDate>Sun, 19 Feb 2023 23:59:13 +0900</pubDate>
    </item>
    <item>
      <title>이펙티브 코틀린 : 변수의 스코프를 최소화하라</title>
      <link>https://haruple.tistory.com/239</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;변수의 스코프를 최소화하라&lt;/b&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;li&gt;스코프를 좁게 만드는 이유 : 프로그램을 추적하고 관리하기 쉽기 때문&lt;/li&gt;
&lt;li&gt;스코프 범위가 너무 넓으면 다른 개발자에 의해 변수가 잘못 사용될 수도 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;최대한 플랫폼 타입을 사용하지 말라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코틀린에서는 null safety 메커니즘이 있지만 C, 자바와 같이 없는 언어와 연결해서 사용할 때는 이런 예외가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;코틀린은 자바 등 다른 언어에서 넘어온 nullable 여부를 알 수 없는 타입을 &amp;lsquo;플랫폼 타입&amp;rsquo; 이라고 한다.&lt;/li&gt;
&lt;li&gt;자바를 코틀린과 함께 사용할 때 가능한 @Nullable 과 @NotNull 어노테이션을 붙여서 사용한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;inferred 타입으로 리턴하지 말라&lt;/b&gt;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;타입 추론 (type inference)는 코틀린의 특징이다.&lt;/li&gt;
&lt;li&gt;타입을 확실하게 지정해야 하는 경우에는 굉장히 중요한 정보이므로 숨기지 않는 것이 좋다.&lt;/li&gt;
&lt;li&gt;안전을 위해 외부 API를 만들 때는 반드시 타입을 지정해야한다.&lt;/li&gt;
&lt;li&gt;val DEFAULT_CAR = Fialt126P() 이렇게 inferred 타입으로 리턴하면 제한이 너무 많아지거나 예측하지 못한 결과를 낼 수 있다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/239</guid>
      <comments>https://haruple.tistory.com/239#entry239comment</comments>
      <pubDate>Sat, 18 Feb 2023 21:00:04 +0900</pubDate>
    </item>
    <item>
      <title>이펙티브 코틀린 : 1부 좋은 코드</title>
      <link>https://haruple.tistory.com/238</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;가변성을 제한하라&lt;/b&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;li&gt;var 가변성이 있으면 코드의 실행을 추론하기 어려워진다.&lt;/li&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;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코틀린은 읽기전용 프로퍼티 val을 사용해 가변성을 제한할 수 있다.&lt;/li&gt;
&lt;li&gt;다만, mutable 객체라면 내부적으로 변할 수 있다.&lt;/li&gt;
&lt;li&gt;val 이 읽기전용 프로퍼티이지만 불변(immutable)을 의미하진 않는다.&lt;/li&gt;
&lt;li&gt;완전히 변경할 필요가 없는 변수라면 final을 활용하자.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;읽기 전용 : Iterable, Collection, Set, List&lt;/li&gt;
&lt;li&gt;읽기쓰기 : MutableIterable, MutableCollection, MutableSet, MutableList&lt;/li&gt;
&lt;li&gt;읽기 전용에서 mutable로 변경해야 한다면, 복제(copy)를 통해서 새로운 mutable 컬렉션을 만드는 list.toMutableList를 활용해야한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Delegates.observable을 사용하면 변경이 있을 때 감지할 수 있다.&lt;/li&gt;
&lt;li&gt;var list = mutableList&amp;lt;Int&amp;gt;() 이렇게 두 지점에 모두 가변성을 주는건 좋지 않다. 두 지점에 대한 동기화를 모두 구현해야하고, 모호성이 발생해 +-를 사용할 수 없다.&lt;/li&gt;
&lt;li&gt;상태를 나타내는 mutable 객체를 외부에 노출하는 것은 위험하다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/238</guid>
      <comments>https://haruple.tistory.com/238#entry238comment</comments>
      <pubDate>Mon, 6 Feb 2023 22:37:30 +0900</pubDate>
    </item>
    <item>
      <title>[1월에 읽은 도서] 주택청약의 모든 것</title>
      <link>https://haruple.tistory.com/237</link>
      <description>&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;회사에서 챌린지를 하나 진행하는데 그 중 하나가 매달 책 1권 읽기입니다!&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;백날 부동산 경매니 시세 차익이니 봐도 내가 당장 실행을 못하기때문에.. 그냥 그렇구나 하고 넘어갔어요ㅜ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cajcEZ/btrXqtj6rkF/xkXKIsjsHQpzejcaXeczwK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cajcEZ/btrXqtj6rkF/xkXKIsjsHQpzejcaXeczwK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cajcEZ/btrXqtj6rkF/xkXKIsjsHQpzejcaXeczwK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcajcEZ%2FbtrXqtj6rkF%2FxkXKIsjsHQpzejcaXeczwK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bCg1Pz/btrXrUoe0jf/WUPzKHklSiqn9kRTDjtR5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bCg1Pz/btrXrUoe0jf/WUPzKHklSiqn9kRTDjtR5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bCg1Pz/btrXrUoe0jf/WUPzKHklSiqn9kRTDjtR5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbCg1Pz%2FbtrXrUoe0jf%2FWUPzKHklSiqn9kRTDjtR5K%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/figure&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;&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;h2 data-ke-size=&quot;size26&quot;&gt;생애최초 특별공급&lt;/h2&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;신청 자격&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 과거 주택 소유x&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 근로자 또는 자영업자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;- 5개년 이상 소득세 납부&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cXMoFc/btrXoB3Z3IK/7PpK0iT9C7daq2jjQDKtc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cXMoFc/btrXoB3Z3IK/7PpK0iT9C7daq2jjQDKtc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cXMoFc/btrXoB3Z3IK/7PpK0iT9C7daq2jjQDKtc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcXMoFc%2FbtrXoB3Z3IK%2F7PpK0iT9C7daq2jjQDKtc1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;4000&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;4000&quot;/&gt;&lt;/span&gt;&lt;/figure&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>일상/일상</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/237</guid>
      <comments>https://haruple.tistory.com/237#entry237comment</comments>
      <pubDate>Mon, 30 Jan 2023 20:22:34 +0900</pubDate>
    </item>
    <item>
      <title>[Android] TextInputEditText의 Error 메세지 작업</title>
      <link>https://haruple.tistory.com/236</link>
      <description>&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;구글 material 라이브러리의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;TextInputEditText&lt;/b&gt;&lt;/span&gt;로 작업중인데 에러 메세지를 띄우는데 문제가 있었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_Photo_2023-01-29-21-19-57 003.jpeg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1114&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WKuWN/btrXnk9GnpZ/sDGKWtu84Aq0V70CMhZki0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WKuWN/btrXnk9GnpZ/sDGKWtu84Aq0V70CMhZki0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WKuWN/btrXnk9GnpZ/sDGKWtu84Aq0V70CMhZki0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWKuWN%2FbtrXnk9GnpZ%2FsDGKWtu84Aq0V70CMhZki0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;311&quot; height=&quot;321&quot; data-filename=&quot;edited_KakaoTalk_Photo_2023-01-29-21-19-57 003.jpeg&quot; data-origin-width=&quot;1080&quot; data-origin-height=&quot;1114&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 TextInputEditText에 에러를 설정해보았습니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;binding.etNickName.error = &quot;자음과 모음을 조합해주세요&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그러자&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_Photo_2023-01-29-21-19-57 002.jpeg&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;1123&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/tKlWP/btrXrUBG1TD/IszDTWOmV8kQV1bLraajP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/tKlWP/btrXrUBG1TD/IszDTWOmV8kQV1bLraajP1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/tKlWP/btrXrUBG1TD/IszDTWOmV8kQV1bLraajP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FtKlWP%2FbtrXrUBG1TD%2FIszDTWOmV8kQV1bLraajP1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;293&quot; height=&quot;308&quot; data-filename=&quot;edited_KakaoTalk_Photo_2023-01-29-21-19-57 002.jpeg&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;1123&quot;/&gt;&lt;/span&gt;&lt;/figure&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;너무 무서워보이는 절대 입력해서는 안될것같은 무시무시한 UI가 출력되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;저정도의 UI를 바란게 아니라 하단에서 밑으로 에러메세지가 출력 되는게 일반적인 UI인데 왜저러나 하고 계속 서치해봤습니다.&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;TextInputEditText에 error를 적용하면 안되고 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;TextInputLayout에 적용&lt;/b&gt;&lt;/span&gt;해야합니다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;binding.textInputLayout.error = &quot;자음과 모음을 조합해주세요&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_KakaoTalk_Photo_2023-01-29-21-19-57 001.jpeg&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;1077&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxluKt/btrXtScAKbD/ZfG2aK0RyM0oC1IT10Klp1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxluKt/btrXtScAKbD/ZfG2aK0RyM0oC1IT10Klp1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxluKt/btrXtScAKbD/ZfG2aK0RyM0oC1IT10Klp1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxluKt%2FbtrXtScAKbD%2FZfG2aK0RyM0oC1IT10Klp1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;286&quot; height=&quot;289&quot; data-filename=&quot;edited_KakaoTalk_Photo_2023-01-29-21-19-57 001.jpeg&quot; data-origin-width=&quot;1067&quot; data-origin-height=&quot;1077&quot;/&gt;&lt;/span&gt;&lt;/figure&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;오늘은 연속 10시간째 코딩중인데 중간에 머리좀 식혀야할듯..!&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>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/236</guid>
      <comments>https://haruple.tistory.com/236#entry236comment</comments>
      <pubDate>Sun, 29 Jan 2023 21:28:44 +0900</pubDate>
    </item>
    <item>
      <title>[Android] 카카오 로그인을 구현하면서 경험한 시행착오</title>
      <link>https://haruple.tistory.com/235</link>
      <description>&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카카오 로그인 구현 과정은 아래 블로그에서 자세히 설명해두셔서 참고해서 구현했습니다.&lt;/p&gt;
&lt;figure id=&quot;og_1674914595644&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Kotlin] 코틀린으로 카카오 로그인 연동해보기(API v2)&quot; data-og-description=&quot;Kakao Login API v2 연동&quot; data-og-host=&quot;kdjun97.github.io&quot; data-og-source-url=&quot;https://kdjun97.github.io/kotlin/kotlin-kakao-login/&quot; data-og-url=&quot;https://kdjun97.github.io/kotlin/kotlin-kakao-login/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/YCqIo/hyRpMwpBGG/2SwjAUDaZL4elq3ThaBS70/img.png?width=1228&amp;amp;height=834&amp;amp;face=0_0_1228_834,https://scrap.kakaocdn.net/dn/X6jzC/hyRq4oEMEi/t8hoDtNO2c28fhpkiWnbrK/img.png?width=670&amp;amp;height=713&amp;amp;face=0_0_670_713,https://scrap.kakaocdn.net/dn/c5AXYP/hyRpD7hKRF/BFKvrnw8bip5x2AvBZY6K0/img.png?width=659&amp;amp;height=673&amp;amp;face=0_0_659_673&quot;&gt;&lt;a href=&quot;https://kdjun97.github.io/kotlin/kotlin-kakao-login/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://kdjun97.github.io/kotlin/kotlin-kakao-login/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/YCqIo/hyRpMwpBGG/2SwjAUDaZL4elq3ThaBS70/img.png?width=1228&amp;amp;height=834&amp;amp;face=0_0_1228_834,https://scrap.kakaocdn.net/dn/X6jzC/hyRq4oEMEi/t8hoDtNO2c28fhpkiWnbrK/img.png?width=670&amp;amp;height=713&amp;amp;face=0_0_670_713,https://scrap.kakaocdn.net/dn/c5AXYP/hyRpD7hKRF/BFKvrnw8bip5x2AvBZY6K0/img.png?width=659&amp;amp;height=673&amp;amp;face=0_0_659_673');&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;[Kotlin] 코틀린으로 카카오 로그인 연동해보기(API v2)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Kakao Login API v2 연동&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;kdjun97.github.io&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;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;1. 카카오 이메일 필수동의 권한 어디로?!&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파이어베이스 로그인할 때 필수적으로 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;이메일ID&lt;/b&gt;&lt;/span&gt;가 필요한데, &lt;u&gt;카카오 API에서 필수 동의 기능을 제공하지 않고 있었습니다.&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;702&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baJsci/btrXon5cJjB/iYdXIazeM3hzcfzu4KwkMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baJsci/btrXon5cJjB/iYdXIazeM3hzcfzu4KwkMk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baJsci/btrXon5cJjB/iYdXIazeM3hzcfzu4KwkMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaJsci%2FbtrXon5cJjB%2FiYdXIazeM3hzcfzu4KwkMk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;391&quot; height=&quot;258&quot; data-origin-width=&quot;1062&quot; data-origin-height=&quot;702&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;선택동의면 사용자가 혹시 이메일ID를 제공하지 않음에 체크한다면 회원가입을 진행할 수가 없습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;594&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EsQ4y/btrXnKmhVku/368kzYGOxgpTh7ZA2PGXC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EsQ4y/btrXnKmhVku/368kzYGOxgpTh7ZA2PGXC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EsQ4y/btrXnKmhVku/368kzYGOxgpTh7ZA2PGXC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEsQ4y%2FbtrXnKmhVku%2F368kzYGOxgpTh7ZA2PGXC0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;297&quot; height=&quot;304&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;594&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필수 동의 권한을 얻으려면 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;비즈니스 계정 등록&lt;/b&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;/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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1850&quot; data-origin-height=&quot;890&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JXKK8/btrXmJIrk83/i29X8EjvoJ5wroMzSicvc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JXKK8/btrXmJIrk83/i29X8EjvoJ5wroMzSicvc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JXKK8/btrXmJIrk83/i29X8EjvoJ5wroMzSicvc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FJXKK8%2FbtrXmJIrk83%2Fi29X8EjvoJ5wroMzSicvc1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1850&quot; height=&quot;890&quot; data-origin-width=&quot;1850&quot; data-origin-height=&quot;890&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 개인 개발자 비즈 앱 전환을 누르고 진행하면 됩니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;2.&amp;nbsp; Gladle 의존성 그냥 IDE로 편하게 넣자&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글이 Firebase 개발자 문서를 업데이트 하지 않아서인지 문서에 있는 코드로 dependencies를 넣으면 에러가 계속 발생했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1674957724779&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private lateinit var auth : FirebaseAuth
auth = FirebaseAuth.getInstance()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적으로 FirebaseAuth를 초기화하는데서 의존성이 잘못되었다는 에러 코드가 자꾸 발생하네요. 그 외에도 여러 에러가 발생..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수기로 의존성을 넣지말고 IDE의 힘을 빌리니 쉽게 해결되었습니다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;1014&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/exI43B/btrXtRYJkqj/MwKpQplVsFck8HMHFEX0c0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/exI43B/btrXtRYJkqj/MwKpQplVsFck8HMHFEX0c0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/exI43B/btrXtRYJkqj/MwKpQplVsFck8HMHFEX0c0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FexI43B%2FbtrXtRYJkqj%2FMwKpQplVsFck8HMHFEX0c0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;254&quot; height=&quot;453&quot; data-origin-width=&quot;568&quot; data-origin-height=&quot;1014&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;Tools - Firebase - Authentication - email, password 뭐시기 저시기 클릭&lt;/b&gt;&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;1604&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bXJRS7/btrXoocab2K/OODm7M20YCoVfMne5GZKC1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bXJRS7/btrXoocab2K/OODm7M20YCoVfMne5GZKC1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bXJRS7/btrXoocab2K/OODm7M20YCoVfMne5GZKC1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbXJRS7%2FbtrXoocab2K%2FOODm7M20YCoVfMne5GZKC1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;543&quot; height=&quot;668&quot; data-origin-width=&quot;1304&quot; data-origin-height=&quot;1604&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 나온 설명대로 Connect 누르고, 인증 SDK 넣으면 바로 해결됩니다!&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;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Android</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/235</guid>
      <comments>https://haruple.tistory.com/235#entry235comment</comments>
      <pubDate>Sun, 29 Jan 2023 11:02:31 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시 S23 시리즈 유출 (출시일, 디자인, 카메라, 성능, 가격)</title>
      <link>https://haruple.tistory.com/234</link>
      <description>&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;여러 해외 매체들을 통해서 곧 출시되는 갤럭시 S23의 정보들이 거의 유출되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;언팩 날짜도 이미 정해졌는데 한국 날짜로 &lt;b&gt;2022년 2월 2일 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;삼성 갤럭시 언팩 2023&lt;/span&gt;&lt;/b&gt;을 통해 공개될 예정입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cEFUXs/btrWSvqoT08/aThpw0EHblz6tUs26KFWtk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cEFUXs/btrWSvqoT08/aThpw0EHblz6tUs26KFWtk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cEFUXs/btrWSvqoT08/aThpw0EHblz6tUs26KFWtk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcEFUXs%2FbtrWSvqoT08%2FaThpw0EHblz6tUs26KFWtk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;341&quot; data-origin-width=&quot;1348&quot; data-origin-height=&quot;650&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;네이버에 이미 사전판매 알림신청까지 떴고, 유출된 기기와 오피셜로 뜬 저 카메라 모양이 동일한거로 봐서 유출 사진과 동일하게 나올 가능성이 매우 높아 보입니다. 삼성놈들 몇년전부터 계속 유출되던데.. 보안이 어떻게 된건지... &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qXzDb/btrW569I7VX/UxEGIfd9PaUaobstn8nEh1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qXzDb/btrW569I7VX/UxEGIfd9PaUaobstn8nEh1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qXzDb/btrW569I7VX/UxEGIfd9PaUaobstn8nEh1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqXzDb%2FbtrW569I7VX%2FUxEGIfd9PaUaobstn8nEh1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;1184&quot; height=&quot;592&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kxxKB/btrWU7vv5a5/0OK8PdWBeeJ8HRBjb7mK01/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kxxKB/btrWU7vv5a5/0OK8PdWBeeJ8HRBjb7mK01/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kxxKB/btrWU7vv5a5/0OK8PdWBeeJ8HRBjb7mK01/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkxxKB%2FbtrWU7vv5a5%2F0OK8PdWBeeJ8HRBjb7mK01%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;1184&quot; height=&quot;592&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;592&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/89led/btrWXjbna2r/q0pZ88taar6K4wgfBCGfa1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/89led/btrWXjbna2r/q0pZ88taar6K4wgfBCGfa1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/89led/btrWXjbna2r/q0pZ88taar6K4wgfBCGfa1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F89led%2FbtrWXjbna2r%2Fq0pZ88taar6K4wgfBCGfa1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;1184&quot; height=&quot;592&quot; data-origin-width=&quot;1184&quot; data-origin-height=&quot;592&quot;/&gt;&lt;/span&gt;&lt;/figure&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;울트라 모델은 전작이랑 디자인이 동일하고, 일반 S23, S23+ 모델만 이전 컨투어컷 카메라 디자인에서 카메라 섬이 없어졌습니다.&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;1788&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/rAwcz/btrW3803iDT/TsZWoROPT4ELE2l6Vk4Snk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rAwcz/btrW3803iDT/TsZWoROPT4ELE2l6Vk4Snk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rAwcz/btrW3803iDT/TsZWoROPT4ELE2l6Vk4Snk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FrAwcz%2FbtrW3803iDT%2FTsZWoROPT4ELE2l6Vk4Snk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;451&quot; height=&quot;738&quot; data-origin-width=&quot;1092&quot; data-origin-height=&quot;1788&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;울트라 모델 한정으로 2억 화소 카메라&lt;/b&gt;&lt;/span&gt;가 들어간다고 합니다. Ice universe에서 유출한 2억화소로 찍고 12배 확대한 사진인데 엄청 선명해보입니다! 다른 경쟁사들도 센서 사이즈를 많이 키워서 갤럭시 카메라를 많이 따라잡았었는데 이번에 갤럭시가 얼마나 격차를 벌려낼지 기대되네요! 폴드에도 &lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;2억화소 카메라가&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;그리고 야간 촬영과 달 사진 촬영 성능 개선을 예고하는 갤럭시 언팩 2023 티저가 공개되었습니다.&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;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;youtube&quot; data-video-url=&quot;https://www.youtube.com/watch?v=ia2eRkRqMXM&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/beBnZh/hyRoHtixP0/Y4d1IvB8FrbNMmenExCXk1/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=0_0_1280_720&quot; data-video-width=&quot;860&quot; data-video-height=&quot;484&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;484&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;iframe src=&quot;https://www.youtube.com/embed/ia2eRkRqMXM&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;갤럭시 언팩 2023 티저&lt;/figcaption&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Snapdragon 8 Gen 2&lt;/b&gt;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 스냅드래곤 성능 유출된게 A16 칩셋과 멀티코어 부분에서 비슷하고 그래픽에서는 더 높은 점수로 나왔습니다. 이번 작에서는 성능, 발열, 배터리 모두 진짜 기대해도 좋을수도..? 엑시노스를 이번에 탑재하지 않아서 정말 다행입니다!&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&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OLYvv/btrWS1QcbIt/vKjNKCC25wh9kNXexxKkjK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OLYvv/btrWS1QcbIt/vKjNKCC25wh9kNXexxKkjK/img.webp&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1280&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OLYvv/btrWS1QcbIt/vKjNKCC25wh9kNXexxKkjK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOLYvv%2FbtrWS1QcbIt%2FvKjNKCC25wh9kNXexxKkjK%2Fimg.webp&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; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uwqT1/btrWR8hGJ3K/R3C5tEpboLvI5jIgAtKaHK/img.webp&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uwqT1/btrWR8hGJ3K/R3C5tEpboLvI5jIgAtKaHK/img.webp&quot; data-origin-width=&quot;720&quot; data-origin-height=&quot;1280&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uwqT1/btrWR8hGJ3K/R3C5tEpboLvI5jIgAtKaHK/img.webp&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuwqT1%2FbtrWR8hGJ3K%2FR3C5tEpboLvI5jIgAtKaHK%2Fimg.webp&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; loading=&quot;lazy&quot; width=&quot;720&quot; height=&quot;1280&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&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;b&gt;갤럭시 S23 : 115만 5000원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;갤럭시 S23+ : 136만 3000원&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;갤럭시 S23 울트라 : 159만 4000원&lt;/b&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;원자재 가격 상승과 스냅드래곤8 Gen2 칩셋의 가격 상승 때문에 가격을 전작보다 15만원이나 높게 받는다고 하네요.. 아쉽지만 성능이 아이폰 13, 14 급으로 받쳐준다면야 지불할 가치가 있는 것 같습니다.&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;그리고 내년 S24부터는 플러스 모델이 단종될 수도 있다는 소식이 들려오고 있는데.. 중간 모델이 잘 팔리지 않아서 그런거 같긴 합니다. 아이폰도 일반 모델과 프로모델은 잘 팔리는데 플러스 모델이 유독 안팔려서 최근에 30~40% 생산량을 줄인다고 하네요.&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;저는 앞으로도 계속 폴드를 쓸 예정이라 이번 모델 패스하고 8월까지 기다려보겠습니다!&lt;/p&gt;</description>
      <category>일상/전자제품</category>
      <category>2억화소</category>
      <category>갤럭시 S23</category>
      <category>갤럭시 언팩 2023</category>
      <category>삼성</category>
      <category>스냅드래곤8 Gen2</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/234</guid>
      <comments>https://haruple.tistory.com/234#entry234comment</comments>
      <pubDate>Tue, 24 Jan 2023 19:27:05 +0900</pubDate>
    </item>
    <item>
      <title>[Android] CollapsingToolbarLayout, ViewPager2를 함께 사용시 스크롤 이슈 해결방법</title>
      <link>https://haruple.tistory.com/233</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;앱을 개발하다가 구글 meterial 라이브러리 중 CollapsingToolbarLayout을 사용했다.&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;CoordinatorLayout 내부에 상단에 쓸 AppBarLayout 을 쓰고 그 하단에 뷰가 보일 페이지를 구성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나는 &lt;b&gt;하단에 ViewPager2&lt;/b&gt; 를 사용하였기 때문에 내부를 NestedScrollView로 감싸고, 그 NestedScrollView에&amp;nbsp; behavior 옵션을 지정했었다.&lt;/p&gt;
&lt;pre class=&quot;avrasm&quot;&gt;&lt;code&gt;app:layout_behavior=&quot;@string/appbar_scrolling_view_behavior&quot;&lt;/code&gt;&lt;/pre&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;u&gt;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;스크롤에 이슈&lt;/b&gt;&lt;/span&gt;&lt;/u&gt;가 생겼다.&lt;/p&gt;
&lt;pre id=&quot;code_1674110418186&quot; class=&quot;stylus&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;androidx.coordinatorlayout.widget.CoordinatorLayout&amp;gt;

	 &amp;lt;com.google.android.material.appbar.AppBarLayout&amp;gt;
     
     	&amp;lt;com.google.android.material.appbar.CollapsingToolbarLayout&amp;gt;
        
         &amp;lt;/com.google.android.material.appbar.CollapsingToolbarLayout&amp;gt;
         
     &amp;lt;/com.google.android.material.appbar.AppBarLayout&amp;gt;
     
     &amp;lt;androidx.core.widget.NestedScrollView&amp;gt;
     
     	&amp;lt;androidx.viewpager2.widget.ViewPager2/&amp;gt;
        
     &amp;lt;/androidx.core.widget.NestedScrollView&amp;gt;
     
&amp;lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;손으로 꾹 누른 상태로 스크롤 하면 상단 AppBar가 움직이지 않고, 스크롤 직후 떼면 관성에 의해서만 AppBar가 동작하는 이슈였다.&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;굉장히 많은 삽질과 스택오버플로우의 검색으로 2시간 반만에 문제를 해결했다... &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;무려 7년 7개월 전 스택오버플로우 게시글에서 힌트를 찾을 수 있었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;154&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bbA5Y3/btrWERmDQI3/bIf5wBl0Rd2k0AOivevMA1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bbA5Y3/btrWERmDQI3/bIf5wBl0Rd2k0AOivevMA1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bbA5Y3/btrWERmDQI3/bIf5wBl0Rd2k0AOivevMA1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbbA5Y3%2FbtrWERmDQI3%2FbIf5wBl0Rd2k0AOivevMA1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1366&quot; height=&quot;154&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1366&quot; data-origin-height=&quot;154&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;252&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bikhMm/btrWINjm8Iy/plO9tbV2201i9lkHYr3L4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bikhMm/btrWINjm8Iy/plO9tbV2201i9lkHYr3L4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bikhMm/btrWINjm8Iy/plO9tbV2201i9lkHYr3L4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbikhMm%2FbtrWINjm8Iy%2FplO9tbV2201i9lkHYr3L4k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1172&quot; height=&quot;252&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1172&quot; data-origin-height=&quot;252&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;pre id=&quot;code_1674110926425&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;androidx.coordinatorlayout.widget.CoordinatorLayout&amp;gt;

	 &amp;lt;com.google.android.material.appbar.AppBarLayout&amp;gt;
     
     	 &amp;lt;com.google.android.material.appbar.CollapsingToolbarLayout&amp;gt;
        
         &amp;lt;/com.google.android.material.appbar.CollapsingToolbarLayout&amp;gt;
         
     &amp;lt;/com.google.android.material.appbar.AppBarLayout&amp;gt;
     
            &amp;lt;androidx.viewpager2.widget.ViewPager2
                android:id=&quot;@+id/view_pager&quot;
                android:layout_width=&quot;match_parent&quot;
                android:layout_height=&quot;match_parent&quot;
                android:nestedScrollingEnabled=&quot;false&quot;
                app:layout_behavior=&quot;@string/appbar_scrolling_view_behavior&quot;/&amp;gt;
    
&amp;lt;/androidx.coordinatorlayout.widget.CoordinatorLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ViewPager에 behavior 속성을 넣고 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;ViewPager 내부에서 사용하는 프래그먼트에 NestedScrollView&lt;/b&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;size14&quot;&gt;&lt;span style=&quot;font-family: 'Noto Sans Light';&quot;&gt;&lt;b&gt;fragment.xml&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1674111038278&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;androidx.core.widget.NestedScrollView
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;&amp;gt;
        
        ''' 중략 '''
        
&amp;lt;/androidx.core.widget.NestedScrollView&amp;gt;&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;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;u&gt;&lt;b&gt;CollapsingToolbarLayout 을 사용하는 xml에 있는 스크롤뷰만 인식한다고 생각했었는데 이게 큰 오산이었다.&lt;/b&gt;&lt;/u&gt; 뷰페이저에 사용하는 프래그먼트의 스크롤도 인식하도록 구글이 구현해두었을줄이야..&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어쨌든 이상한건 밖에 있는 스크롤뷰는 제대로 인식하지 못하고 내부에 있는 스크롤뷰만 제대로 인식하는게 이상하긴 한데 동작해서 좋다.&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>androidstudio</category>
      <category>CollapsingToolbarLayout</category>
      <category>ViewPager2</category>
      <category>스크롤</category>
      <category>안드로이드</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/233</guid>
      <comments>https://haruple.tistory.com/233#entry233comment</comments>
      <pubDate>Thu, 19 Jan 2023 17:10:02 +0900</pubDate>
    </item>
    <item>
      <title>[Android | Kotlin] Bottom Sheet Dialog 개발하기</title>
      <link>https://haruple.tistory.com/232</link>
      <description>&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Bottom Sheet Dialog&lt;/b&gt;&lt;/span&gt;를 개발중인 앱에 적용해야해서 커스텀해서 예쁘게 적용을 완료했습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 Bottom Sheet 라이브러리를 알기전에는 git에서 다른 유저가 개발한 라이브러리를 가져와서 스크롤 되는 화면을 구현했었는데요, 성능적으로나 미관상으로도 좋지 않은 방법이었습니다.&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;Bottom Sheet Dialog를 사용하는 다른 앱을 찾아보았는데요, 제가 사용하던 '스픽' 이라는 영어 스피킹 앱에서 Bottom Sheet Dialog를 이용해 캘린더를 적용한 모습을 볼 수 있었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure data-ke-type=&quot;video&quot; data-ke-style=&quot;alignCenter&quot; data-video-host=&quot;kakaotv&quot; data-video-url=&quot;https://tv.kakao.com/v/435127810&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/c2qiV3/hyRjc2HsEL/pxnK7OrNjo8yKmZAuXyoW1/img.jpg?width=1080&amp;amp;height=1348&amp;amp;face=0_0_1080_1348,https://scrap.kakaocdn.net/dn/iG9X5/hyRkh2mJ8B/5jPtBZna7JRZDV7FcMMsyK/img.jpg?width=1080&amp;amp;height=1348&amp;amp;face=0_0_1080_1348&quot; data-video-width=&quot;400&quot; data-video-height=&quot;499&quot; data-video-origin-width=&quot;860&quot; data-video-origin-height=&quot;1073&quot; data-ke-mobilestyle=&quot;widthContent&quot; data-video-play-service=&quot;daum_tistory&quot;&gt;&lt;iframe src=&quot;https://play-tv.kakao.com/embed/player/cliplink/435127810?service=daum_tistory&quot; width=&quot;400&quot; height=&quot;499&quot; frameborder=&quot;0&quot; allowfullscreen=&quot;true&quot;&gt;&lt;/iframe&gt;
&lt;figcaption&gt;&lt;/figcaption&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;Bottom Sheet Dialog는 위 영상처럼 평소에는 숨겨져 있다가 나타나는 뷰입니다. 그리고 Dialog로 만들어져있기 때문에 Dialog 내부의 함수를 이용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;b&gt;개발하면서 느낀 Dialog의 장점&lt;/b&gt;&lt;/u&gt;은 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;상단 작업표시줄까지 깔끔하게 alpha 처리 되어 완성도를 높일 수 있다는 점&lt;/span&gt;&lt;/b&gt;과, 커스텀해서 복잡한 뷰가 포함되어 있더라도 &lt;b&gt;&lt;span style=&quot;color: #006dd7;&quot;&gt;Dialog가 제거되면 뷰가 완전히 사라지면서 앱 성능을 좋게 유지&lt;/span&gt;&lt;/b&gt;할 수 있다는 점입니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Bottom Sheet Dialog 개발&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;먼저 Bottom Sheet Dialog 내부 레이아웃을 만듭니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;u&gt;layout_behavior에 BottomSheet로 사용할 레이아웃이라는 것을 명시&lt;/u&gt;&lt;/b&gt;해줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;bottom_sheet_dialog.xml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1673956631612&quot; class=&quot;xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    app:layout_behavior=&quot;com.google.android.material.bottomsheet.BottomSheetBehavior&quot;&amp;gt;

&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;&lt;b&gt;MainActivity.kt&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot;&gt;&lt;code&gt;val bottomSheetView = layoutInflater.inflate(R.layout.bottom_sheet_dialog, null)
val bottomSheetDialog = BottomSheetDialog(this)
bottomSheetDialog.setContentView(bottomSheetView)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용할 화면에서 BottomSheetDialog를 띄워주면 끝입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;정말 기본적인 코드만 적어두었는데, 여러곳에서 사용하려면 BottomSheetDialog만의 클래스를 생성해 모듈화 작업을 거치는게 좋습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;BottomSheetDialog 속성&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;BottomSheetDialog는 behavior 라는 속성에 쉽게 커스텀 할 수 있도록 여러 옵션을 제공하고 있습니다.&lt;/p&gt;
&lt;pre class=&quot;ini&quot;&gt;&lt;code&gt;bottomSheetDialog.behavior.isHideable = true&lt;/code&gt;&lt;/pre&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;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;peekHeight&lt;/b&gt;&lt;/span&gt; : bottomSheet를 완전히 접었을 때의 높이를 설정한다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fffdd8;&quot;&gt;isHideable&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; : bottomSheet를 완전히 접었을 때 아예 숨길 수 있도록 할지 설정한다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fffdd8;&quot;&gt;skipCollapsed&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; : bottomSheet를 숨길때 접히는 상태를 무시할지 여부를 결정.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;draggable&lt;/b&gt;&lt;/span&gt; : 뷰를 드래그해서 접을지 펼칠지 여부를 결정한다. BottomSheet 내부에 스크롤바가 있으면 해당 옵션을 동적으로 지정해 스크롤 동작을 원하는대로 수행할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fffdd8;&quot;&gt;&lt;b&gt;fitToContents&lt;/b&gt;&lt;/span&gt; : 펼쳐진 뷰의 높이가 content를 감쌀 것인지의 여부를 결정한다. false로 설정시 뷰가 펼쳐졌을 때 아래로 드래그할 경우 부모 컨테이너 높이의 절반으로 먼저 접히고 다시 드래그하면 완전히 접힌다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #fffdd8;&quot;&gt;halfExpandedRatio&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; : 절반만 펼쳐졌을 때 뷰의 높이를 결정한다. fitToContents가 false 일때만 동작한다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;font-family: 'Noto Sans Demilight', 'Noto Sans KR'; background-color: #fffdd8;&quot;&gt;&lt;b&gt;expandedOffset&lt;/b&gt;&lt;/span&gt; : 완전히 펼쳐진 상태일 때 뷰의 오프셋을 결정한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buStJC/btrWwJVOPME/9BoXhGDMAx4FvVlat4SSOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buStJC/btrWwJVOPME/9BoXhGDMAx4FvVlat4SSOK/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buStJC/btrWwJVOPME/9BoXhGDMAx4FvVlat4SSOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuStJC%2FbtrWwJVOPME%2F9BoXhGDMAx4FvVlat4SSOK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bB0Ry9/btrWx5cK0lF/cuKJwF6HiH6eK7HkhfprH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB0Ry9/btrWx5cK0lF/cuKJwF6HiH6eK7HkhfprH0/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%; margin-right: 10px;&quot; data-widthpercent=&quot;33.33&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB0Ry9/btrWx5cK0lF/cuKJwF6HiH6eK7HkhfprH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB0Ry9%2FbtrWx5cK0lF%2FcuKJwF6HiH6eK7HkhfprH0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cbKW9Z/btrWwoxDyZx/IZcynkwFYgBftRY6RUIC51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cbKW9Z/btrWwoxDyZx/IZcynkwFYgBftRY6RUIC51/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 32.5581%;&quot; data-widthpercent=&quot;33.34&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cbKW9Z/btrWwoxDyZx/IZcynkwFYgBftRY6RUIC51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcbKW9Z%2FbtrWwoxDyZx%2FIZcynkwFYgBftRY6RUIC51%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 behavior 옵션들을 사용해 서비스 되고 있는 '스픽' 앱처럼 BottomSheetDialog 를 커스텀 할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;BottomSheetDialog 상태&lt;/span&gt;&lt;/h2&gt;
&lt;pre class=&quot;pf&quot;&gt;&lt;code&gt;bottomSheetDialog.behavior.state = BottomSheetBehavior.STATE_EXPANDED&lt;/code&gt;&lt;/pre&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;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;STATE_EXPANDED&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 완전히 펼쳐진 상태&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;STATE_COLLAPSED&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 접혀있는 상태&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;STATE_HIDDEN&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 아래로 숨겨진 상태&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;STATE_HALF_EXPANDED&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 절반으로 펼쳐진 상태&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;STATE_DRAGGING&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 드래그 되고 있는 상태&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #fffdd8; font-family: 'Noto Sans Demilight', 'Noto Sans KR';&quot;&gt;&lt;b&gt;STATE_SETTING&lt;/b&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;: 드래그/스와이프 직후 고정된 상태&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;732&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpQzhY/btrWyK0vs6i/2A0bnJK5KBUmYgEruMajK0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpQzhY/btrWyK0vs6i/2A0bnJK5KBUmYgEruMajK0/img.gif&quot; data-alt=&quot;BottomSheetDialog 상태&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpQzhY/btrWyK0vs6i/2A0bnJK5KBUmYgEruMajK0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bpQzhY/btrWyK0vs6i/2A0bnJK5KBUmYgEruMajK0/img.gif&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; loading=&quot;lazy&quot; width=&quot;270&quot; height=&quot;732&quot; data-origin-width=&quot;350&quot; data-origin-height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;BottomSheetDialog 상태&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>behavior</category>
      <category>bottomsheetdialog</category>
      <category>안드로이드스튜디오</category>
      <category>코틀린</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/232</guid>
      <comments>https://haruple.tistory.com/232#entry232comment</comments>
      <pubDate>Tue, 17 Jan 2023 21:33:26 +0900</pubDate>
    </item>
    <item>
      <title>[Android | Kotlin] 이모지/이모티콘을 TextView에 적용하기</title>
      <link>https://haruple.tistory.com/231</link>
      <description>&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;&lt;a href=&quot;https://developer.android.com/guide/topics/ui/look-and-feel/emoji-compat?hl=ko&quot;&gt;https://developer.android.com/guide/topics/ui/look-and-feel/emoji-compat?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1673773969599&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;그림 이모티콘 호환성 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;그림 이모티콘 지원 라이브러리를 사용하면 최신 그림 이모티콘으로 Android 기기를 최신 상태로 유지할 수 있습니다.&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/guide/topics/ui/look-and-feel/emoji-compat?hl=ko&quot; data-og-url=&quot;https://developer.android.com/guide/topics/ui/look-and-feel/emoji-compat?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/eFEER/hyRhN2Ir3j/OdVswDD9pzcG2GQTs8dvB1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/6XKk5/hyRhIf1I2E/bV1ZvHME5KbkO55wPEoMJk/img.png?width=600&amp;amp;height=301&amp;amp;face=0_0_600_301,https://scrap.kakaocdn.net/dn/ccP8MO/hyRhIAjR4k/wn2KGKRQJblknTJ4AKjt0k/img.png?width=600&amp;amp;height=217&amp;amp;face=0_0_600_217&quot;&gt;&lt;a href=&quot;https://developer.android.com/guide/topics/ui/look-and-feel/emoji-compat?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/guide/topics/ui/look-and-feel/emoji-compat?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/eFEER/hyRhN2Ir3j/OdVswDD9pzcG2GQTs8dvB1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/6XKk5/hyRhIf1I2E/bV1ZvHME5KbkO55wPEoMJk/img.png?width=600&amp;amp;height=301&amp;amp;face=0_0_600_301,https://scrap.kakaocdn.net/dn/ccP8MO/hyRhIAjR4k/wn2KGKRQJblknTJ4AKjt0k/img.png?width=600&amp;amp;height=217&amp;amp;face=0_0_600_217');&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;그림 이모티콘 호환성 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;그림 이모티콘 지원 라이브러리를 사용하면 최신 그림 이모티콘으로 Android 기기를 최신 상태로 유지할 수 있습니다.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드 공식 문서에서 제공하는대로 라이브러리를 적용해보았는데 제대로 안나오더라구요.. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&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;background-color: #f6e199;&quot;&gt;&lt;b&gt;더 쉽게 이모티콘의 유니코드로 바로 이모지를 적용하는 방법&lt;/b&gt;&lt;/span&gt;을 찾았습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://apps.timwhitlock.info/emoji/tables/unicode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://apps.timwhitlock.info/emoji/tables/unicode&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1673774085713&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;Emoji unicode characters for use on the web&quot; data-og-description=&quot;Emoji code points and example glyphs using web fonts, sprites and native OS representation of Emoji characters&quot; data-og-host=&quot;apps.timwhitlock.info&quot; data-og-source-url=&quot;https://apps.timwhitlock.info/emoji/tables/unicode&quot; data-og-url=&quot;https://apps.timwhitlock.info/emoji/tables/unicode&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/p8O6D/hyRhQylDwb/gb7ieEWnbaotcAgCIecHok/img.png?width=329&amp;amp;height=329&amp;amp;face=181_31_222_230&quot;&gt;&lt;a href=&quot;https://apps.timwhitlock.info/emoji/tables/unicode&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://apps.timwhitlock.info/emoji/tables/unicode&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/p8O6D/hyRhQylDwb/gb7ieEWnbaotcAgCIecHok/img.png?width=329&amp;amp;height=329&amp;amp;face=181_31_222_230');&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;Emoji unicode characters for use on the web&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Emoji code points and example glyphs using web fonts, sprites and native OS representation of Emoji characters&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;apps.timwhitlock.info&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;적용하고 싶은 유니코드를 복사합니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;180&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cvQVL4/btrWdIJ3ozk/t81TVzep40FER3OPhwa761/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cvQVL4/btrWdIJ3ozk/t81TVzep40FER3OPhwa761/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cvQVL4/btrWdIJ3ozk/t81TVzep40FER3OPhwa761/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcvQVL4%2FbtrWdIJ3ozk%2Ft81TVzep40FER3OPhwa761%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1150&quot; height=&quot;180&quot; data-origin-width=&quot;1150&quot; data-origin-height=&quot;180&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;웃는 얼굴 유니코드는 &lt;b&gt;'U+1F601'&lt;/b&gt; 인데 여기서 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;u&gt;U+ 를 0x 로 치환&lt;/u&gt;&lt;/span&gt;해 &lt;b&gt;'0x1F601' &lt;/b&gt;로 바꿉니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1673774299186&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val unicodeText = &quot;${String(Character.toChars(&quot;0x1F601&quot;))}&quot;
binding.textView.text = unicodeText&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 이렇게 텍스트를 적용해주면 이모티콘이 잘 나오게 됩니다.&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>안드로이드</category>
      <category>안드로이드스튜디오</category>
      <category>이모지</category>
      <category>이모티콘</category>
      <category>코틀린</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/231</guid>
      <comments>https://haruple.tistory.com/231#entry231comment</comments>
      <pubDate>Sun, 15 Jan 2023 18:22:22 +0900</pubDate>
    </item>
    <item>
      <title>[Android | 앱 성능 최적화] GPU 렌더링 속도 프로파일링 및 레이아웃 평탄화</title>
      <link>https://haruple.tistory.com/230</link>
      <description>&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;많이 아시다시피 안드로이드와 IOS의 앱 성능 차이는 눈에 띌 정도로 크게 납니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IOS는 걱정을 덜해도 되는 반면 안드로이드는 개발할 때 성능면에서 더 깊은 고민과 함께 코드를 짜야합니다.. &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;곧 출시되는 &lt;b&gt;갤럭시S23부터는 스냅드래곤8 Gen2&lt;/b&gt; 가 들어가는데 유출된 성능을 보면 싱글코어 1500점대, 멀티코어 4600점대로 애플의 A14칩셋 정도로 따라온 것을 볼 수 있습니다. (분발해라 엑시노스던 퀄컴이던..)&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;회사에서 신규 앱을 개발한지 벌써 1년이 넘었는데요,&lt;span&gt; 계속해서 기능이 추가되고 복잡한 커스텀 UI나 애니메이션을 넣다보니 슬슬 앱에 렉이 생기기 시작했습니다. 거기에 모자라서 BottomNavigation으로 여러 Fragment를 한번에 생성하고 그 BottomNavigation의 Fragment 내부에 ViewPager 화면이 11개가 있는 등 어마어마한 양의 뷰를 처리하다보니 렉이 안생길수가 없습니다ㅜㅜ 자연스럽게 메모리도 많이 먹게 되었고, 애니메이션을 실행할 때 심한 렉이 동반되기 시작했습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;&lt;span&gt;그렇게 뒤늦게나마 앱 최적화 작업에 들어가게 되었습니다.&lt;/span&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;안드로이드의 성능 최적화를 검색하면 아마 &lt;u&gt;&lt;b&gt;GPU 렌더링 프로파일링과 오버드로 디버그&lt;/b&gt;&lt;/u&gt;를 통해 문제를 해결하는게 가장 많이 보일텐데요, 이번 글에서는 GPU 렌더링 속도 프로파일링으로 어떻게 성능을 향상했는지 알려드리겠습니다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로파일러 사용 설정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설정 - gpu 검색 - 프로필 HWUI 렌더링 - 화면에 막대로 표시&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKb2v4/btrV74ybwa3/Hsy4KoiLYbxDXiuKf0TCgk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKb2v4/btrV74ybwa3/Hsy4KoiLYbxDXiuKf0TCgk/img.png&quot; data-origin-width=&quot;560&quot; data-origin-height=&quot;654&quot; data-is-animation=&quot;false&quot; data-widthpercent=&quot;40.83&quot; style=&quot;width: 39.8824%; margin-right: 10px;&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKb2v4/btrV74ybwa3/Hsy4KoiLYbxDXiuKf0TCgk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKb2v4%2FbtrV74ybwa3%2FHsy4KoiLYbxDXiuKf0TCgk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;560&quot; height=&quot;654&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4Cmzi/btrV67vc7ho/XpW4tQBLBeFj91mqPUiy51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4Cmzi/btrV67vc7ho/XpW4tQBLBeFj91mqPUiy51/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;580&quot; data-origin-height=&quot;1318&quot; data-filename=&quot;스크린샷 2023-01-12 오후 8.24.49.png&quot; style=&quot;width: 20.4967%; margin-right: 10px;&quot; data-widthpercent=&quot;20.98&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4Cmzi/btrV67vc7ho/XpW4tQBLBeFj91mqPUiy51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4Cmzi%2FbtrV67vc7ho%2FXpW4tQBLBeFj91mqPUiy51%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;580&quot; height=&quot;1318&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2gdt/btrV7euhtPR/Yt8ElWIySK7UwVvJGqbsU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2gdt/btrV7euhtPR/Yt8ElWIySK7UwVvJGqbsU0/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 37.2953%;&quot; data-widthpercent=&quot;38.19&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2gdt/btrV7euhtPR/Yt8ElWIySK7UwVvJGqbsU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2gdt%2FbtrV7euhtPR%2FYt8ElWIySK7UwVvJGqbsU0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로파일러로 속도 저하 문제 확인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 기능은 프로파일러 말 그대로 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;u&gt;&lt;b&gt;속도 저하의 문제가 무엇인지 확인하는 용도&lt;/b&gt;&lt;/u&gt;&lt;/span&gt;로만 사용합니다. 시각적으로 구동되고 있는 앱이 어느정도의 프레임을 달성하고 있는지 보여줍니다. 요즘 출시되는 스마트폰은 초당 120 프레임까지도 표현하는데 사실 렉걸린다는거 부터 초당 10프레임까지도 떨어진다는걸 의미하기 때문에 속도 문제를 해결하기 전에는 하드웨어의 120프레임을 온전히 활용할 수가 없습니다 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mXb9p/btrV7Ovp5T5/j47hB30kSOR32KijLF5n00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mXb9p/btrV7Ovp5T5/j47hB30kSOR32KijLF5n00/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mXb9p/btrV7Ovp5T5/j47hB30kSOR32KijLF5n00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FmXb9p%2FbtrV7Ovp5T5%2Fj47hB30kSOR32KijLF5n00%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WLtQn/btrV68t7sih/tbUiGqhzMVjLslaVmsno1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WLtQn/btrV68t7sih/tbUiGqhzMVjLslaVmsno1k/img.png&quot; data-origin-width=&quot;1768&quot; data-origin-height=&quot;2208&quot; data-is-animation=&quot;false&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WLtQn/btrV68t7sih/tbUiGqhzMVjLslaVmsno1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWLtQn%2FbtrV68t7sih%2FtbUiGqhzMVjLslaVmsno1k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1768&quot; height=&quot;2208&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;토스와 배달의 민족 Android App GPU 렌더링 프로파일링&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;GPU 렌더링 프로파일링을 켜두고 토스와 배달의 민족 앱을 구동해봤습니다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/De6zT/btrV1VDvEa3/cAGS1jLd6ekUBGaCxMqv11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/De6zT/btrV1VDvEa3/cAGS1jLd6ekUBGaCxMqv11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/De6zT/btrV1VDvEa3/cAGS1jLd6ekUBGaCxMqv11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDe6zT%2FbtrV1VDvEa3%2FcAGS1jLd6ekUBGaCxMqv11%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;471&quot; height=&quot;115&quot; data-origin-width=&quot;1148&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가로 선의 의미를 알아야 하는데요, &lt;b&gt;&lt;span style=&quot;color: #1b711d;&quot;&gt;얇게 있는 녹색 가로선은 16.67ms&lt;/span&gt;&lt;/b&gt;를 의미합니다. 초당 60프레임을 달성하려면 맨 아래에 있는 녹색 가로선을 그래프가 넘지 않아야 합니다. 그런데 사진에서 토스나 배달의 민족 앱 모두 훌쩍 뛰어넘어 있는걸 볼 수 있습니다. 이는 앱을 최초 실행하였을 때 레이아웃을 계산해야하기 때문에 필연적으로 최초 1회동안만 발생하는 렉이라 괜찮습니다. 우리는 앱을 구동중에 렉이 발생하지 않도록 해야합니다. 이제 세로선의 의미를 보겠습니다. 제가 중점으로 봐야할 부분은 &lt;b&gt;'측정, 레이아웃'&lt;/b&gt; 입니다.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1738&quot; data-origin-height=&quot;1448&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uSosM/btrV5nTp6o6/afhci7O2yTTNKzsRnHcAN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uSosM/btrV5nTp6o6/afhci7O2yTTNKzsRnHcAN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uSosM/btrV5nTp6o6/afhci7O2yTTNKzsRnHcAN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuSosM%2FbtrV5nTp6o6%2Fafhci7O2yTTNKzsRnHcAN1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1738&quot; height=&quot;1448&quot; data-origin-width=&quot;1738&quot; data-origin-height=&quot;1448&quot;/&gt;&lt;/span&gt;&lt;/figure&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;Constraint Latout을 하나만 사용하여 평탄화&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;androidx.constraintlayout.widget.ConstraintLayout 
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;&amp;gt;

    &amp;lt;androidx.constraintlayout.widget.ConstraintLayout
    	android:id=&quot;@+id/button&quot;
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&amp;gt;

    &amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;

&amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사실 최적화를 진행하기 전에는 ConstraintLayout 내부에 ConstraintLayout을 하나 더 생성해서 조금 복잡한 UI의 버튼을 구현하곤 했었습니다  이게 개발자 입장에서는 레이아웃을 통째로 버튼으로 쓰면되니까 편한데 성능에서는 전혀 좋지 않습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&quot;&gt;레이아웃 계층이 하나씩 늘어날 때마다 안드로이드는 뷰 위치를 계산해야 하는 횟수가 증가하게 됩니다. 그래서 Constraint 레이아웃을 하나만 사용하도록 xml을 수정했고 같은 뷰를 구현하더라도 레이아웃 계산에 쓰이는 시간을 줄일수 있게 되었습니다.&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;한번 이렇게 리팩토링을 거치고나면서 성능의 중요성을 깨닫고.. 이제는 처음부터 ConstraintLayout을 한번만 사용하려고 하고 있습니다ㅠㅠ&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;정말 간단히 가로/세로로만 뷰가 배치되면 LinearLayout 사용하기&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 앱 화면을 개발할 때 가로, 세로로만 뷰가 배치되는 경우는 거의 없습니다. 그럼에도 화면 내부에서 일부 모듈만을 개발한다거나 정말 간단한 화면을 구현할 때는 가로, 세로로만 배치되는 경우가 간혹 있습니다. 이런 경우에는 LinearLayout을 써도 계층이 더 복잡해지지 않기 때문에 괜찮습니다.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;&amp;gt;
    
    &amp;lt;TextView
        android:id=&quot;@+id/tv_test_1&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;/&amp;gt;

    &amp;lt;TextView
        android:id=&quot;@+id/tv_test_2&quot;
        android:layout_width=&quot;wrap_content&quot;
        android:layout_height=&quot;wrap_content&quot;/&amp;gt;

&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;b&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;다른 레이아웃을 가져올 때 merge 태그 사용하기&lt;/span&gt;&lt;/b&gt;&lt;/blockquote&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;&amp;gt;
    
    &amp;lt;include
        layout=&quot;@layout/act_main&quot;/&amp;gt;

&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;보통 반복되는 레이아웃을 재사용하기 위해 &amp;lt;include/&amp;gt; 태그를 사용하곤 합니다. &lt;b&gt;이때 include 내부에 들어있는 layout은 무조건 레이아웃이 감싸져있겠죠? &lt;/b&gt;그래서 위의 코드와 아래 코드가 똑같을 겁니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;html xml&quot; data-ke-language=&quot;html&quot;&gt;&lt;code&gt;&amp;lt;LinearLayout
    xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    android:orientation=&quot;vertical&quot;&amp;gt;

    &amp;lt;androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width=&quot;match_parent&quot;
        android:layout_height=&quot;match_parent&quot;&amp;gt;
        
        ''' 중략 '''
        
    &amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;

&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러면 쓸모없이 레이아웃이 하나 더 생성되어 있는거고 마찬가지로 레이아웃 계층 계산에 시간이 더 소요되게 됩니다. &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;이를 해결하기 위해 안드로이드에서는 merge 태그를 제공합니다.&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&amp;gt;
&amp;lt;merge xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;
    xmlns:tools=&quot;http://schemas.android.com/tools&quot;
    android:id=&quot;@+id/layout_parent&quot;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;wrap_content&quot;
    tools:parentTag=&quot;androidx.constraintlayout.widget.ConstraintLayout&quot;&amp;gt;

&amp;lt;/merge&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 화면에 갖다붙힐 모듈의 xml에 merge로 감싸고 해당 xml이 어떤 레이아웃을 사용할지 &lt;u&gt;&lt;b&gt;tools:parentTag&lt;/b&gt;&lt;/u&gt; 로 정의해주면 쉽게 레이아웃 평탄화를 할 수 있습니다. merge 태그로 만든 레이아웃은 가장 바깥 레이아웃이 사라지고 include 등을 통해 넣게된 xml의 부모 레이아웃과 엮이게 됩니다.&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;지금 회사에서 개발하는 앱의 각 기능들을 모듈화 해두었고, 각 모듈 xml을 화면으로 그대로 가져와 사용하는 경우가 잦습니다. 그래서 merge 태그를 많이 사용할 수 있었고 속도 향상도 많이 이룰수 있었습니다.&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>개발/Android</category>
      <category>HWUI</category>
      <category>레이아웃</category>
      <category>속도 최적화</category>
      <category>안드로이드 개발</category>
      <category>안드로이드스튜디오</category>
      <category>최적화</category>
      <category>평탄화</category>
      <category>프로파일링</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/230</guid>
      <comments>https://haruple.tistory.com/230#entry230comment</comments>
      <pubDate>Thu, 12 Jan 2023 21:21:33 +0900</pubDate>
    </item>
    <item>
      <title>[2023 연말정산] 월세 소득공제, 세액공제 받는 방법</title>
      <link>https://haruple.tistory.com/229</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&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;그런데..!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;월세는 여기에 포함되지 않습니다. 젠장...&lt;/span&gt;&lt;/b&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;h3 data-ke-size=&quot;size23&quot;&gt;소득공제&lt;/h3&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;2022년 소득에 따른 세율&lt;/b&gt;입니다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 155px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;과세표준 (단위 : 만 원)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;세율&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;누진공제&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;1,200 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;6%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;1,200 초과 ~ 4,600 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;15%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;1,080,000원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;4,600 초과 ~ 8,800 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;24%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;5,220,000원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;8,800 초과 ~ 15,000 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;35%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;14,900,000원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;15,000 초과 ~ 30,000 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;38%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;19,400,000원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;30,000 초과 ~ 50,000 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;40%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;25,400,000원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;50,000 초과 ~ 100,000 이하&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;42%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;35,400,000원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;100,000 초과&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;45%&lt;/td&gt;
&lt;td style=&quot;width: 33.3333%; height: 17px; text-align: center;&quot;&gt;65,400,000원&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;2023년 올해는 과세표준 구간이 완화되면서 서민, 중산층의 세금 부담이 조금 줄어들 것 같습니다!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 이번 연말정산은 위 표인 2022년 과세표준 구간을 보셔야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2023년 소득에 따른 세율&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 66.1628%; height: 72px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style4&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;과세표준 (단위 : 만 원)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px; text-align: center;&quot;&gt;&lt;b&gt;세율&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 19px; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;1,400 이하&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 19px; text-align: center;&quot;&gt;6%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;1,400 초과 ~ 5,000 이하&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;15%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 17px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;&lt;span style=&quot;background-color: #f9f9f9;&quot;&gt;5,000 초과 ~ 8,800 이하&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 17px; text-align: center;&quot;&gt;24%&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;&lt;span style=&quot;color: #000000; font-size: 1.44em; letter-spacing: -1px; font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif;&quot;&gt;세액공제&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세액공제는 내가 &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;실제로 내야하는 세금에서 금액을 빼주는 방식&lt;/b&gt;&lt;/span&gt;이에요. 만약 세액 공제율이 16.5%라면 내가 낼 세금에서 그만큼 감면해주게됩니다. 세액 공제가 계산도 간단하고 공제에 대한 효과도 더 크기 때문에 세액 공제를 챙기면 좋아요! 하지만 혜택이 좋은만큼 세액 공제를 받기위한 조건이 까다롭습니다 &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;월세도 소득 공제와 세액 공제가 따로 있습니다. 두 공제는 중복으로 받을 수 없기 때문에 내가 공제 받을 수 있는 항목을 선택해야해요. 게다가 올해 월세 공제액이 대폭 늘었기 때문에 조건이 된다면 세액 공제를 챙기는 것이 좋습니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;286&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/6Yups/btrVpuStLJc/Q0FadbcjbSBSqpRD3Hd4uk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/6Yups/btrVpuStLJc/Q0FadbcjbSBSqpRD3Hd4uk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/6Yups/btrVpuStLJc/Q0FadbcjbSBSqpRD3Hd4uk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F6Yups%2FbtrVpuStLJc%2FQ0FadbcjbSBSqpRD3Hd4uk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;493&quot; height=&quot;286&quot; data-filename=&quot;blob&quot; data-origin-width=&quot;1380&quot; data-origin-height=&quot;286&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;월세 소득공제&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 59.4177%; height: 204px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;조건&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;공제율/한도&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;근로소득자이며 임대차 계약서상 본인이어야 함.&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot; rowspan=&quot;2&quot;&gt;다른 현금 영수증과 모두 합쳐 30%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;주택 소유 여부, 연봉 조건, 주택 가격 상관 없음.&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;월세 세액공제&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 59.3014%; height: 229px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;조건&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%; text-align: center;&quot;&gt;&lt;b&gt;공제율/한도&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;국민주택규모 (국가에서 지원한 주택) 또는 기준 시가 3억 이하 (주거용 오피스텔, 고시원 가능)&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot; rowspan=&quot;5&quot;&gt;급여 5,500만원 이하 : 17%&lt;br /&gt;급여 5,500 ~ 7000만원 : 15%&lt;br /&gt;&lt;br /&gt;한도 : 750만원&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;총 급여 7000만원 이하의 근로소득자&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;전용면적 85&lt;span style=&quot;background-color: #ffffff; color: #554f45;&quot;&gt;㎡ (약 25평) 이하의 주택 거주&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #554f45;&quot;&gt;전입신고 완료&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;span&gt;&lt;span style=&quot;background-color: #ffffff; color: #554f45;&quot;&gt;무주택 세대주&lt;/span&gt;&lt;/span&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style3&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;월세&amp;nbsp;소득공제,&amp;nbsp;세액공제&amp;nbsp;받는&amp;nbsp;방법&lt;/b&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소득 공제&lt;/b&gt; : 국세청 홈택스에서 현금영수증 신청 후 회사에 제출하면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_스크린샷 2023-01-04 오후 11.41.21.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;758&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b27Wk5/btrVpZrabnn/FkWzXxmjzqHtt9GqtoRhK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b27Wk5/btrVpZrabnn/FkWzXxmjzqHtt9GqtoRhK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b27Wk5/btrVpZrabnn/FkWzXxmjzqHtt9GqtoRhK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb27Wk5%2FbtrVpZrabnn%2FFkWzXxmjzqHtt9GqtoRhK1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;527&quot; height=&quot;758&quot; data-filename=&quot;edited_스크린샷 2023-01-04 오후 11.41.21.png&quot; data-origin-width=&quot;1538&quot; data-origin-height=&quot;758&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;&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;span style=&quot;background-color: #f6e199; color: #000000;&quot;&gt;&lt;b&gt;소득 공제로 현금영수증 신청을 진행&lt;/b&gt;&lt;/span&gt;해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.01.31.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1220&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dGtVHh/btrWrJnGCkD/KzfoX1pwvpEfoKIVzWml30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGtVHh/btrWrJnGCkD/KzfoX1pwvpEfoKIVzWml30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGtVHh/btrWrJnGCkD/KzfoX1pwvpEfoKIVzWml30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGtVHh%2FbtrWrJnGCkD%2FKzfoX1pwvpEfoKIVzWml30%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;2000&quot; height=&quot;1220&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.01.31.png&quot; data-origin-width=&quot;2000&quot; data-origin-height=&quot;1220&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&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-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.03.26.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;664&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XHRRO/btrWsTXIyhm/OalpHprFhFquKJrOYPV2K0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XHRRO/btrWsTXIyhm/OalpHprFhFquKJrOYPV2K0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XHRRO/btrWsTXIyhm/OalpHprFhFquKJrOYPV2K0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXHRRO%2FbtrWsTXIyhm%2FOalpHprFhFquKJrOYPV2K0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1562&quot; height=&quot;664&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.03.26.png&quot; data-origin-width=&quot;1562&quot; data-origin-height=&quot;664&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;204&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C36Ek/btrWp0DXRPN/6HM4Yw9cSIOUpViiKwgRI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C36Ek/btrWp0DXRPN/6HM4Yw9cSIOUpViiKwgRI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C36Ek/btrWp0DXRPN/6HM4Yw9cSIOUpViiKwgRI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC36Ek%2FbtrWp0DXRPN%2F6HM4Yw9cSIOUpViiKwgRI1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1858&quot; height=&quot;204&quot; data-origin-width=&quot;1858&quot; data-origin-height=&quot;204&quot;/&gt;&lt;/span&gt;&lt;/figure&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;752&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0N3Y5/btrWr5RzD8r/S978C7LYowKzdKzZL2AAK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0N3Y5/btrWr5RzD8r/S978C7LYowKzdKzZL2AAK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0N3Y5/btrWr5RzD8r/S978C7LYowKzdKzZL2AAK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0N3Y5%2FbtrWr5RzD8r%2FS978C7LYowKzdKzZL2AAK1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1964&quot; height=&quot;752&quot; data-origin-width=&quot;1964&quot; data-origin-height=&quot;752&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: #ee2323;&quot;&gt;&lt;b&gt;* 부분은 필수 기입란&lt;/b&gt;&lt;/span&gt;입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그런데 여기서 &lt;b&gt;&lt;u&gt;월세와 선금을 잘 확인해주세요.&lt;/u&gt;&lt;/b&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;p data-ke-size=&quot;size16&quot;&gt;저는 보증금이 있었기 때문에 보증금도 기입했고, &lt;u&gt;&lt;b&gt;기타 참고사항에는 '월세에 관리비 ~~만원 포함.' 을 기입&lt;/b&gt;&lt;/u&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1972&quot; data-origin-height=&quot;458&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJCZHt/btrWr6XhBJS/KASfku3htn5ztp21cKBq8k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJCZHt/btrWr6XhBJS/KASfku3htn5ztp21cKBq8k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJCZHt/btrWr6XhBJS/KASfku3htn5ztp21cKBq8k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJCZHt%2FbtrWr6XhBJS%2FKASfku3htn5ztp21cKBq8k%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1972&quot; height=&quot;458&quot; data-origin-width=&quot;1972&quot; data-origin-height=&quot;458&quot;/&gt;&lt;/span&gt;&lt;/figure&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;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;월세 송금 확인증&lt;/b&gt;&lt;/span&gt;을 발급받아야합니다. 저는 토스로 발급받았구요, 여러분이 송금한 은행 앱에 들어가서 날짜를 선택하면 발급 받을 수 있습니다. &lt;u&gt;발급 방법은 은행 앱마다 달라서 직접 검색&lt;/u&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: #ee2323;&quot;&gt;&lt;b&gt;부동산 월세 계약서&lt;/b&gt;&lt;/span&gt;를 사진 찍고 이미지를 첨부서류로 업로드하시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2TbPg/btrWqIpjaH2/o8DcyZYctMvVvehEi7p2pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2TbPg/btrWqIpjaH2/o8DcyZYctMvVvehEi7p2pK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;1336&quot; data-origin-height=&quot;1892&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.13.03.png&quot; style=&quot;width: 49.1488%; margin-right: 10px;&quot; data-widthpercent=&quot;49.73&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2TbPg/btrWqIpjaH2/o8DcyZYctMvVvehEi7p2pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2TbPg%2FbtrWqIpjaH2%2Fo8DcyZYctMvVvehEi7p2pK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1336&quot; height=&quot;1892&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b7KZY0/btrWsjhZrno/vL7tAOdJO7MIDsmmywkxs1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b7KZY0/btrWsjhZrno/vL7tAOdJO7MIDsmmywkxs1/img.png&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;2132&quot; data-is-animation=&quot;false&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.14.31.png&quot; style=&quot;width: 49.6884%;&quot; data-widthpercent=&quot;50.27&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b7KZY0/btrWsjhZrno/vL7tAOdJO7MIDsmmywkxs1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb7KZY0%2FbtrWsjhZrno%2FvL7tAOdJO7MIDsmmywkxs1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1522&quot; height=&quot;2132&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;월세 공금 확인증, 부동산 월세 계약서&lt;/figcaption&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;h2 data-ke-size=&quot;size26&quot;&gt;월세 현금영수증 신고 처리 현황 조회&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.16.53.png&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;492&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3vpCx/btrWpnFWFCi/IECEkRriUUgNUzE0qZYdbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3vpCx/btrWpnFWFCi/IECEkRriUUgNUzE0qZYdbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3vpCx/btrWpnFWFCi/IECEkRriUUgNUzE0qZYdbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3vpCx%2FbtrWpnFWFCi%2FIECEkRriUUgNUzE0qZYdbK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;626&quot; height=&quot;198&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.16.53.png&quot; data-origin-width=&quot;1558&quot; data-origin-height=&quot;492&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;&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&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.20.05.png&quot; data-origin-width=&quot;1950&quot; data-origin-height=&quot;342&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmMPCB/btrWtetYCqD/ubk5526yr0EHadBfUXnmF1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmMPCB/btrWtetYCqD/ubk5526yr0EHadBfUXnmF1/img.png&quot; data-alt=&quot;홈택스 민원 처리 현황&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmMPCB/btrWtetYCqD/ubk5526yr0EHadBfUXnmF1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbmMPCB%2FbtrWtetYCqD%2Fubk5526yr0EHadBfUXnmF1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1950&quot; height=&quot;342&quot; data-filename=&quot;스크린샷 2023-01-17 오전 10.20.05.png&quot; data-origin-width=&quot;1950&quot; data-origin-height=&quot;342&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;홈택스 민원 처리 현황&lt;/figcaption&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;</description>
      <category>일상/일상</category>
      <category>2023 연말정산</category>
      <category>세액공제</category>
      <category>소득공제</category>
      <category>연말정산 하는법</category>
      <category>월세 연말정산</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/229</guid>
      <comments>https://haruple.tistory.com/229#entry229comment</comments>
      <pubDate>Wed, 4 Jan 2023 23:47:13 +0900</pubDate>
    </item>
    <item>
      <title>갤럭시 워치 무한 부팅 현상 - 방수 믿지 마세요</title>
      <link>https://haruple.tistory.com/227</link>
      <description>&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;저는 2019년 출시된 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;갤럭시워치 액티브2&lt;/b&gt;&lt;/span&gt;를 거의 매일 착용하고 다녔는데요, 3년 가까이 사용한 것 치고 외관도 멀쩡하고 디스플레이도 아주 잘나옵니다!&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bh28iT/btrEJdFQKDK/zULTV2cucSrQIEk7IkYnK1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bh28iT/btrEJdFQKDK/zULTV2cucSrQIEk7IkYnK1/img.jpg&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;4000&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;KakaoTalk_Photo_2022-06-13-21-06-54 004.jpeg&quot; style=&quot;width: 49.4186%; margin-right: 10px;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bh28iT/btrEJdFQKDK/zULTV2cucSrQIEk7IkYnK1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbh28iT%2FbtrEJdFQKDK%2FzULTV2cucSrQIEk7IkYnK1%2Fimg.jpg&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; loading=&quot;lazy&quot; width=&quot;4000&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BHcyq/btrEGKLTjo1/Dqe1i5F9IKbpbKiRzaSTa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BHcyq/btrEGKLTjo1/Dqe1i5F9IKbpbKiRzaSTa1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot; data-filename=&quot;edited_KakaoTalk_Photo_2022-06-13-21-06-51 003.jpeg&quot; style=&quot;width: 49.4186%;&quot; data-widthpercent=&quot;50&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BHcyq/btrEGKLTjo1/Dqe1i5F9IKbpbKiRzaSTa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBHcyq%2FbtrEGKLTjo1%2FDqe1i5F9IKbpbKiRzaSTa1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;당시 &lt;span style=&quot;color: #ee2323;&quot;&gt;44mm 스테인리스 모델을 45만원 정도&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;background-color: #f6e199;&quot;&gt;&lt;b&gt;최근에 출시된 워치 4 가격은 20만원 초반에서 10만원 후반&lt;/b&gt;&lt;/span&gt;에도 구매가 가능할 정도로 저렴해졌죠.&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;2598&quot; data-origin-height=&quot;1408&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bR0EYA/btrEH4bMrDS/eOK2YGMsRxKduaSWUYZ5IK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bR0EYA/btrEH4bMrDS/eOK2YGMsRxKduaSWUYZ5IK/img.png&quot; data-alt=&quot;삼성전자 갤럭시워치 액티브2 광고 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bR0EYA/btrEH4bMrDS/eOK2YGMsRxKduaSWUYZ5IK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbR0EYA%2FbtrEH4bMrDS%2FeOK2YGMsRxKduaSWUYZ5IK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;2598&quot; height=&quot;1408&quot; data-origin-width=&quot;2598&quot; data-origin-height=&quot;1408&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;삼성전자 갤럭시워치 액티브2 광고 이미지&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 갤럭시 워치 액티브2 광고입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;IP68 등급의 방수방진 등급을 갖추었다고 되어있습니다.&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;u&gt;&lt;b&gt;침수로 인해 워치가 고장나버렸습니다..&lt;/b&gt; &lt;/u&gt;무한 부팅 현상이 계속 나타나고 있는데요 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;침수로 인한 고장은 정책상 무조건 유상수리&lt;/span&gt;&lt;/b&gt;로 들어가기 때문에 저는 워치를 이제 다른 제품으로 교체하려 합니다. 곧 &lt;b&gt;8월에 워치5가 출시&lt;/b&gt; 된다고 하는데 저는 워치 4가 집에 남는게 있어 워치 4를 사용하려 합니다.&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;예전에 워터파크, 목욕탕 갈 때도 그냥 갤럭시워치 액티브2 를 들고 정말 막 잘썼기 때문에 이번에도 물놀이 하러 가서 그냥 막 사용했는데요.. 이제 제 워치는 가버렸습니다ㅠㅠ&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bxWo7m/btrEIrYP76A/iMzUF6JbDFYm587rgzcgP1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bxWo7m/btrEIrYP76A/iMzUF6JbDFYm587rgzcgP1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;3000&quot; data-origin-height=&quot;2250&quot; data-filename=&quot;edited_KakaoTalk_Photo_2022-06-13-21-06-49 002.jpeg&quot; style=&quot;width: 63.2558%; margin-right: 10px;&quot; data-widthpercent=&quot;64&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bxWo7m/btrEIrYP76A/iMzUF6JbDFYm587rgzcgP1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbxWo7m%2FbtrEIrYP76A%2FiMzUF6JbDFYm587rgzcgP1%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;3000&quot; height=&quot;2250&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sgdKE/btrEJwL75Ko/4LuvlkaEbM8aaZrvAVjfdK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sgdKE/btrEJwL75Ko/4LuvlkaEbM8aaZrvAVjfdK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;2250&quot; data-origin-height=&quot;3000&quot; data-filename=&quot;edited_KakaoTalk_Photo_2022-06-13-21-06-46 001.jpeg&quot; style=&quot;width: 35.5814%;&quot; data-widthpercent=&quot;36&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sgdKE/btrEJwL75Ko/4LuvlkaEbM8aaZrvAVjfdK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsgdKE%2FbtrEJwL75Ko%2F4LuvlkaEbM8aaZrvAVjfdK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;2250&quot; height=&quot;3000&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;잠깐 작동될 때 촬영한 갤럭시 워치. 갑자기 날짜가 마음대로 바뀐다..&lt;/figcaption&gt;
&lt;/figure&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;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;내구성은 확실히 정말 만족합니다.&lt;/span&gt;&lt;/b&gt; 아무 보호 장치 없이도 액정 파손 없었고 물리 버튼 오작동도 없었기 때문에 정말 만족하고 사용했습니다. 하지만, 출시한지 거의 3년이 된 제품이다 보니 방수 실링이 벗겨지는 부분에서는 옛날 워치 사용하는 분들은 모두 주의 해야겠습니다..&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;/p&gt;</description>
      <category>일상/전자제품</category>
      <category>갤럭시 워치 방수</category>
      <category>갤럭시 워치 액티브2</category>
      <category>갤럭시워치</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/227</guid>
      <comments>https://haruple.tistory.com/227#entry227comment</comments>
      <pubDate>Tue, 14 Jun 2022 17:00:43 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드스튜디오 Activity에서 다른 Activity 변수/함수 접근하기</title>
      <link>https://haruple.tistory.com/226</link>
      <description>&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;이렇게 다른 파일에 접근하기 위해 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;자바에서는 public&lt;/b&gt;&lt;/span&gt;을 선언하고, 코틀린에서는 private를 붙이지 않고 &lt;b&gt;&lt;span style=&quot;background-color: #f6e199;&quot;&gt;val/var만 써 변수를 선언&lt;/span&gt;&lt;/b&gt;하거나 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;fun만 사용&lt;/b&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;size18&quot;&gt;SubActivity.kt&lt;/p&gt;
&lt;pre id=&quot;code_1655120045273&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class SubActivity {
    //다른 클래스에 공유할 변수와 함수 선언
    var apple = &quot;apple&quot;
    fun banana() : String {
        return &quot;banana&quot;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다른 클래스에 공유할 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;변수 apple&lt;/b&gt;&lt;/span&gt;과 &lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;함수 banana&lt;/b&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;size18&quot;&gt;MainActivity.kt&lt;/p&gt;
&lt;pre id=&quot;code_1655120331194&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)

        //SubActivity에 선언한 변수와 함수 값을 가져옴
        val apple = SubActivity().apple
        val banana = SubActivity().banana()
        
        println(&quot;과일 : $apple&quot;)
        println(&quot;과일 : $banana&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;span style=&quot;color: #ee2323;&quot;&gt;중요한 것은 클래스 내부에서만 사용할 것은 private로 사용해 변수와 함수 안전성을 높이고, 공유한 변수들만 private를 없애고 public으로 사용하는 겁니다.&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;저는 개발할 때 자주 사용하는 공유 변수를 Utility 클래스를 따로 만들어 여러번 사용하는 방법으로 코드를 줄이고, 클린코딩 하기 위해 노력하고 있습니다. 정말 쉽지만 중요한 내용입니다 ⭐️&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;&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>Activity</category>
      <category>androidstudio</category>
      <category>private</category>
      <category>Public</category>
      <category>다른 클래스 변수</category>
      <category>변수</category>
      <category>변수 접근</category>
      <category>안드로이드스튜디오</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/226</guid>
      <comments>https://haruple.tistory.com/226#entry226comment</comments>
      <pubDate>Tue, 14 Jun 2022 08:00:08 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드스튜디오 자바를 코틀린으로 번역하는 가장 쉬운 방법! (Convert Code From Java)</title>
      <link>https://haruple.tistory.com/225</link>
      <description>&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;Java&lt;/b&gt;와 &lt;b&gt;Kotlin&lt;/b&gt; 두가지로 이루어져 있기 때문에 &lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;구글링을 통해 샘플 코드&lt;/span&gt;&lt;/b&gt;를 찾으면 &lt;u&gt;내가 사용하는 언어와 다른 언어를 마주치는 경우가 꽤 있습니다.&lt;/u&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;s&gt;&lt;b&gt;&lt;span style=&quot;color: #ef5369;&quot;&gt;귀차니즘&lt;/span&gt;&lt;/b&gt;&lt;/s&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;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;복사, 붙혀넣기&lt;/b&gt;&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;오잉?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;바로 보여드리겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1984&quot; data-origin-height=&quot;298&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nF09r/btrEJw6mPl8/9CMwdkgmO0kzrcANAzDspk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nF09r/btrEJw6mPl8/9CMwdkgmO0kzrcANAzDspk/img.png&quot; data-alt=&quot;블로그의 코드를 복사한 이미지&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nF09r/btrEJw6mPl8/9CMwdkgmO0kzrcANAzDspk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnF09r%2FbtrEJw6mPl8%2F9CMwdkgmO0kzrcANAzDspk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1984&quot; height=&quot;298&quot; data-origin-width=&quot;1984&quot; data-origin-height=&quot;298&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;블로그의 코드를 복사한 이미지&lt;/figcaption&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;그리고 안드로이드 스튜디오에서 필요한 부분에 붙혀넣기 하면&lt;i&gt; &lt;b&gt;Convert Code From Java&lt;/b&gt; &lt;/i&gt;라고 나옵니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;280&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lbx6m/btrEJ4Pks3k/AmC4BFElVihuo3tzE5OTAK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lbx6m/btrEJ4Pks3k/AmC4BFElVihuo3tzE5OTAK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lbx6m/btrEJ4Pks3k/AmC4BFElVihuo3tzE5OTAK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flbx6m%2FbtrEJ4Pks3k%2FAmC4BFElVihuo3tzE5OTAK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;487&quot; height=&quot;280&quot; data-origin-width=&quot;1034&quot; data-origin-height=&quot;280&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 당연히&lt;i&gt;&lt;b&gt; Yes&lt;/b&gt;&lt;/i&gt; 를 누르면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;138&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dUCXFU/btrEHCGMx62/6bFMfJCtUpJNhK1HZK1Ci0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dUCXFU/btrEHCGMx62/6bFMfJCtUpJNhK1HZK1Ci0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dUCXFU/btrEHCGMx62/6bFMfJCtUpJNhK1HZK1Ci0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdUCXFU%2FbtrEHCGMx62%2F6bFMfJCtUpJNhK1HZK1Ci0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;1226&quot; height=&quot;138&quot; data-origin-width=&quot;1226&quot; data-origin-height=&quot;138&quot;/&gt;&lt;/span&gt;&lt;/figure&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;역시 JetBrains이 만든 프레임워크는 어마어마 합니다..&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;span style=&quot;background-color: #f6e199;&quot;&gt;모든 자바 코드가 정확하게 번역 되는 것은 아니지만&lt;/span&gt;&lt;/b&gt; 왠만한 깔끔한 자바 코드는 대부분 번역 되기 때문에 저도 자주 사용하는 기능입니다. &lt;span style=&quot;color: #ee2323;&quot;&gt;이런 꿀기능 만들어준 JetBrains에 감사를 표합니다.. &lt;/span&gt;&lt;/p&gt;</description>
      <category>개발/Android</category>
      <category>Convert Code From Java</category>
      <category>JavaToKotlin</category>
      <category>번역</category>
      <category>안드로이드스튜디오</category>
      <category>자바</category>
      <category>코틀린</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/225</guid>
      <comments>https://haruple.tistory.com/225#entry225comment</comments>
      <pubDate>Mon, 13 Jun 2022 22:30:05 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드스튜디오 스택에 쌓인 Activity 한번에 종료하기</title>
      <link>https://haruple.tistory.com/224</link>
      <description>&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;span style=&quot;color: #ef5369;&quot;&gt;&lt;b&gt;Activity와 Fragment의 역할과 생명주기는 아주 중요합니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면 이동을 위해 Activity를 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;Intent로 단순히 계속 이동하면 메모리에 Activity 스택이 계속 쌓이게 됩니다.&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 화면상 굳이 이전 화면을 저장할 필요가 없을 때는 이전 Activity를 종료해주는 것이 앱 메모리 관리에 효과적입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;546&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/E6iYI/btrEJKcjgfC/buZ8udkVSOVCXPoN8btEmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/E6iYI/btrEJKcjgfC/buZ8udkVSOVCXPoN8btEmK/img.png&quot; data-alt=&quot;4개의 Activity가 쌓인 그림&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/E6iYI/btrEJKcjgfC/buZ8udkVSOVCXPoN8btEmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FE6iYI%2FbtrEJKcjgfC%2FbuZ8udkVSOVCXPoN8btEmK%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;210&quot; height=&quot;320&quot; data-origin-width=&quot;358&quot; data-origin-height=&quot;546&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;4개의 Activity가 쌓인 그림&lt;/figcaption&gt;
&lt;/figure&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;대충 알아보시겠죠..? Activity가 총 4개가 실행되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기서 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;onBackPressed&lt;/b&gt;&lt;/span&gt; 메소드를 실행하면 이전 화면으로 돌아가면서 현재 있던 Activity가 종료되게 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(onBackPressed는 안드로이드 뒤로가기를 누르면 실행되는 메소드 입니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;538&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQplA0/btrEIt3lp28/a79tTzIbO88iQi4QDVUzX0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQplA0/btrEIt3lp28/a79tTzIbO88iQi4QDVUzX0/img.png&quot; data-alt=&quot;onBackPressed() 메소드 실행&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQplA0/btrEIt3lp28/a79tTzIbO88iQi4QDVUzX0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQplA0%2FbtrEIt3lp28%2Fa79tTzIbO88iQi4QDVUzX0%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;487&quot; height=&quot;291&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;538&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;onBackPressed() 메소드 실행&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onBackPressed 후 액티비티가 3개로 줄었습니다.&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;&lt;span style=&quot;color: #ee2323;&quot;&gt;&lt;b&gt;아이디 입력화면 -&amp;gt; 비밀번호 입력화면 -&amp;gt; 회원가입 완료&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 경우 &lt;u&gt;회원가입 완료 화면에서 앞의 화면 두개를 한번에 종료&lt;/u&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 때 사용할 수 있는 것이 Intent의 내장 함수인 &lt;span style=&quot;color: #ffffff;&quot;&gt;&lt;b&gt;&lt;span style=&quot;background-color: #006dd7;&quot;&gt;FLAG&lt;/span&gt;&lt;/b&gt;&lt;/span&gt; 입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면을 넘길때 사용한 Intent 부분에 아래처럼 setFlags 코드를 추가로 적용해주면 화면을 넘길때 Activity 정보가 저장되지 않으면서 모든 액티비티의 정보가 날아가게 됩니다.&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;JAVA&lt;/p&gt;
&lt;pre id=&quot;code_1655118331653&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Intent i = new Intent(this, MainActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(i);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Kotlin&lt;/p&gt;
&lt;pre id=&quot;code_1655118384447&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val i = Intent(this, MainActivity::class.java)
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
startActivity(i)&lt;/code&gt;&lt;/pre&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-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;578&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ouga8/btrEJxjTOdE/X72nobYYhs8KRm0R2baBqk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ouga8/btrEJxjTOdE/X72nobYYhs8KRm0R2baBqk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ouga8/btrEJxjTOdE/X72nobYYhs8KRm0R2baBqk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fouga8%2FbtrEJxjTOdE%2FX72nobYYhs8KRm0R2baBqk%2Fimg.png&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; loading=&quot;lazy&quot; width=&quot;409&quot; height=&quot;253&quot; data-origin-width=&quot;934&quot; data-origin-height=&quot;578&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Intent 의 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;FLAG_ACTIVITY_NEW_TASK&lt;/b&gt;&lt;/span&gt; 와 &lt;span style=&quot;background-color: #f6e199;&quot;&gt;&lt;b&gt;FLAG_ACTIVITY_CLEAR_TASK&lt;/b&gt;&lt;/span&gt;를 사용해 위 그림처럼 Activity 정보를 초기화할 수 있었습니다.&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;Intent의 내장 메소드에 대해 더 찾아보려면 안드로이드 공식 문서를 참고하시면 됩니다  &lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'Apple SD Gothic Neo', Arial, sans-serif; letter-spacing: 0px;&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;a href=&quot;https://developer.android.com/reference/android/content/Intent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.android.com/reference/android/content/Intent&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1655118430061&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;Intent &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;android.net.wifi.hotspot2.omadm&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/reference/android/content/Intent&quot; data-og-url=&quot;https://developer.android.com/reference/android/content/Intent&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Ppx56/hyOLeAERSE/860XbLkK3vrTdHsg4JEeD1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676&quot;&gt;&lt;a href=&quot;https://developer.android.com/reference/android/content/Intent&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/reference/android/content/Intent&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Ppx56/hyOLeAERSE/860XbLkK3vrTdHsg4JEeD1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676');&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;Intent &amp;nbsp;|&amp;nbsp; Android Developers&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;android.net.wifi.hotspot2.omadm&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;developer.android.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;</description>
      <category>개발/Android</category>
      <category>Activity</category>
      <category>FLAG_ACTIVITY_CLEAR_TASK</category>
      <category>FLAG_ACTIVITY_NEW_TASK</category>
      <category>intent</category>
      <category>안드로이드스튜디오</category>
      <category>앱 개발</category>
      <category>한번에 종료</category>
      <author>하루플스토리</author>
      <guid isPermaLink="true">https://haruple.tistory.com/224</guid>
      <comments>https://haruple.tistory.com/224#entry224comment</comments>
      <pubDate>Mon, 13 Jun 2022 20:12:51 +0900</pubDate>
    </item>
  </channel>
</rss>