<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>안드로이드 세계</title>
    <link>https://ryan94.tistory.com/</link>
    <description>안드로이드 및 알고리즘 정리</description>
    <language>ko</language>
    <pubDate>Fri, 19 Jun 2026 02:08:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>리안94</managingEditor>
    <item>
      <title>[Kotlin] 접근 제한자(public, private, internal, protected)</title>
      <link>https://ryan94.tistory.com/41</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기본적으로 코틀린은 모든 클래스, 변수들은 public으로 선언됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1680967779142&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 두가지는 동일한 내용
public val a = &quot;이것&quot;
val a = &quot;이것&quot;

public class A{
	...
}

class A{
	...
}&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;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style7&quot; /&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;public : Top Level 선언이 가능하며, 모든곳에서 접근이 가능합니다.&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;private : Top Level 선언이 가능하며, 같은 코틀린 파일내에서만 접근 가능합니다.&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;internal : Top Level 선언이 가능하며, 같은 모듈내에서만 접근 가능합니다. 따라서 해당 접근자를 통하여 모듈화를 쉽게 할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ &lt;span style=&quot;background-color: #c0d1e7;&quot;&gt;접근 시, 변수 또는 메소드는&amp;nbsp; internal 또는 private 접근 제한자&lt;/span&gt;를 가져야합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp; &amp;nbsp; (모듈 내에서만 접근 가능해야하는데, 외부에서 접근이 가능해진다면 모듈화가 깨지기 때문입니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1680969046007&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;internal class Utils{
    fun print() = print(&quot;A&quot;)
}

class B{
    val b = Utils() // 에러발생
    internal val c = Utils()
    private val d = Utils()
}&lt;/code&gt;&lt;/pre&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;protected : Top Level에서 선언이 불가능하며, 어떤 클래스 내 또는 해당 클래스를 상속받은 경우에 접근가능합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;※ Top-Level에서 protected 접근 제한자를 사용하면 아래와 같은 에러가 발생합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1681126111763&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;protected class C{ // Error
    ...
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;104&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnwEfA/btr88sodOG9/azWlAoyCi4Kkn7K1bV2Ep1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnwEfA/btr88sodOG9/azWlAoyCi4Kkn7K1bV2Ep1/img.png&quot; data-alt=&quot;Top-Level에서 protected 사용시 에러&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnwEfA/btr88sodOG9/azWlAoyCi4Kkn7K1bV2Ep1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnwEfA%2Fbtr88sodOG9%2FazWlAoyCi4Kkn7K1bV2Ep1%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;442&quot; height=&quot;104&quot; data-origin-width=&quot;442&quot; data-origin-height=&quot;104&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;Top-Level에서 protected 사용시 에러&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;pre id=&quot;code_1681126149452&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;open class A{
    protected val b = &quot;BB&quot;
}

class B : A(){
    val a = b
}

class C{
    val a = b // Error
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>안드로이드(Android)/이론</category>
      <category>internal</category>
      <category>Kotlin</category>
      <category>private</category>
      <category>Protected</category>
      <category>public</category>
      <category>접근제한자</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/41</guid>
      <comments>https://ryan94.tistory.com/41#entry41comment</comments>
      <pubDate>Mon, 10 Apr 2023 20:33:45 +0900</pubDate>
    </item>
    <item>
      <title>[Android] SnackBar 위치 조절</title>
      <link>https://ryan94.tistory.com/40</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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;예시 화면&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ezgif.com-gif-maker (2).gif&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/beYck4/btrCl2ny0kS/iE9k1rssOLaWLwzr3HrIK1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/beYck4/btrCl2ny0kS/iE9k1rssOLaWLwzr3HrIK1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/beYck4/btrCl2ny0kS/iE9k1rssOLaWLwzr3HrIK1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/beYck4/btrCl2ny0kS/iE9k1rssOLaWLwzr3HrIK1/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;406&quot; height=&quot;830&quot; data-filename=&quot;ezgif.com-gif-maker (2).gif&quot; data-origin-width=&quot;406&quot; data-origin-height=&quot;830&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;위의 예시 화면처럼 스낵바가 출력되게 된다면 아래에 있는 버튼은 누를 수가 없다.&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;u&gt;&lt;b&gt;예시 화면&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ezgif.com-gif-maker (3).gif&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;824&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/mnvqg/btrCrhw1ufS/KyQMSrsYPYZExKc2Bgl7e0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/mnvqg/btrCrhw1ufS/KyQMSrsYPYZExKc2Bgl7e0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/mnvqg/btrCrhw1ufS/KyQMSrsYPYZExKc2Bgl7e0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/mnvqg/btrCrhw1ufS/KyQMSrsYPYZExKc2Bgl7e0/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;402&quot; height=&quot;824&quot; data-filename=&quot;ezgif.com-gif-maker (3).gif&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;824&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652780579517&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)

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_short).setOnClickListener {
            createSnackBar(&quot;message_short&quot;, Snackbar.LENGTH_SHORT).apply{
                anchorView = findViewById(R.id.btn_indefinite) // 특정뷰 위로 스낵바 이동
            }.show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_long).setOnClickListener {
            createSnackBar(&quot;message_long&quot;, Snackbar.LENGTH_LONG).apply{
                anchorView = findViewById(R.id.btn_indefinite) // 특정뷰 위로 스낵바 이동
            }.show()
        }
    }

    private fun createSnackBar(message: String, duration: Int): Snackbar {
        return Snackbar.make(findViewById(R.id.root_const), message, duration)
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/40</guid>
      <comments>https://ryan94.tistory.com/40#entry40comment</comments>
      <pubDate>Tue, 17 May 2022 18:50:18 +0900</pubDate>
    </item>
    <item>
      <title>[Android] SnackBar Custom Layout</title>
      <link>https://ryan94.tistory.com/39</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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1652629839430&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)

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_short).setOnClickListener {
            createSnackBar(&quot;message_short&quot;, Snackbar.LENGTH_SHORT).show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_long).setOnClickListener {
            createSnackBar(&quot;message_long&quot;, Snackbar.LENGTH_LONG).show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_indefinite).setOnClickListener {
            createSnackBar(&quot;message_indefinite&quot;, Snackbar.LENGTH_INDEFINITE).setAction(&quot;Check&quot;) {
                createSnackBar(&quot;Click Event&quot;, Snackbar.LENGTH_SHORT).apply {
                    setCustomLayout()
                }.show()
            }.show()
        }
    }

    private fun createSnackBar(message: String, duration: Int): Snackbar {
        return Snackbar.make(findViewById(R.id.root_const), message, duration)
    }

    private fun Snackbar.setCustomLayout() {
        val customLayout = layoutInflater.inflate(R.layout.custom_snackbar, null)

        val snackBarLayout = this.view as Snackbar.SnackbarLayout
        snackBarLayout.apply {
            setPadding(0, 0, 0, 0)
            addView(customLayout)
        }
    }

}&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&lt;/p&gt;
&lt;pre id=&quot;code_1652629946900&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&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;
    android:layout_width=&quot;match_parent&quot;
    android:layout_height=&quot;match_parent&quot;
    xmlns:app=&quot;http://schemas.android.com/apk/res-auto&quot;&amp;gt;

    &amp;lt;ImageView
        android:id=&quot;@+id/iv_content&quot;
        android:layout_width=&quot;0dp&quot;
        android:src=&quot;@drawable/ic_launcher_background&quot;
        android:layout_height=&quot;match_parent&quot;
        app:layout_constraintWidth_percent=&quot;0.2&quot;
        app:layout_constraintLeft_toLeftOf=&quot;parent&quot;/&amp;gt;

    &amp;lt;TextView
        android:id=&quot;@+id/tv_content&quot;
        android:layout_width=&quot;0dp&quot;
        android:layout_height=&quot;match_parent&quot;
        android:textColor=&quot;@color/white&quot;
        android:text=&quot;커스텀 스낵바입니다.&quot;
        android:textStyle=&quot;bold&quot;
        android:gravity=&quot;center&quot;
        app:layout_constraintWidth_percent=&quot;0.6&quot;
        app:layout_constraintLeft_toRightOf=&quot;@id/iv_content&quot;
        app:layout_constraintRight_toLeftOf=&quot;@id/btn_action&quot;/&amp;gt;

    &amp;lt;Button
        android:id=&quot;@+id/btn_action&quot;
        android:layout_width=&quot;0dp&quot;
        android:layout_height=&quot;match_parent&quot;
        app:layout_constraintLeft_toRightOf=&quot;@id/tv_content&quot;
        app:layout_constraintRight_toRightOf=&quot;parent&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;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;u&gt;&lt;b&gt;예시 화면&lt;/b&gt;&lt;/u&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ezgif.com-gif-maker (1).gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLuDfQ/btrB6jv9Mau/0uIESCExYRVmxtcifx4050/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLuDfQ/btrB6jv9Mau/0uIESCExYRVmxtcifx4050/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLuDfQ/btrB6jv9Mau/0uIESCExYRVmxtcifx4050/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bLuDfQ/btrB6jv9Mau/0uIESCExYRVmxtcifx4050/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;400&quot; height=&quot;830&quot; data-filename=&quot;ezgif.com-gif-maker (1).gif&quot; data-origin-width=&quot;400&quot; data-origin-height=&quot;830&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/39</guid>
      <comments>https://ryan94.tistory.com/39#entry39comment</comments>
      <pubDate>Mon, 16 May 2022 00:52:54 +0900</pubDate>
    </item>
    <item>
      <title>[Android] SnackBar</title>
      <link>https://ryan94.tistory.com/38</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&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;nbsp;&lt;/li&gt;
