<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>seoft</title>
    <link>https://seoft.tistory.com/</link>
    <description>https://github.com/seoft
https://play.google.com/store/apps/developer?id=seoft</description>
    <language>ko</language>
    <pubDate>Sun, 5 Apr 2026 10:59:34 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>seoft</managingEditor>
    <item>
      <title>컴포즈 프리뷰 에러 원인 중 일부 분석</title>
      <link>https://seoft.tistory.com/95</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;[ compose compiler 1.5.10 / compose_bom androidx.compose:compose-bom:2024.12.01 ] 기준&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴포즈 프리뷰내 구성된 컴포즈 root 를 포함한 모든 하위 구성이 참조하는 코틀린 파일의 모든 멤버변수를 읽고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;멤버변수가 주입이 덜된 구성이거나 오류를 발생할 경우 preview error 를 유발&lt;/p&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;A.kt 구성이 다음과 같고&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;val version = &quot;1.0&quot;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;val error = &quot;&quot;.let {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;error(&quot;error&quot;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&quot;&quot;&lt;/span&gt;&lt;br /&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;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프리뷰의 컴포즈가 A.version 만 사용한다 가정했을때&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;error 는 사용하지 않지만 A.kt 의 멤버 프로퍼티를 읽으면서 오류발생&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;error 프로퍼티를 삭제하거나 다음처럼 처리하면 정상동작&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;val error by lazy {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&quot;&quot;.let {&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;error(&quot;error&quot;)&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&quot;&quot;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;}&lt;/span&gt;&lt;br /&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;</description>
      <category>android</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/95</guid>
      <comments>https://seoft.tistory.com/95#entry95comment</comments>
      <pubDate>Tue, 18 Mar 2025 22:22:44 +0900</pubDate>
    </item>
    <item>
      <title>app-ads.txt</title>
      <link>https://seoft.tistory.com/94</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;google.com,&amp;nbsp;pub-1113145392459989,&amp;nbsp;DIRECT,&amp;nbsp;f08c47fec0942fa0&lt;/p&gt;</description>
      <category>etc</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/94</guid>
      <comments>https://seoft.tistory.com/94#entry94comment</comments>
      <pubDate>Sun, 11 Aug 2024 20:51:21 +0900</pubDate>
    </item>
    <item>
      <title>ubuntu java gradle 설치, 환경변수 설정</title>
      <link>https://seoft.tistory.com/93</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;사전 권장사항 openssh-server 설치 후 방화벽해제&lt;/p&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;mdash;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ubuntu20.04lts / jdk 11 / gradle 7.4.2 기준&lt;/p&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;mdash;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;apt-get update&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo apt-get install openjdk-11-jdk&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo nano /etc/profile.d/java.sh&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#/bin/bash&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;export JAVA_HOME=/usr/lib/jvm/java-11-openjdk-amd64&lt;/p&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;mdash;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo mkdir /downloads/gradle -p&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cd /downloads/gradle&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo wget &lt;a href=&quot;https://downloads.gradle-dn.com/distributions/gradle-7.4.2-bin.zip&quot;&gt;https://downloads.gradle-dn.com/distributions/gradle-7.4.2-bin.zip&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cd /downloads/gradle&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo unzip gradle-7.4.2-bin.zip -d /opt&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo ln -s /opt/gradle-7.4.2 /opt/gradle&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo nano /etc/profile.d/gradle.sh&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#/bin/bash&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;export GRADLE_HOME=/opt/gradle&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;export PATH=/opt/gradle/bin:${PATH}&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;sudo&amp;nbsp;chmod&amp;nbsp;+x&amp;nbsp;/etc/profile.d/gradle.sh&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;source&amp;nbsp;/etc/profile.d/gradle.sh&lt;/p&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;mdash;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;번외 rabbit mq 안도커&lt;span style=&quot;background-color: #fafafa; color: #383a42;&quot;&gt;&lt;/span&gt;&lt;/p&gt;</description>
      <category>etc</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/93</guid>
      <comments>https://seoft.tistory.com/93#entry93comment</comments>
      <pubDate>Sun, 18 Dec 2022 19:36:50 +0900</pubDate>
    </item>
    <item>
      <title>kotlin spring 실행시 Task :compileKotlin FAILED e: java.lang.OutOfMemoryError: Java heap space  에러</title>
      <link>https://seoft.tistory.com/92</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;원래 잘 되던 kotlin spring boot 서버를 실행했더니 다음 에러를 출력하며 빌드 fail 발생&lt;/p&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;gt; Task :compileKotlin FAILED&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;e: java.lang.OutOfMemoryError: Java heap space&lt;/p&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;gradle clean test ( in project dir )&lt;/p&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.5.21 기준) 그 다음 스탭으로 다음 솔루션을 제시하였으나 나는 위 옵션으로 해결되어 해보진않았다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;gradle.properties 파일에 다음 명령어 추가&lt;/p&gt;