&lt;li&gt;팝업 메세지로는 Toast와 SnackBar가 있는데, SnackBar가 Toast를 대체하고 있습니다.&lt;/li&gt;
&lt;li&gt;Android 12 (API 31) 이상을 타겟팅한다면 Toast는 다음과 같은 제약사항이 생깁니다.
&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;SnackBar에는 사&lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;용자가 실행할 수 있는 옵션이 포함되어 있습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;background-color: #ffffff; color: #202124;&quot;&gt;BackGround에서는 알림(Notification)을 이용하고, ForeGround에서는 SnackBar를 이용하는 것이 좋습니다.&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 id=&quot;coordinator&quot; data-text=&quot;CoordinatorLayout 사용&quot; data-ke-size=&quot;size26&quot;&gt;&lt;b&gt;&lt;span&gt;CoordinatorLayout&lt;/span&gt;&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;CoordinatorLayout을 이용하면 다음과 같은 기능이 추가됩니다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SnackBar를 스와이프 하여 닫을 수 있습니다.&lt;/li&gt;
&lt;li&gt;FloatingActionButton등을 이용할 때, 스낵바가 나타나면 해당 버튼이 스낵바 위로 이동합니다. (즉, 스낵바가 버튼을 덮지 않습니다.)&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;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 객체 생성&lt;/p&gt;
&lt;pre id=&quot;code_1652170095155&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val mySnackbar = SnackBar.make(view, message, duration)&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;view
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SnackBar를 연결할 뷰, 일반적으로 Content를 포함하고 있는 Layout에 연결을 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;message
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;SnackBar에 표시할 message 또는 message의 resourceId입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;duration
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;message를 표시할 기간입니다. LENGHT_LONG, LENGTH_SHORT, LENGTH_INDEFINITE 이 있습니다.&lt;/li&gt;
&lt;li&gt;LENGHT_LONG : 길게 출력&lt;/li&gt;
&lt;li&gt;LENGTH_SHORT : 짧게 출력&lt;/li&gt;
&lt;li&gt;LENGTH_&lt;span&gt;INDEFINITE&lt;span&gt; : 무기한 출력&lt;/span&gt;&lt;/span&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;p data-ke-size=&quot;size16&quot;&gt;2. 메시지 출력&lt;/p&gt;
&lt;pre id=&quot;code_1652172270911&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mySnackBar.show()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;현재 출력 중인 SnackBar가 존재하지 않는다면 즉시 출력되며, 출력중인 SnackBar가 있다면 출력중인 SnackBar메시지가 끝난 후에 출력이 됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1652180962534&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)

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_short).setOnClickListener {
            createSnackBar(&quot;message_short&quot;, Snackbar.LENGTH_SHORT).show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_long).setOnClickListener {
            createSnackBar(&quot;message_long&quot;, Snackbar.LENGTH_LONG).show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_indefinite).setOnClickListener {
            createSnackBar(&quot;message_indefinite&quot;, Snackbar.LENGTH_INDEFINITE).show()
        }
    }

    private fun createSnackBar(message: String, duration: Int) : Snackbar{
        return Snackbar.make(findViewById(R.id.root_const), message, duration)
    }

}&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;size18&quot;&gt;&lt;u&gt;&lt;b&gt;예시 화면&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;snackbar.gif&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;828&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/JMtKS/btrBYaS7HbU/wLEuXOZRW4zWPJZEKJKOd1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/JMtKS/btrBYaS7HbU/wLEuXOZRW4zWPJZEKJKOd1/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/JMtKS/btrBYaS7HbU/wLEuXOZRW4zWPJZEKJKOd1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/JMtKS/btrBYaS7HbU/wLEuXOZRW4zWPJZEKJKOd1/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;396&quot; height=&quot;828&quot; data-filename=&quot;snackbar.gif&quot; data-origin-width=&quot;396&quot; data-origin-height=&quot;828&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;액션 추가&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1652338550217&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val mySnackbar = SnackBar.make(view, message, duration)
mySnackbar.setAction(action){
	//TODO
}&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;action : 액션 명입니다. CharSequence 또는 Resourceid입니다.&lt;/li&gt;
&lt;/ul&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;※ SnackBar는 잠시 후 자동으로 사라지기 때문에 메시지를 보거나 버튼을 누를 수 있다는 기회를 기대할 수 없습니다. 이러한 이유로 작업을 수행하는 다른 방법을 제공하는 것을 고려해야 합니다.&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;예시 코드&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1652342592003&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)

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_short).setOnClickListener {
            createSnackBar(&quot;message_short&quot;, Snackbar.LENGTH_SHORT).show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_long).setOnClickListener {
            createSnackBar(&quot;message_long&quot;, Snackbar.LENGTH_LONG).show()
        }

        findViewById&amp;lt;Button&amp;gt;(R.id.btn_indefinite).setOnClickListener {
            createSnackBar(&quot;message_indefinite&quot;, Snackbar.LENGTH_INDEFINITE).setAction(&quot;Check&quot;){
                createSnackBar(&quot;Click Event&quot;, Snackbar.LENGTH_SHORT).show()
            }.show()
        }
    }

    private fun createSnackBar(message: String, duration: Int) : Snackbar{
        return Snackbar.make(findViewById(R.id.root_const), message, duration)
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;u&gt;&lt;b&gt;예시 화면&lt;/b&gt;&lt;/u&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;ezgif.com-gif-maker.gif&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;830&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/4vkqZ/btrBUHScj03/5TatfzcS8Uw0xaCm7BWvSK/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/4vkqZ/btrBUHScj03/5TatfzcS8Uw0xaCm7BWvSK/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/4vkqZ/btrBUHScj03/5TatfzcS8Uw0xaCm7BWvSK/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/4vkqZ/btrBUHScj03/5TatfzcS8Uw0xaCm7BWvSK/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;402&quot; height=&quot;830&quot; data-filename=&quot;ezgif.com-gif-maker.gif&quot; data-origin-width=&quot;402&quot; data-origin-height=&quot;830&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;&lt;a href=&quot;https://developer.android.com/training/snackbar/showing?hl=ko&quot;&gt;https://developer.android.com/training/snackbar/showing?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1652433990193&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;Snackbar를 사용하여 간략한 메시지를 표시할 수 있습니다. 이 메시지는 잠시 후에 자동으로 사라집니다. Snackbar는 사용자가 조치를 취할 필요가 없는 간략한 메시지에 적합합니다. 예를 들어 이메&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/training/snackbar/showing?hl=ko&quot; data-og-url=&quot;https://developer.android.com/training/snackbar/showing?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bzjlJt/hyOoAKE7VT/drlcQUNWA3TlV5o0WeVW71/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/snackbar/showing?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/training/snackbar/showing?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bzjlJt/hyOoAKE7VT/drlcQUNWA3TlV5o0WeVW71/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;Snackbar를 사용하여 간략한 메시지를 표시할 수 있습니다. 이 메시지는 잠시 후에 자동으로 사라집니다. Snackbar는 사용자가 조치를 취할 필요가 없는 간략한 메시지에 적합합니다. 예를 들어 이메&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/training/snackbar/action?hl=ko&quot;&gt;https://developer.android.com/training/snackbar/action?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1652434216367&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;사용자가 메시지에 응답할 수 있도록 Snackbar에 작업을 추가할 수 있습니다. Snackbar에 작업을 추가하면 Snackbar에서 메시지 텍스트 옆에 버튼을 둡니다. 버튼을 누르면 작업을 트리거할 수 있습니&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/training/snackbar/action?hl=ko&quot; data-og-url=&quot;https://developer.android.com/training/snackbar/action?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/MvVxb/hyOoFd8dyL/jyEMeAVHQuKF125J6Pehr1/img.png?width=800&amp;amp;height=476&amp;amp;face=0_0_800_476,https://scrap.kakaocdn.net/dn/wTHBm/hyOoD1GSgw/xqlNkUl5glIpqkGKogpckK/img.png?width=800&amp;amp;height=476&amp;amp;face=0_0_800_476&quot;&gt;&lt;a href=&quot;https://developer.android.com/training/snackbar/action?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/training/snackbar/action?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/MvVxb/hyOoFd8dyL/jyEMeAVHQuKF125J6Pehr1/img.png?width=800&amp;amp;height=476&amp;amp;face=0_0_800_476,https://scrap.kakaocdn.net/dn/wTHBm/hyOoD1GSgw/xqlNkUl5glIpqkGKogpckK/img.png?width=800&amp;amp;height=476&amp;amp;face=0_0_800_476');&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;사용자가 메시지에 응답할 수 있도록 Snackbar에 작업을 추가할 수 있습니다. Snackbar에 작업을 추가하면 Snackbar에서 메시지 텍스트 옆에 버튼을 둡니다. 버튼을 누르면 작업을 트리거할 수 있습니&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)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/38</guid>
      <comments>https://ryan94.tistory.com/38#entry38comment</comments>
      <pubDate>Thu, 12 May 2022 17:04:41 +0900</pubDate>
    </item>
    <item>
      <title>DialogFragment lifecycleScope 사용시 주의점</title>
      <link>https://ryan94.tistory.com/37</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;다이얼로그 프래그먼트에서 아무생각없이 일반 프래그먼트와 동일하게 lifecycleScope를 이용했었더니 다음과 같은 문제가 발생하였다.&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;init.gif&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;1078&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bfGbnl/btrnUO5edfE/OcByBBavNAOZCd10RKRrg0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bfGbnl/btrnUO5edfE/OcByBBavNAOZCd10RKRrg0/img.gif&quot; data-alt=&quot;초기설정이 무너지는 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bfGbnl/btrnUO5edfE/OcByBBavNAOZCd10RKRrg0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/bfGbnl/btrnUO5edfE/OcByBBavNAOZCd10RKRrg0/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;366&quot; height=&quot;725&quot; data-filename=&quot;init.gif&quot; data-origin-width=&quot;544&quot; data-origin-height=&quot;1078&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;
&lt;pre id=&quot;code_1639544054432&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@AndroidEntryPoint
class TestDialogFragment : DialogFragment() {

	...

    init {
        lifecycleScope.launch {
            whenResumed {
            	//초기세팅
            }
            whenCreated {
            	//초기 값 세팅
            }
        }
    }
}&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;di(hilt)를 이용해 다이얼로그를 싱글톤으로 생성해주는데, 첫 1회는 해당 lifecycleScope는 잘 동작하지만, 두번째 부터는 해당구문은 타지않는다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 문제를 해결하기위해서는 init에서 설정할 것이 아닌 onCreateView에서 설정해주어야한다. 또한 fragment의 lifecycleScope를 이용하는 것이 아닌 viewLifecycleOwner의 lifecycleScope를 이용해주어야한다.&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_1639544672230&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@AndroidEntryPoint
class TestDialogFragment : DialogFragment() {

	...

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        viewLifecycleOwner.lifecycleScope.launch {
            whenResumed {
                //초기 설정
            }
            whenCreated {
            	//초기 값 설정
            }
        }
        return super.onCreateView(inflater, container, savedInstanceState)
    }
}​&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-filename=&quot;onCreateView.gif&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;1080&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9P3DM/btrn0XsAEaM/hXTkoAyL8Zb6GHpunRVDM1/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9P3DM/btrn0XsAEaM/hXTkoAyL8Zb6GHpunRVDM1/img.gif&quot; data-alt=&quot;초기설정이 잘 유지되는 화면&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9P3DM/btrn0XsAEaM/hXTkoAyL8Zb6GHpunRVDM1/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/b9P3DM/btrn0XsAEaM/hXTkoAyL8Zb6GHpunRVDM1/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;366&quot; height=&quot;735&quot; data-filename=&quot;onCreateView.gif&quot; data-origin-width=&quot;538&quot; data-origin-height=&quot;1080&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;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <category>Android</category>
      <category>dialog fragment</category>
      <category>dialogfragment singleton</category>
      <category>lifecycleScope</category>
      <category>singleton</category>
      <category>다이얼로그 프래그먼트</category>
      <category>싱글톤</category>
      <category>안드로이드</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/37</guid>
      <comments>https://ryan94.tistory.com/37#entry37comment</comments>
      <pubDate>Wed, 15 Dec 2021 15:01:28 +0900</pubDate>
    </item>
    <item>
      <title>com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable 에러 해결법</title>
      <link>https://ryan94.tistory.com/36</link>
      <description>&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-origin-width=&quot;1453&quot; data-origin-height=&quot;256&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dFVVBq/btq9aeiWpP4/xfKOx6fSh8w29qXkSL8t8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dFVVBq/btq9aeiWpP4/xfKOx6fSh8w29qXkSL8t8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dFVVBq/btq9aeiWpP4/xfKOx6fSh8w29qXkSL8t8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdFVVBq%2Fbtq9aeiWpP4%2FxfKOx6fSh8w29qXkSL8t8K%2Fimg.png&quot; data-origin-width=&quot;1453&quot; data-origin-height=&quot;256&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당에러 해결법은 간단한데, 다음과같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. gradle.properties를 연다.&lt;/p&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;span style=&quot;background-color: #ffffff; color: #000000;&quot;&gt; android.enableJetifier=true 를 추가해준다.&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;2의 역할은 third party 라이브러리들을 androidx로 변환해준다는 의미이다.&lt;/p&gt;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/36</guid>
      <comments>https://ryan94.tistory.com/36#entry36comment</comments>
      <pubDate>Fri, 9 Jul 2021 13:43:32 +0900</pubDate>
    </item>
    <item>
      <title>Data Class vs Class</title>
      <link>https://ryan94.tistory.com/35</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Data Class는 데이터 보관 목적으로 만들어진 클래스인데, 일반 Class와 달리 toString(), copy(), hashCode(), equals()를 자동으로 구현해줍니다.&lt;/p&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: #242729;&quot;&gt;boilerplate&lt;span&gt; Code를 줄여주는 장점이있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1625251101738&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;data class User(val userId: String, val userName: String)

class NormalClassUser(val userId: String, val userName: String)&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1625250942746&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val user = User(&quot;user1&quot;, &quot;ryan&quot;)
val user2 = user.copy()
val normalUser = NormalClassUser(&quot;user2&quot;, &quot;ryan2&quot;)
val normalUser2 = normalUser.copy() // Class는 Copy가 구현되어있지않기때문에 error발생



user.also {
    Log.e(&quot;Data Class&quot;, &quot;userId -&amp;gt; ${it.userId} userName -&amp;gt; ${it.userName} toString -&amp;gt; $it hashCode -&amp;gt; ${it.hashCode()}&quot;)
}

normalUser.also {
    Log.e(&quot;Class&quot;, &quot;userId -&amp;gt; ${it.userId} userName -&amp;gt; ${it.userName} toString-&amp;gt; $it hashCode -&amp;gt; ${it.hashCode()}&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;span style=&quot;color: #242729;&quot;&gt;&lt;span&gt;아래의 코드는 로그입니다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242729;&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1625250981658&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;E/Data&amp;nbsp;Class: userId -&amp;gt; user1 userName -&amp;gt; ryan toString -&amp;gt; User(userId=user1, userName=ryan) hashCode -&amp;gt; -832516178
E/Class: userId -&amp;gt; user2 userName -&amp;gt; ryan2 toString-&amp;gt; kr.ryan.comparedataclasswithclass.NormalClassUser@14cb62b hashCode -&amp;gt; 21804587&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;span style=&quot;color: #242729;&quot;&gt;&lt;span&gt;로그의 결과처럼 차이점은 copy가 구현되어있지 않은 점&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #242729;&quot;&gt;&lt;span&gt;객체를 출력하였을 때 Class는 객체의 주소가 나오는 점과, Data Class는 객체의 내용이 출력되는 점이 다른 것을 확인할 수 있습니다.&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;span style=&quot;color: #242729;&quot;&gt;&lt;span&gt;Data Class의 특징은 다음과 같습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;생성자에는 한 개 이상의 프로퍼티를 가져야 한다.&lt;/li&gt;
&lt;li&gt;프로퍼티는 var 또는 val로 선언되어야 한다.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #242729;&quot;&gt;abstract, open, inner 등을 붙일 수 없습니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #242729;&quot;&gt;toString(), copy(), hashCode(), equals() 자동으로 구현해줍니다.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #242729;&quot;&gt;상속이 불가능합니다.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&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;color: #242729;&quot;&gt;정리&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;color: #242729;&quot;&gt;Entity를 이용할 때에는 데이터 클래스를 사용하게 됩니다. 그 이유로는 &lt;/span&gt;&lt;span style=&quot;color: #242729;&quot;&gt;1. 일반적으로 구현해야 하는 메서드(toString(), equals(), hashCode(), copy())등을 자동으로 만들어주어 &lt;span style=&quot;color: #242729;&quot;&gt;boilerplate&lt;/span&gt;&lt;span style=&quot;color: #242729;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Code 줄여줍니다.&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #242729;&quot;&gt;2. 일반적인 메서드를&amp;nbsp;자동으로 구현해주기 때문에 코드의 간결성이 올라가 가독성이 증가합니다.&lt;/span&gt;&lt;span style=&quot;color: #242729;&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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #242729;&quot;&gt;참고&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #242729;&quot;&gt;&lt;a href=&quot;https://codechacha.com/ko/kotlin-destructuring-declarations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://codechacha.com/ko/kotlin-destructuring-declarations/&lt;/a&gt;&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1625251264768&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;Kotlin - Destructuring Declaration&quot; data-og-description=&quot;Destructuring Declaration은 어떤 객체의 데이터를 변수들에 대입하는 기술입니다. 이 기술은 코드의 가독성을 높여주며 코드의 길이를 줄여줍니다. 데이터 클래스가 이런 기능을 기본으로 지원하며, &quot; data-og-host=&quot;codechacha.com&quot; data-og-source-url=&quot;https://codechacha.com/ko/kotlin-destructuring-declarations/&quot; data-og-url=&quot;https://codechacha.com/ko/kotlin-destructuring-declarations/&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/WdwQk/hyKLwFLetr/jkEh5nIp8mTSNafBJybhrk/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192&quot;&gt;&lt;a href=&quot;https://codechacha.com/ko/kotlin-destructuring-declarations/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://codechacha.com/ko/kotlin-destructuring-declarations/&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/WdwQk/hyKLwFLetr/jkEh5nIp8mTSNafBJybhrk/img.png?width=192&amp;amp;height=192&amp;amp;face=0_0_192_192');&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 - Destructuring Declaration&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Destructuring Declaration은 어떤 객체의 데이터를 변수들에 대입하는 기술입니다. 이 기술은 코드의 가독성을 높여주며 코드의 길이를 줄여줍니다. 데이터 클래스가 이런 기능을 기본으로 지원하며,&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;codechacha.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;문제가 될 시 포스팅을 삭제하겠습니다.&lt;/p&gt;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/35</guid>
      <comments>https://ryan94.tistory.com/35#entry35comment</comments>
      <pubDate>Sat, 3 Jul 2021 03:42:47 +0900</pubDate>
    </item>
    <item>
      <title>[Android] WorkManager 특정시간알림</title>
      <link>https://ryan94.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;AlarmManager처럼 특정시간을 세팅해준다면 아주편하게 사용할 수 있겠지만, WorkManager는 불가능하다.&lt;/p&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_1622522035227&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun getCertainTime(): Long{

    val currentDate = Calendar.getInstance()
    val dueDate = Calendar.getInstance().apply {

        set(Calendar.HOUR_OF_DAY, 2)
        set(Calendar.MINUTE, 20)
        set(Calendar.SECOND, 0)

    }

    if (dueDate.before(currentDate))
        dueDate.add(Calendar.HOUR_OF_DAY, 24)

    return dueDate.timeInMillis - currentDate.timeInMillis
}&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;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622522732593&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class WorkApplication : Application() {

    private val backgroundCoroutineScope = CoroutineScope(Dispatchers.Default)

    override fun onCreate() {
        super.onCreate()
        delayCreateWork()
    }

    private fun delayCreateWork(){
        backgroundCoroutineScope.launch {
            createWorkManager()
        }
    }

    private fun createWorkManager(){
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.UNMETERED)
            .setRequiresBatteryNotLow(true)
            .setRequiresCharging(true)
            .setRequiresStorageNotLow(true)
            .build()

        val oneTimeWorkRequest = OneTimeWorkRequestBuilder&amp;lt;Worker&amp;gt;().
            setInitialDelay(getCertainTime(), TimeUnit.MILLISECONDS).
            setConstraints(constraints).build()

        WorkManager.getInstance(applicationContext).enqueueUniqueWork(Worker.WORK_NAME, ExistingWorkPolicy.KEEP, oneTimeWorkRequest)
    }
}&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;pre id=&quot;code_1622522838220&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Worker(appContext: Context, parameters: WorkerParameters) : CoroutineWorker(appContext, parameters) {

    companion object{
        const val WORK_NAME = &quot;Notification Work&quot;
    }

    override suspend fun doWork(): Result {

        try { 
            //Work
            
            val constraints = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)
                .setRequiresBatteryNotLow(true)
                .setRequiresCharging(true)
                .setRequiresStorageNotLow(true)
                .build()

            val oneTimeWorkRequest = OneTimeWorkRequestBuilder&amp;lt;Worker&amp;gt;().
                setInitialDelay(getCertainTime(), TimeUnit.MILLISECONDS).
                setConstraints(constraints).build()

            WorkManager.getInstance(applicationContext).enqueueUniqueWork(Worker.WORK_NAME, ExistingWorkPolicy.REPLACE, oneTimeWorkRequest)

        }catch (e: Exception){
            Result.retry()
        }

        return Result.success()
    }

}&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;워커에서는 REPLACE로 작업을 세팅해주어야하는데, 그이유는 워커에 등록된 이전 작업이 완전히종료가된상태가 아니기때문이다.&lt;/p&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;1분마다 세팅한 결과&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TaKa6/btq6cUuVQLG/9ykwhZ9HHjK5AJzxvvlp91/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TaKa6/btq6cUuVQLG/9ykwhZ9HHjK5AJzxvvlp91/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TaKa6/btq6cUuVQLG/9ykwhZ9HHjK5AJzxvvlp91/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTaKa6%2Fbtq6cUuVQLG%2F9ykwhZ9HHjK5AJzxvvlp91%2Fimg.png&quot; data-origin-width=&quot;745&quot; data-origin-height=&quot;143&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&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://github.com/pyg1007/WorkManager-Sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/pyg1007/WorkManager-Sample&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1622524386814&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;pyg1007/WorkManager-Sample&quot; data-og-description=&quot;Contribute to pyg1007/WorkManager-Sample development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/pyg1007/WorkManager-Sample&quot; data-og-url=&quot;https://github.com/pyg1007/WorkManager-Sample&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/b4pUGX/hyKqQYkGli/65VrakaqnsgZOGKnPn5660/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/pyg1007/WorkManager-Sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/pyg1007/WorkManager-Sample&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/b4pUGX/hyKqQYkGli/65VrakaqnsgZOGKnPn5660/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;pyg1007/WorkManager-Sample&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to pyg1007/WorkManager-Sample development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/34</guid>
      <comments>https://ryan94.tistory.com/34#entry34comment</comments>
      <pubDate>Tue, 1 Jun 2021 14:24:47 +0900</pubDate>
    </item>
    <item>
      <title>[Android] WorkManager</title>
      <link>https://ryan94.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;백그라운드에서 작업을 실행하면 RAM 및 배터리와 같은 제한된 리소스가 소모됩니다.&lt;/p&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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;화면이 꺼져있고, 기기가 유휴 상태이고 충전중이 아닌 경우&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;백그라운드 위치제한
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;백그라운드 앱이 사용자의 현재 위치를 검색할 수 있는 빈도를 제한&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;백그라운드 서비스 제한
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&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;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&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;지연 가능한 비동기 작업을 쉽게 예약할 수 있는 API&lt;br /&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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: circle;&quot; data-ke-list-type=&quot;circle&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;371&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkdfI6/btq58YRoHZm/qf0afXf4Zx6Kt9jf1yhSK1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkdfI6/btq58YRoHZm/qf0afXf4Zx6Kt9jf1yhSK1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkdfI6/btq58YRoHZm/qf0afXf4Zx6Kt9jf1yhSK1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkdfI6%2Fbtq58YRoHZm%2Fqf0afXf4Zx6Kt9jf1yhSK1%2Fimg.png&quot; data-origin-width=&quot;610&quot; data-origin-height=&quot;371&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;백그라운드 실행 방법&lt;/b&gt;&lt;/h3&gt;
&lt;table style=&quot;border-collapse: collapse; width: 91.7548%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2825%;&quot;&gt;사용사례&lt;/td&gt;
&lt;td style=&quot;width: 36.4837%;&quot;&gt;예&lt;/td&gt;
&lt;td style=&quot;width: 20.7794%;&quot;&gt;해결책&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2825%;&quot;&gt;연기 가능한 작업 실행보장&lt;/td&gt;
&lt;td style=&quot;width: 36.4837%;&quot;&gt;서버에 로그 업로드&lt;br /&gt;다운로드 / 업로드 콘텐츠 암호화/ 복호화&lt;br /&gt;데이터베이스 동기화&lt;/td&gt;
&lt;td style=&quot;width: 20.7794%;&quot;&gt;WorkManager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2825%;&quot;&gt;외부 이벤트에 대한 응답으로 시작된 작업&lt;/td&gt;
&lt;td style=&quot;width: 36.4837%;&quot;&gt;이메일과 같은 온라인 콘텐츠 동기화&lt;/td&gt;
&lt;td style=&quot;width: 20.7794%;&quot;&gt;FCM + WorkManager&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2825%;&quot;&gt;앱을 종료하더라도 즉시 실행해야하는 작업&lt;/td&gt;
&lt;td style=&quot;width: 36.4837%;&quot;&gt;음악플레이어&lt;br /&gt;활동 추적&lt;br /&gt;네비게이션&lt;/td&gt;
&lt;td style=&quot;width: 20.7794%;&quot;&gt;Foreground Service&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 37.2825%;&quot;&gt;정확한 시간에 알림과 같이 사용자 상호 작용과 관련된 작업을 트리거&lt;/td&gt;
&lt;td style=&quot;width: 36.4837%;&quot;&gt;알람 시계&lt;br /&gt;의학 알림&lt;/td&gt;
&lt;td style=&quot;width: 20.7794%;&quot;&gt;AlarmManager&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&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;b&gt;작업 제약조건&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 120px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;옵션&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;NetworkType&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;작업이 필요한 네트워크 유형을 제한합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;BatteryNotLow&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;기기의 배터리 부족모드인경우 작업을 제한여부를 설정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;RequiresCharging&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;기기가 충전중인 경우에만 작업을 실행할 여부를 설정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;DeviceIdle&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;기기가 유휴상태에서만 작업할 여부를 설정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 22.5581%; height: 20px;&quot;&gt;StorageNotLow&lt;/td&gt;
&lt;td style=&quot;width: 77.4419%; height: 20px;&quot;&gt;기기의 저장공간이 부족한 경우 작업할 여부를 설정합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;NetworkType의 종류&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 21.0465%; height: 20px;&quot;&gt;옵션&lt;/td&gt;
&lt;td style=&quot;width: 78.9535%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 21.0465%; height: 20px;&quot;&gt;CONNECTED&lt;/td&gt;
&lt;td style=&quot;width: 78.9535%; height: 20px;&quot;&gt;네트워크가 연결되어있는 경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 21.0465%; height: 20px;&quot;&gt;UNMETERED&lt;/td&gt;
&lt;td style=&quot;width: 78.9535%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #202124;&quot;&gt;무제한 네트워크&lt;/span&gt;에 연결되어있는경우 ex) Wifi&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 21.0465%; height: 20px;&quot;&gt;METERED&lt;/td&gt;
&lt;td style=&quot;width: 78.9535%; height: 20px;&quot;&gt;데이터 통신망에 연결되어있는경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 21.0465%; height: 20px;&quot;&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;NOT&lt;/span&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;REQUIRED&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.9535%; height: 20px;&quot;&gt;네트워크가 필요없는경우&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 21.0465%;&quot;&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;NOT&lt;/span&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;_&lt;/span&gt;&lt;span style=&quot;background-color: rgba(255, 255, 255, 0.95); color: #37474f;&quot;&gt;ROAMING&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;td style=&quot;width: 78.9535%;&quot;&gt;비 로밍 네트워크가 연결이되어있는경우&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;i&gt;&lt;b&gt;사용방법&lt;/b&gt;&lt;/i&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1622468002028&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private fun createConstraints() : Constraints{
    return Constraints.Builder()
        .setRequiredNetworkType(NetworkType.UNMETERED)
        .setRequiresBatteryNotLow(true)
        .setRequiresCharging(true)
        .apply {
            if (Build.VERSION.SDK_INT &amp;gt;= Build.VERSION_CODES.Q)
                setRequiresDeviceIdle(true)
        }
        .setRequiresStorageNotLow(true)
        .build()
}&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;b&gt;강력한 예약 관리&lt;/b&gt;&lt;b&gt;&lt;/b&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;pre id=&quot;code_1622469097664&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private fun createWorkManager(){

    val periodicWorkRequest = PeriodicWorkRequestBuilder&amp;lt;Worker&amp;gt;(1, TimeUnit.DAYS).build()

    WorkManager.getInstance(applicationContext).enqueueUniqueWork(&quot;work&quot;, ExistingWorkPolicy.KEEP, periodicWorkRequest)
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;하루마다 실행하도록 구성됨&lt;/li&gt;
&lt;li&gt;enqueueUniqueWork로 워크 매니저에 등록&lt;/li&gt;
&lt;li&gt;UniqueWorkName, 같은 이름을 가진다면 정책을 정하고, Request를 넣어준다.&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;pre id=&quot;code_1622469384592&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private fun createWorkManager(){
   
    val oneTimeWorkRequest = OneTimeWorkRequestBuilder&amp;lt;Worker&amp;gt;().build()

    WorkManager.getInstance(applicationContext).enqueueUniqueWork(&quot;A&quot;, ExistingWorkPolicy.KEEP, oneTimeWorkRequest)
    
}&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;정책&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 100px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.2326%; height: 20px;&quot;&gt;옵션&lt;/td&gt;
&lt;td style=&quot;width: 79.7674%; height: 20px;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.2326%; height: 20px;&quot;&gt;APPEND&lt;/td&gt;
&lt;td style=&quot;width: 79.7674%; height: 20px;&quot;&gt;동일한 고유이름을 가지고 완료되지않은 작업이 있다면 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.2326%; height: 20px;&quot;&gt;APPEND_OR_REPLACE&lt;/td&gt;
&lt;td style=&quot;width: 79.7674%; height: 20px;&quot;&gt;동일한 고유이름을 가지고 완료되지않은 작업이 있다면 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.2326%; height: 20px;&quot;&gt;KEEP&lt;/td&gt;
&lt;td style=&quot;width: 79.7674%; height: 20px;&quot;&gt;동일한 고유이름을 가지고 완료되지않은 작업이 있다면 아무런 일을 하지않는다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 20.2326%; height: 20px;&quot;&gt;REPLACE&lt;/td&gt;
&lt;td style=&quot;width: 79.7674%; height: 20px;&quot;&gt;동일한 고유이름을 가지고 완료되지않은 작업이 있다면 취소하고 삭제한뒤 실행한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;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;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&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;&amp;nbsp;&lt;b&gt;재시도 정책&lt;/b&gt;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style8&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.1395%;&quot;&gt;옵션&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%;&quot;&gt;설명&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.1395%;&quot;&gt;Result.success()&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%;&quot;&gt;작업이 성공적으로 완료되었습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.1395%;&quot;&gt;Result.failure()&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%;&quot;&gt;작업에 실패하였습니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 18.1395%;&quot;&gt;Result.retry()&lt;/td&gt;
&lt;td style=&quot;width: 81.8605%;&quot;&gt;재시도 정책에 따라 다른시점에 시도&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622469695967&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Worker(appContext: Context, parameters: WorkerParameters) : CoroutineWorker(appContext, parameters) {

    override suspend fun doWork(): Result {

        try {

            //Work

        }catch (e: Exception){
            Result.retry()
        }

        return Result.success()
    }

}&lt;/code&gt;&lt;/pre&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;작업 체이닝&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;복잡한 작업인 경우 인터페이스를 이용하여 순차적으로 동작하게 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1622469809033&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;WorkManager.getInstance(...)
    .beginWith(listOf(workA,workB))
    .then(workC)
    .enqueue()&lt;/code&gt;&lt;/pre&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;내장 스레딩 상호 운용성&lt;/b&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;RxJava, Coroutine 등을 사용할 수 있다.&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;p data-ke-size=&quot;size16&quot;&gt;위의 내용을 통해서 wifi를 이용해야 하며, 배터리가 부족하면 안 되고, 충전 중이여 야만 하고, 저장공간이 충분한 경우, 진행 중인 작업이 있는 경우는 작업을 하지 않는 일회성 작업을 구성하는 내용은 아래와 같이 구성할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Work.class&lt;/p&gt;
&lt;pre id=&quot;code_1622470113201&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class Worker(appContext: Context, parameters: WorkerParameters) : CoroutineWorker(appContext, parameters) {

    companion object{
        const val WORK_NAME = &quot;Notification Work&quot;
    }

    override suspend fun doWork(): Result {

        try {

            //Work

        }catch (e: Exception){
            Result.retry()
        }

        return Result.success()
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Application클래스가 가장 먼저 생성되기 때문에 Application의 onCreate에서 작업을 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1622470176806&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class WorkApplication : Application() {

    private val backgroundCoroutineScope = CoroutineScope(Dispatchers.Default)

    override fun onCreate() {
        super.onCreate()
        delayCreateWork()
    }

    private fun delayCreateWork(){
        backgroundCoroutineScope.launch { 
            createWorkManager()
        }
    }

    private fun createWorkManager(){
        val constraints = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.UNMETERED)
            .setRequiresBatteryNotLow(true)
            .setRequiresCharging(true)
            .setRequiresStorageNotLow(true)
            .build()

        val oneTimeWorkRequest = OneTimeWorkRequestBuilder&amp;lt;Worker&amp;gt;().
            setConstraints(constraints).build()

        WorkManager.getInstance(applicationContext).enqueueUniqueWork(Worker.WORK_NAME, ExistingWorkPolicy.KEEP, oneTimeWorkRequest)
    }
}&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;코 루틴을 이용한 이유는, onCreate에서 바로 실행을 하게 되면 기본 스레드에서 실행이 되기 때문에 앱 로드가 지연되거나 UI스레드가 차단될 수 있기 때문에 사용해주는 것이 좋다.&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;b&gt;※ 참고사이트&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1622460080638&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;Modern background execution in Android&quot; data-og-description=&quot;Posted by Luiz Gustavo Martins, Partner Developer Advocate, Partner DevRel This is the third in a series of blog posts in which outli...&quot; data-og-host=&quot;android-developers.googleblog.com&quot; data-og-source-url=&quot;https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html&quot; data-og-url=&quot;https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/OQ88U/hyKo0uc23q/1Osj9k85nKJHTwCIu6ZGj0/img.png?width=960&amp;amp;height=504&amp;amp;face=0_0_960_504,https://scrap.kakaocdn.net/dn/blQcLR/hyKo0nsFLC/lLDVAKTUp9HrVkbNuDaKn1/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540&quot;&gt;&lt;a href=&quot;https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://android-developers.googleblog.com/2018/10/modern-background-execution-in-android.html&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/OQ88U/hyKo0uc23q/1Osj9k85nKJHTwCIu6ZGj0/img.png?width=960&amp;amp;height=504&amp;amp;face=0_0_960_504,https://scrap.kakaocdn.net/dn/blQcLR/hyKo0nsFLC/lLDVAKTUp9HrVkbNuDaKn1/img.png?width=960&amp;amp;height=540&amp;amp;face=0_0_960_540');&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;Modern background execution in Android&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Posted by Luiz Gustavo Martins, Partner Developer Advocate, Partner DevRel This is the third in a series of blog posts in which outli...&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;android-developers.googleblog.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://developer.android.com/codelabs/kotlin-android-training-work-manager?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fkotlin-fundamentals-nine%23codelab-%2Fcodelabs%2Fkotlin-android-training-work-manager#0&quot;&gt;https://developer.android.com/codelabs/kotlin-android-training-work-manager?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fkotlin-fundamentals-nine%23codelab-%2Fcodelabs%2Fkotlin-android-training-work-manager#0&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1622460116935&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;Android Kotlin Fundamentals: WorkManager &amp;nbsp;|&amp;nbsp; Android 개발자&quot; data-og-description=&quot;In this codelab, you learn how to use WorkManager to schedule background tasks in an efficient and optimized way in your Android Kotlin app.&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/codelabs/kotlin-android-training-work-manager?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fkotlin-fundamentals-nine%23codelab-%2Fcodelabs%2Fkotlin-android-training-work-manager#0&quot; data-og-url=&quot;https://developer.android.com/codelabs/kotlin-android-training-work-manager?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/c74t8M/hyKo26FxUS/O9UKAZalyFWKsHC9mpnIp1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/dlCEFO/hyKoUOjwuo/mP5m3mkkruRW8dnGgMKHUK/img.png?width=1174&amp;amp;height=1204&amp;amp;face=0_0_1174_1204,https://scrap.kakaocdn.net/dn/bthTb5/hyKo4pSi5V/yYRNOoNliFMzBdSptLmj9k/img.png?width=800&amp;amp;height=505&amp;amp;face=0_0_800_505&quot;&gt;&lt;a href=&quot;https://developer.android.com/codelabs/kotlin-android-training-work-manager?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fkotlin-fundamentals-nine%23codelab-%2Fcodelabs%2Fkotlin-android-training-work-manager#0&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/codelabs/kotlin-android-training-work-manager?continue=https%3A%2F%2Fdeveloper.android.com%2Fcourses%2Fpathways%2Fkotlin-fundamentals-nine%23codelab-%2Fcodelabs%2Fkotlin-android-training-work-manager#0&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/c74t8M/hyKo26FxUS/O9UKAZalyFWKsHC9mpnIp1/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/dlCEFO/hyKoUOjwuo/mP5m3mkkruRW8dnGgMKHUK/img.png?width=1174&amp;amp;height=1204&amp;amp;face=0_0_1174_1204,https://scrap.kakaocdn.net/dn/bthTb5/hyKo4pSi5V/yYRNOoNliFMzBdSptLmj9k/img.png?width=800&amp;amp;height=505&amp;amp;face=0_0_800_505');&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;Android Kotlin Fundamentals: WorkManager &amp;nbsp;|&amp;nbsp; Android 개발자&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;In this codelab, you learn how to use WorkManager to schedule background tasks in an efficient and optimized way in your Android Kotlin app.&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;a href=&quot;https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko&quot;&gt;https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;figure id=&quot;og_1622460204479&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;WorkManager로 작업 예약 &amp;nbsp;|&amp;nbsp; Android 개발자 &amp;nbsp;|&amp;nbsp; Android Developers&quot; data-og-description=&quot;WorkManager로 작업 예약&amp;nbsp;&amp;nbsp;Android Jetpack의 일부 WorkManager는 지연 가능한 비동기 작업을 쉽게 예약할 수 있는 API로, 지연 가능한 비동기 작업은 앱이 종료되거나 기기가 다시 시작되더라도 실행될 것&quot; data-og-host=&quot;developer.android.com&quot; data-og-source-url=&quot;https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko&quot; data-og-url=&quot;https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/Gd2w5/hyKoYwqDny/vcfXuYdlkhGzqhPFW95G7k/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/htybs/hyKoSwdBhe/n0W4HrlVn3cmCt093NvZl1/img.png?width=1704&amp;amp;height=798&amp;amp;face=0_0_1704_798&quot;&gt;&lt;a href=&quot;https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://developer.android.com/topic/libraries/architecture/workmanager?hl=ko&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/Gd2w5/hyKoYwqDny/vcfXuYdlkhGzqhPFW95G7k/img.png?width=1201&amp;amp;height=676&amp;amp;face=0_0_1201_676,https://scrap.kakaocdn.net/dn/htybs/hyKoSwdBhe/n0W4HrlVn3cmCt093NvZl1/img.png?width=1704&amp;amp;height=798&amp;amp;face=0_0_1704_798');&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;WorkManager로 작업 예약 &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;WorkManager로 작업 예약&amp;nbsp;&amp;nbsp;Android Jetpack의 일부 WorkManager는 지연 가능한 비동기 작업을 쉽게 예약할 수 있는 API로, 지연 가능한 비동기 작업은 앱이 종료되거나 기기가 다시 시작되더라도 실행될 것&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)/코틀린(Kotlin)</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/33</guid>
      <comments>https://ryan94.tistory.com/33#entry33comment</comments>
      <pubDate>Mon, 31 May 2021 23:15:17 +0900</pubDate>
    </item>
    <item>
      <title>[Android] ScrollView의 Child View Height 문제</title>
      <link>https://ryan94.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Nanum Gothic';&quot;&gt;ScrollView를 이용하거나, NestedScrollView를 이용할 때 자식 뷰그룹으로 ConstraintLayout을 지정할 때가 있다.&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;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;ConstraintLayout의 자식 뷰의 &lt;/span&gt;높이를 0dp로 준후에 layout_constraintHeight_percent를 이용해서 크기를 지정할때에는 자식 뷰그룹인 ConstraintLayout의 높이는 0dp이기 때문에 뷰가 그려지지 않는다.&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;font-family: 'Nanum Gothic';&quot;&gt;검색을 하게되면&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;ScrollView 또는 &lt;span style=&quot;color: #333333;&quot;&gt;NestedScrollView에 &lt;span&gt;android&lt;/span&gt;&lt;span&gt;:fillViewport&lt;/span&gt;&lt;span&gt;=&quot;true&quot;로 설정 하라는 글들이 많다.&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 style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;실제로 사용해보면 &lt;span style=&quot;color: #333333;&quot;&gt;ScrollView 또는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;NestedScrollView&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 style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;하지만 percent를 이용해서 크기를 지정한 경우에는 사용할 수가없다.&amp;nbsp;&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 style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;잘 되는 것처럼 xml의 Design탭에서는 나오지만 스크롤 가능할만큼 높이를 주었음에도 불구하고 스크롤은 되지않는다.&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 style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&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 style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&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 style=&quot;font-family: 'Nanum Gothic';&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&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;pre id=&quot;code_1619811800694&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun Context.getDeviceHeight(): Int { // 디바이스의 높이를 구한다.

    val windowManager = getSystemService(Context.WINDOW_SERVICE) as WindowManager
    return if (Build.VERSION.SDK_INT &amp;gt;= 30) {
        windowManager.currentWindowMetrics.bounds.height()
    } else {
        val display = windowManager.defaultDisplay
        val size = Point()
        display.getSize(size)
        size.y
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1619811822334&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;fun resizeViewHeight(deviceHeight: Int, view: View, height: Float) { // 뷰의 크기를 조절한다.
    val layoutParams = view.layoutParams
    layoutParams.height = (deviceHeight * height).toInt()
    view.layoutParams = layoutParams
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;사용은 이렇게 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1619812291855&quot; class=&quot;kotlin&quot; data-ke-language=&quot;kotlin&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//Fragment
private fun resizingViewHeight() {
    val deviceHeight = requireContext().getDeviceHeight()
    resizeViewHeight(deviceHeight, view, 0.05f)
}

//Activity
private fun resizingViewHeight() {
    val deviceHeight = getDeviceHeight()
    resizeViewHeight(deviceHeight, view, 0.05f)
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;잘못된 내용이나 더 조언해줄방법이있다면 댓글로알려주세요~!&lt;/p&gt;</description>
      <category>안드로이드(Android)/코틀린(Kotlin)</category>
      <category>NestedScrollView</category>
      <category>scrollview</category>
      <category>ScrollView Child View Height Programmatically</category>
      <category>ScrollView with ConstraintLayout</category>
      <category>스크롤뷰 자식 뷰 높이 동적조절</category>
      <author>리안94</author>
      <guid isPermaLink="true">https://ryan94.tistory.com/32</guid>
      <comments>https://ryan94.tistory.com/32#entry32comment</comments>
      <pubDate>Sat, 1 May 2021 12:55:29 +0900</pubDate>
    </item>
  </channel>
</rss>