&lt;div&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;org.gradle.jvmargs=-Duser.country=US -Dkotlin.daemon.jvm.options=-Xmx2400m -Dfile.encoding=UTF-8
&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;</description>
      <category>server</category>
      <category>compileKotlin FAILED</category>
      <category>java.lang.OutOfMemoryError: Java heap space</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/92</guid>
      <comments>https://seoft.tistory.com/92#entry92comment</comments>
      <pubDate>Thu, 5 May 2022 13:13:10 +0900</pubDate>
    </item>
    <item>
      <title>삽질어록</title>
      <link>https://seoft.tistory.com/91</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;- AlarmChannel 개발할때  NotificationManager::createNotificationChannel 사용시 이미 존재하는기존 ChannelId를 할당할 경우 NotificationChannel 설정이 덮어씌어지지 않고 기존게 유지되는사항 개발때 염두필요&lt;/p&gt;</description>
      <category>?</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/91</guid>
      <comments>https://seoft.tistory.com/91#entry91comment</comments>
      <pubDate>Sat, 19 Feb 2022 20:09:17 +0900</pubDate>
    </item>
    <item>
      <title>추후작성</title>
      <link>https://seoft.tistory.com/90</link>
      <description>&lt;pre id=&quot;code_1642269955998&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Execution failed for task ':app:kaptDebugKotlin'.
&amp;gt; A failure occurred while executing org.jetbrains.kotlin.gradle.internal.KaptWithoutKotlincTask$KaptExecutionWorkAction
   &amp;gt; java.lang.reflect.InvocationTargetException (no error message)&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;위와 같이 세부적인 에러를 출력하지 않을경우 다음 명령어 gradle.properties 에 기입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;kapt.use.worker.api=false
kapt.incremental.apt=false&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;</description>
      <category>?</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/90</guid>
      <comments>https://seoft.tistory.com/90#entry90comment</comments>
      <pubDate>Sun, 16 Jan 2022 03:06:40 +0900</pubDate>
    </item>
    <item>
      <title>자동완성 안됨 / javax.net.ssl.SSLHandshakeException: Chain validation failed</title>
      <link>https://seoft.tistory.com/89</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;코드랩 도중에 초기 설정 시행착오에 관한 기록&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;https://developer.android.com/codelabs/advanced-kotlin-coroutines?hl=ko#0&lt;/p&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;b&gt;그래들 버전 4.1.2 -&amp;gt; 7.0.4&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;javax.net.ssl.SSLHandshakeException: Chain validation failed :&lt;/p&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. 시간대가 안맞다(약 10일후로 시간대가 맞춰져있어서 avd 의 auto시간 설정을 풀고 직접설정) -&amp;gt; 그래도안됨 (이게 해결을위한 중간에 필수항목인지 의문)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;2. avd 끈후에 avd manager 에서 cold reboot&amp;nbsp;&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;ref :&amp;nbsp;&lt;a href=&quot;https://stackoverflow.com/questions/45923747/android-emulator-chain-validation-failed-connecting-developers-machine-with-se/51767841&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/45923747/android-emulator-chain-validation-failed-connecting-developers-machine-with-se/51767841&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://stackoverflow.com/questions/29159242/auto-complete-not-working-in-android-studio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://stackoverflow.com/questions/29159242/auto-complete-not-working-in-android-studio&lt;/a&gt; (여기 그래들 버전관련 언급으로 7.0.4 시도)&lt;/p&gt;</description>
      <category>?</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/89</guid>
      <comments>https://seoft.tistory.com/89#entry89comment</comments>
      <pubDate>Sun, 12 Dec 2021 13:18:59 +0900</pubDate>
    </item>
    <item>
      <title>리사이클러뷰 보일러 플레이트 최소화 방안 (with Antonio)</title>
      <link>https://seoft.tistory.com/88</link>
      <description>&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최근 들어 리사이클러뷰가 포함되지 않는 앱이 거의 없을 정도이고 앱의 요구사항이 복잡해지면서 멀티타입이나 중첩 구조도 쉽게 접할 수 있습니다. 리사이클러뷰의 구성을 위해서는 아답터와 뷰홀더도 함께 구성해야 하지만, 특이한 케이스가 아니라면 불필요한 보일러플레이트 코드로도 자리매김할 수 있어 보입니다. &lt;br /&gt;&lt;br /&gt;이번&amp;nbsp;포스팅에서는&amp;nbsp;리사이클러뷰&amp;nbsp;구성시&amp;nbsp;아답터와&amp;nbsp;뷰홀더의&amp;nbsp;보일러플레이트를&amp;nbsp;최소화하는&amp;nbsp;방법과&amp;nbsp;관련된&amp;nbsp;라이브러리&amp;nbsp;또한&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;size18&quot;&gt;&lt;b&gt;샘플 프로젝트 소개&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여러 방식 비교를 위해 리스트를 페이징 하는 간단한 샘플 프로젝트를 구성하였습니다. &lt;a title=&quot;링크&quot; href=&quot;https://github.com/seoft/android-laboratory/tree/dev/antonio-sample&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;(링크)&lt;/a&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-filename=&quot;sample.gif&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;480&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oTLJj/btrkPHMQwJp/GC5CwI1mLS4FEH3vakP4a0/img.gif&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oTLJj/btrkPHMQwJp/GC5CwI1mLS4FEH3vakP4a0/img.gif&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oTLJj/btrkPHMQwJp/GC5CwI1mLS4FEH3vakP4a0/img.gif&quot; srcset=&quot;https://blog.kakaocdn.net/dn/oTLJj/btrkPHMQwJp/GC5CwI1mLS4FEH3vakP4a0/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;228&quot; height=&quot;480&quot; data-filename=&quot;sample.gif&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;480&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;-&amp;nbsp;동일&amp;nbsp;시나리오&amp;nbsp;세 가지&amp;nbsp;방식&amp;nbsp;구성 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;- A. 일반적인 리사이클러뷰 구성 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;- B. 바인딩을 통한 보일러플레이트 감소 방안의 리사이클러뷰 구성 &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;- C. Antonio 라이브러리를 사용한 리사이클러뷰 구성 (B방법에서 개선되고 다양한 기능들을 포함하고 있는 라이브러리)&lt;br /&gt;&amp;nbsp;- MVVM 아키텍처와 연동하여 간단한 페이징 시나리오 구성&lt;br /&gt;&amp;nbsp;-&amp;nbsp;세 개의&amp;nbsp;멀티타입&amp;nbsp;뷰홀더&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;size18&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;세 가지 방식에서 차이점은 아답터, 뷰홀더의 유무와 없을 경우에 대체를 위한 처리방안이 차이가 있고, 그 외에는 대부분 구성이 동일합니다. 다음 코드들은 세 가지 구성 중 동일하거나 비슷한 맥락을 가지고 있는 부분입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/6851f4a9b621604875c70408795eeaf9.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mock 데이터를 위한 인터페이스이며 서버 데이터라 가정하고 구성돼있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/0b348d9ab2d9e7a06801e54602829c80.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Mock 에서 발행되는 데이터를 각 구성의 Ui모델에 맞게 맵핑하는 역할을 합니다. 여기 코드는 같은 맥락이지만 각각 방식에 따라 다르게 구성되어있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/13767eb5481c20403d908aa7a500381a.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰모델에서의 일부 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성자로 MockApi 인터페이스의 실 구현체가 주입됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;loadMoreUiModels 함수 내에서 Mock 을 통해 리스트를 받아 맵핑을 진행 후&amp;nbsp; uiModels LiveData로 결과가 구성됩니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/c53d58169942f4774c72aa6ad188c07e.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;엑티비티에서의 일부 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onCreate 혹은 페이징 로직에서 viewModel.loadMoreUiModels() 를 호출합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;uiModels LiveData 를 옵저빙하고 있고 각 방식에 맞게 리사이클러뷰 출력을 진행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/43797322743d0ce92b2df503fcb57554.js&quot;&gt;&lt;/script&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;script src=&quot;https://gist.github.com/seoft/e3a90a9cd3a854f5685872fb4b098472.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;뷰홀더 아이템의 xml 파일 중 일부 파일입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각 방식에 따른 xml 들이 타입마다 3개씩 존재하며, variable 구성도 사용하는 모델과 인터페이스에 알맞게 구성되어있습니다.&lt;/p&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;size18&quot;&gt;&lt;b&gt;A. 일반적인 구성&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;script src=&quot;https://gist.github.com/seoft/55e4c56eec4c4e66b693bcf315ac6d19.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;일반적인 구성에서만 존재하는 아답터와 뷰홀더입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;onCreateViewHolder 함수와 뷰홀더 파일에서 비효율적으로 반복되는 코드가 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/0737cd75e91fa958624202d0905baedb.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액티비티 일부 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;생성한 NormalAdapter 의 submitList 를 통해 리스트를 출력합니다.&lt;/p&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;size18&quot;&gt;&lt;b&gt;B. 바인딩을 통한 보일러플레이트 감소 방안의&amp;nbsp;리사이클러뷰 구성&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;a href=&quot;https://github.com/seoft/android-laboratory/tree/dev/antonio-sample/app/src/main/java/kr/co/seoft/antonio_sample/util/binding_util_for_recyclerview&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;(링크)&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size14&quot;&gt;*A방식과 동일한 뷰모델, 모델, 맵퍼를 사용합니다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/a7414b16fbb020bf449610f1f3646e03.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;유틸성 클래스들로 유틸성 뷰홀더와 사용하여 구현된 아답터, UI모델을 layoutId와 매칭 시켜주는 모델로 구성되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/63ed9c4f4f4cd3b7aa0a65d2f7477db0.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;액티비티 일부 코드입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위의 유틸클래스를 통해 아답터를 양식에 맞게 생성하며 옵저빙 하는 곳에서 submitList 직전 모델에 layout 을 매칭시켜주고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A방법과 비교하였을 때 아답터와 뷰홀더에 대한 코드에 대한 일부 매칭하는 부분만 작성해주면 되고 타입이 다양할수록 보일러플레이트는 감소합니다.&lt;/p&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에서 사용되는 variable의 변수 네임이 BR클래스로 할당되고 ViewDataBinding 의 setVariable 함수를 통해 BR클래스에 매칭되는 variable 변수에 특정 값을 넣을 수 있기 때문입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A방법의 아답터의 onCreateViewHolder와 뷰홀더의 반복되는 코드들이 엑티비티에서 아답터 구성을 시작으로 뷰홀더의 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;A방법의 아답터와 뷰홀더의 보일러플레이트는 많이 감소하였지만,&amp;nbsp;BindingItem 클래스에 한번 감싸 져 있는 게 코드 사용처로부터 신경 쓰면서 구현해야 된다는 점과 submitList 직전 각 데이터 타입에 따라 전처리가 필요한 점은 아쉽습니다.&lt;/p&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;size18&quot;&gt;&lt;b&gt;C. Antonio 라이브러리를 사용한 리사이클러뷰 구성&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;NaverZ 사에서 제공하는 리사이클러뷰, 뷰페이져 구성을 위한 오픈소스라이브러리입니다. 실제 메타버스 프로젝트인 &lt;a href=&quot;https://play.google.com/store/apps/details?id=me.zepeto.main&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;ZEPETO 서비스&lt;/a&gt;에서 활용되는 것으로 알고 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/naverz/Antonio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/naverz/Antonio&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1636799516872&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - naverz/Antonio: Android library for the adapter view (RecyclerView, ViewPager, ViewPager2)&quot; data-og-description=&quot;Android library for the adapter view (RecyclerView, ViewPager, ViewPager2) - GitHub - naverz/Antonio: Android library for the adapter view (RecyclerView, ViewPager, ViewPager2)&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/naverz/Antonio&quot; data-og-url=&quot;https://github.com/naverz/Antonio&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/PAwI8/hyMkC6glhj/8ocgTg9RAyRPXUXraR7UYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/naverz/Antonio&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/naverz/Antonio&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/PAwI8/hyMkC6glhj/8ocgTg9RAyRPXUXraR7UYK/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - naverz/Antonio: Android library for the adapter view (RecyclerView, ViewPager, ViewPager2)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Android library for the adapter view (RecyclerView, ViewPager, ViewPager2) - GitHub - naverz/Antonio: Android library for the adapter view (RecyclerView, ViewPager, ViewPager2)&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;부분적으로 B방법에서 비슷한 맥락으로 구성되는 부분도 포함돼있지만 사용 방식이 훨씬 개선되었습니다.&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;- DiffUtil 을 통한 구성 외의 기존 notifyXXX 등 다양한 지원범위&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- 중첩의 중첩 관계에서 뷰 관리를 위한 LiveData 옵저빙 지원&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- LifeCycleOwner 자동 주입&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;- annotation 을 통한 생성 자동화&lt;/p&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;script src=&quot;https://gist.github.com/seoft/4d1fedf4e177a09658bb6929d555205b.js&quot;&gt;&lt;/script&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;script src=&quot;https://gist.github.com/seoft/40df9d620427a8975e71c20db258b35b.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A, B방식과 다르게 UI모델에서 AntonioBindingModel 의 구현이 필요하며 여기서 사용할 xml과 UI모델이 매칭될 xml variable 변수를 결정합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;script src=&quot;https://gist.github.com/seoft/d236fef96bba3c4f63e638b1f699e01f.js&quot;&gt;&lt;/script&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Antonio 에서는 리사이클러뷰 상태를 관리하는 고수준 클래스인 SubmittableRecyclerViewState 라는 개념이 사용되고 있고, 이는 DIffUtil 만 구성하여 손쉽게 구성할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;setState 라는 확장함수를 통하 리사이클러뷰에 설정이 되며 사용방법은 동일하게 submitList로 사용할 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B방식과 다르게 고수준으로 캡슐화돼있어 별도로 신경 쓸 사항 없이 보일러플레이트를 최소화하면서 리사이클러뷰를 구성할 수 있습니다.&lt;/p&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;/s&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;하지만 2021 드로이드나이츠에서 발표한 내용으로 Antonio 관련한 개요부터 발전단계와 내부 구성에 대한 세부 설명도 포함되어있으니 참고 바랍니다.&lt;/p&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://youtu.be/mqY3GWid7ug&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://youtu.be/mqY3GWid7ug&lt;/a&gt;&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=mqY3GWid7ug&quot; data-video-thumbnail=&quot;https://scrap.kakaocdn.net/dn/cO8tdy/hyMltGFLU1/J3LEydKlaY9khvYqDk7Y7k/img.jpg?width=1280&amp;amp;height=720&amp;amp;face=138_404_1210_514&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/mqY3GWid7ug&quot; width=&quot;860&quot; height=&quot;484&quot; frameborder=&quot;&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;&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;size18&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;또한 프로젝트 구성에 따라 리사이클러뷰가 여러 페이지에서 반복되지 않는 상황이면 B, C방식을 이해하고 도입하는 버든이 더 들 수도 있어 보이지만, 일반적으로는 잘 사용될 수 있는 방안일 것 같습니다.&lt;/p&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>Antonio</category>
      <category>recyclerview</category>
      <category>리사이클러뷰</category>
      <category>보일러플레이트</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/88</guid>
      <comments>https://seoft.tistory.com/88#entry88comment</comments>
      <pubDate>Sat, 13 Nov 2021 20:07:40 +0900</pubDate>
    </item>
    <item>
      <title>버전 코드는 이미 사용되었습니다. 다른 버전 코드를 사용해 보세요.</title>
      <link>https://seoft.tistory.com/87</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;856&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cHvbqD/btrhWJzWYQT/a1c6zxXVrlUQH1RFCYbaDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cHvbqD/btrhWJzWYQT/a1c6zxXVrlUQH1RFCYbaDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cHvbqD/btrhWJzWYQT/a1c6zxXVrlUQH1RFCYbaDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcHvbqD%2FbtrhWJzWYQT%2Fa1c6zxXVrlUQH1RFCYbaDK%2Fimg.png&quot; data-origin-width=&quot;925&quot; data-origin-height=&quot;856&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;906&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bkMhfy/btrhVZXjIAE/x2OD4dX4oBI7BSaZrzkvXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bkMhfy/btrhVZXjIAE/x2OD4dX4oBI7BSaZrzkvXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bkMhfy/btrhVZXjIAE/x2OD4dX4oBI7BSaZrzkvXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbkMhfy%2FbtrhVZXjIAE%2Fx2OD4dX4oBI7BSaZrzkvXk%2Fimg.png&quot; data-origin-width=&quot;1006&quot; data-origin-height=&quot;906&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;</description>
      <category>?</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/87</guid>
      <comments>https://seoft.tistory.com/87#entry87comment</comments>
      <pubDate>Sat, 16 Oct 2021 00:12:29 +0900</pubDate>
    </item>
    <item>
      <title>DiffUtil 아이템 개수와 데이터 교체 방법에 따른  종합 성능 테스트</title>
      <link>https://seoft.tistory.com/86</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;개요&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개인적으로&amp;nbsp;리사이클러뷰를&amp;nbsp;구현할&amp;nbsp;때&amp;nbsp;DiffUtil을&amp;nbsp;엄청&amp;nbsp;믿고&amp;nbsp;신뢰하며&amp;nbsp;사용해왔었는데,&amp;nbsp;팀&amp;nbsp;내에서&amp;nbsp;수동적인&amp;nbsp;notifyXXX&amp;nbsp;갱신&amp;nbsp;방식과&amp;nbsp;DiffUtil&amp;nbsp;방식의&amp;nbsp;차이에&amp;nbsp;대해&amp;nbsp;잠시&amp;nbsp;이야기가&amp;nbsp;나왔습니다. &lt;br /&gt;&lt;br /&gt;notifyXXX&amp;nbsp;는&amp;nbsp;변경대상을&amp;nbsp;알고&amp;nbsp;대상&amp;nbsp;부분에만&amp;nbsp;변경요청을&amp;nbsp;하는데&amp;nbsp;비해,&amp;nbsp;디프유틸을&amp;nbsp;사용하게&amp;nbsp;되면&amp;nbsp;하나의&amp;nbsp;아이템에&amp;nbsp;대한&amp;nbsp;변경을&amp;nbsp;위해서&amp;nbsp;full&amp;nbsp;size&amp;nbsp;diff&amp;nbsp;를&amp;nbsp;검사가&amp;nbsp;필요하기&amp;nbsp;때문에&amp;nbsp;성능적인&amp;nbsp;측면에서&amp;nbsp;비효율적인&amp;nbsp;것은&amp;nbsp;사실입니다. &lt;br /&gt;&lt;br /&gt;하지만 예전부터 디바이스 성능이 상향 표준화가 되면서 DiffUtil 도입시의 성능갭이 별로 차이가 나지 않는다면 구현 혹은 유지보수의 용이성과 티가 안나는 성능차이는 트레이드오프할 가치가 있을 것이고 그렇기에 구글 프레임워크에도 포함되어 나오고 있는 거라 생각하고 있었고,&lt;br /&gt;그렇다면&amp;nbsp;어느&amp;nbsp;수준의&amp;nbsp;요구사항까지&amp;nbsp;DiffUtil의&amp;nbsp;성능이&amp;nbsp;커버가&amp;nbsp;될지,&amp;nbsp;리스트의&amp;nbsp;갯수&amp;nbsp;혹은&amp;nbsp;아이템&amp;nbsp;변경&amp;nbsp;방법에&amp;nbsp;따른&amp;nbsp;사용성에&amp;nbsp;어떤&amp;nbsp;영향을&amp;nbsp;미칠지&amp;nbsp;궁금하여&amp;nbsp;테스트를&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;&lt;b&gt;구글에서 설명하는 DiffUtil&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;구글 디벨롭문서에서 DiffUtil 관련하여 기재된 사항중 성능과 테스트 관련하여 작성해보겠습니다.&lt;br /&gt;&lt;a href=&quot;https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://developer.android.com/reference/androidx/recyclerview/widget/DiffUtil&lt;/a&gt; &lt;br /&gt;&lt;br /&gt;DiffUtil&amp;nbsp;내부에서&amp;nbsp;Myers&amp;nbsp;Difference&amp;nbsp;알고리즘을&amp;nbsp;사용하며&amp;nbsp;성능은&amp;nbsp;다음과&amp;nbsp;같습니다. &lt;br /&gt;&lt;br /&gt;변경점을&amp;nbsp;찾는&amp;nbsp;비용 &lt;br /&gt;공간복잡도&amp;nbsp;:&amp;nbsp;O(N)&amp;nbsp; &lt;br /&gt;시간복잡도&amp;nbsp;:&amp;nbsp;O(N&amp;nbsp;+&amp;nbsp;D^2)&amp;nbsp; &lt;br /&gt;&lt;br /&gt;M의&amp;nbsp;추가항목과&amp;nbsp;N의&amp;nbsp;제거항목을&amp;nbsp;찾게&amp;nbsp;될&amp;nbsp;:&amp;nbsp;O(MN)의&amp;nbsp;추가&amp;nbsp;시간복잡도 &lt;br /&gt;&lt;br /&gt;또한&amp;nbsp;다음과&amp;nbsp;같은&amp;nbsp;성능&amp;nbsp;지표를&amp;nbsp;안내하고&amp;nbsp;있습니다. &lt;br /&gt;&lt;br /&gt;테스트&amp;nbsp;환경&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&amp;nbsp;-&amp;nbsp;디바이스&amp;nbsp;Nexus5&amp;nbsp;(OS&amp;nbsp;M)&lt;br /&gt;&amp;nbsp;- random UUID (36 사이즈의 스트링?) 아이템&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;100&amp;nbsp;items&amp;nbsp;and&amp;nbsp;10&amp;nbsp;modifications:&amp;nbsp;avg:&amp;nbsp;0.39&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;0.35&amp;nbsp;ms &lt;br /&gt;100&amp;nbsp;items&amp;nbsp;and&amp;nbsp;100&amp;nbsp;modifications:&amp;nbsp;3.82&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;3.75&amp;nbsp;ms &lt;br /&gt;100&amp;nbsp;items&amp;nbsp;and&amp;nbsp;100&amp;nbsp;modifications&amp;nbsp;without&amp;nbsp;moves:&amp;nbsp;2.09&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;2.06&amp;nbsp;ms &lt;br /&gt;1000&amp;nbsp;items&amp;nbsp;and&amp;nbsp;50&amp;nbsp;modifications:&amp;nbsp;avg:&amp;nbsp;4.67&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;4.59&amp;nbsp;ms &lt;br /&gt;1000&amp;nbsp;items&amp;nbsp;and&amp;nbsp;50&amp;nbsp;modifications&amp;nbsp;without&amp;nbsp;moves:&amp;nbsp;avg:&amp;nbsp;3.59&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;3.50&amp;nbsp;ms &lt;br /&gt;1000&amp;nbsp;items&amp;nbsp;and&amp;nbsp;200&amp;nbsp;modifications:&amp;nbsp;27.07&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;26.92&amp;nbsp;ms &lt;br /&gt;1000&amp;nbsp;items&amp;nbsp;and&amp;nbsp;200&amp;nbsp;modifications&amp;nbsp;without&amp;nbsp;moves:&amp;nbsp;13.54&amp;nbsp;ms,&amp;nbsp;median:&amp;nbsp;13.36&amp;nbsp;ms&lt;/p&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;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;구글에서 제공하는 대략적인 성능 평가가 있었지만 저는 다음 두 사유로 직접 테스트를 진행하게 되었습니다. &lt;br /&gt;&lt;br /&gt;&amp;nbsp;- Nexus5 기기가 13년도의 오래된 단말기라 현시점의 비교적 성능이 업된 단말기에서의 결과 도출하기 위함&lt;br /&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;gt; &lt;a href=&quot;https://github.com/seoft/android-laboratory/tree/dev/diff-util-test&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/seoft/android-laboratory/tree/dev/diff-util-test&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1633267997615&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;object&quot; data-og-title=&quot;GitHub - seoft/android-laboratory&quot; data-og-description=&quot;Contribute to seoft/android-laboratory development by creating an account on GitHub.&quot; data-og-host=&quot;github.com&quot; data-og-source-url=&quot;https://github.com/seoft/android-laboratory/tree/dev/diff-util-test&quot; data-og-url=&quot;https://github.com/seoft/android-laboratory&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bb3DKc/hyLPt2cHJs/gif4KOhOK8eGRRbhziGxPk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600&quot;&gt;&lt;a href=&quot;https://github.com/seoft/android-laboratory/tree/dev/diff-util-test&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://github.com/seoft/android-laboratory/tree/dev/diff-util-test&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bb3DKc/hyLPt2cHJs/gif4KOhOK8eGRRbhziGxPk/img.png?width=1200&amp;amp;height=600&amp;amp;face=0_0_1200_600');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;GitHub - seoft/android-laboratory&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;Contribute to seoft/android-laboratory development by creating an account on GitHub.&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;github.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;657&quot; width=&quot;800&quot; height=&quot;527&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/wtwmQ/btrgB3OIghK/oGZ2U7GdgoVioufn3clAI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/wtwmQ/btrgB3OIghK/oGZ2U7GdgoVioufn3clAI1/img.png&quot; data-alt=&quot;테스트앱 스크린샷&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/wtwmQ/btrgB3OIghK/oGZ2U7GdgoVioufn3clAI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwtwmQ%2FbtrgB3OIghK%2FoGZ2U7GdgoVioufn3clAI1%2Fimg.png&quot; data-origin-width=&quot;998&quot; data-origin-height=&quot;657&quot; width=&quot;800&quot; height=&quot;527&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;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;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;테스트 환경&lt;/b&gt;&lt;/h4&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&amp;nbsp;-&amp;nbsp;현&amp;nbsp;시점에&amp;nbsp;적당히&amp;nbsp;마지노선의&amp;nbsp;단말기(?)인&amp;nbsp;갤럭시&amp;nbsp;S8(OS&amp;nbsp;9)로&amp;nbsp;테스트&lt;br /&gt;&amp;nbsp;-&amp;nbsp;기존&amp;nbsp;테스트의&amp;nbsp;UUID&amp;nbsp;보다는&amp;nbsp;실제&amp;nbsp;유즈케이스와&amp;nbsp;더&amp;nbsp;밀접한&amp;nbsp;환경(?)&lt;br /&gt;&amp;nbsp;-&amp;nbsp;멀티타입의&amp;nbsp;뷰홀더&lt;br /&gt;&amp;nbsp;-&amp;nbsp;실제&amp;nbsp;모델&amp;nbsp;id값으로&amp;nbsp;areItemsTheSame을,&amp;nbsp;ui&amp;nbsp;변경대상&amp;nbsp;파라미터만으로&amp;nbsp;areContentsTheSame&amp;nbsp;로&amp;nbsp;비교&lt;br /&gt;&amp;nbsp;-&amp;nbsp;payload&amp;nbsp;전달로&amp;nbsp;뷰&amp;nbsp;부분&amp;nbsp;업데이트&amp;nbsp;진행&lt;br /&gt;&amp;nbsp;-&amp;nbsp;테스트&amp;nbsp;케이스&amp;nbsp;:&amp;nbsp;순차적&amp;nbsp;추가,&amp;nbsp;랜덤&amp;nbsp;추가,&amp;nbsp;삭제,&amp;nbsp;셔플,&amp;nbsp;수정,&amp;nbsp;(단일&amp;nbsp;추가,수정,삭제)&lt;br /&gt;&amp;nbsp;-&amp;nbsp;테스트&amp;nbsp;개수&amp;nbsp;범위&amp;nbsp;:&amp;nbsp;200*n&amp;nbsp;(~1000)&amp;nbsp;,&amp;nbsp;5000*n&amp;nbsp;(~50000)&lt;br /&gt;&amp;nbsp;-&amp;nbsp;단일&amp;nbsp;업데이트&amp;nbsp;경우&amp;nbsp;인덱스&amp;nbsp;마지막&amp;nbsp;부근에서&amp;nbsp;진행&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 부분 삭제, 변경 경우 다음 테스트 갯수(last 25000)에서 다음 테스트갯수 - 현 테스트 갯수만큼 진행,(ex, 2번째 테스트 경우 600개에서 200개 수행)&lt;/p&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;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 결과는 다음과 같습니다. 각 항목을 10번 진행하여 평균낸 결과이며, 20초가까이 넘어가는 내용들은 무의미하다고 판단하여 복수 테스트는 하지않았습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;353&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b0hMDO/btrgCHx97ok/8XSZFAx4GSKv8QYPOV66kK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b0hMDO/btrgCHx97ok/8XSZFAx4GSKv8QYPOV66kK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b0hMDO/btrgCHx97ok/8XSZFAx4GSKv8QYPOV66kK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb0hMDO%2FbtrgCHx97ok%2F8XSZFAx4GSKv8QYPOV66kK%2Fimg.png&quot; data-origin-width=&quot;1028&quot; data-origin-height=&quot;353&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;*평균내기 전 raw 값도 포함된 excel 파일은 github 테스트앱 프로젝트 디렉토리에 포함되있습니다.&lt;/p&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;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트&amp;nbsp;결과를&amp;nbsp;보고&amp;nbsp;몇&amp;nbsp;가지&amp;nbsp;기술하자면,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;- 전체 셔플에 대한 비교수행 비용은 굉장히 큽니다.(충분히 나올 수 있는 요구사항이고, 셔플범위가 넓을 경우에는 삭제 후 새로 추가하는게 더 용이해보입니다) &lt;br /&gt;-&amp;nbsp;리사이클러뷰가&amp;nbsp;디폴트로&amp;nbsp;애니메이션&amp;nbsp;가지게&amp;nbsp;되는데&amp;nbsp;이를&amp;nbsp;off&amp;nbsp;할&amp;nbsp;경우&amp;nbsp;리스트&amp;nbsp;갯수와&amp;nbsp;추가타입에&amp;nbsp;따라&amp;nbsp;성능차이가&amp;nbsp;있을 수&amp;nbsp;있습니다. &lt;br /&gt;- 개인차가 있어 몇 ms부터&amp;nbsp;느리다고 판단하기는 힘들지만 랜덤 추가방식 경우 2000개, 삭제 경우 6000개 이상이 될 경우 160ms, 200ms 가 넘으면서 사용자 입장에서 반응이 느리게 느껴질 수도 있을듯합니다. &lt;br /&gt;- 제가 주로 리스트를 구성할 때에는 페이징과 부분 아이템의 일부의 상태를 교체하는 요구사항이 일반적인 것 같습니다. 이러한 요구사항에서는 아이템의 갯수가 많아져도 크게 무리가 되지 않아 보입니다. (이 부분은 특정 리스트 기능을 사용할때 유저의 max 페이징 수 지표가 파악되면 더 좋을듯하네요..) &lt;br /&gt;&lt;br /&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;&quot; 일반적인 요구사항에서는 DiffUtil을 도입해도 충분히 괜찮으나, 리스트 구성이나 사용방식에 대해 특이사항이 있을 경우 성능 검토 고려가 필요하다 &quot;&lt;/p&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;개인적으로&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;위에 테스트 프로젝트 구성 외에도 디바이스 환경이나 실제 구성에서의 diff 조건, 뷰홀더명세 등등 테스트 결과에 영향이 미치는 요소가 더 있기 때문에, 제가 가정한 조건에 따른 결과임을 염두 부탁드리며, 추가로 필요시 코드 수정해서 테스트 하셨으면 하는 바램으로 공유드립니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;읽어주셔서&amp;nbsp;감사합니다.&lt;/p&gt;</description>
      <category>android</category>
      <category>Android</category>
      <category>DiffUtil</category>
      <category>recyclerview</category>
      <author>seoft</author>
      <guid isPermaLink="true">https://seoft.tistory.com/86</guid>
      <comments>https://seoft.tistory.com/86#entry86comment</comments>
      <pubDate>Sun, 3 Oct 2021 22:55:43 +0900</pubDate>
    </item>
  </channel>
</rss>