<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Eddie Eddie</title>
    <description>The latest articles on DEV Community by Eddie Eddie (@eddiej).</description>
    <link>https://dev.to/eddiej</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F522545%2F6c70925f-64a0-451f-87ac-1c1a120935e8.jpeg</url>
      <title>DEV Community: Eddie Eddie</title>
      <link>https://dev.to/eddiej</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/eddiej"/>
    <language>en</language>
    <item>
      <title>Flow ของ OAuth 2.0</title>
      <dc:creator>Eddie Eddie</dc:creator>
      <pubDate>Mon, 16 Jan 2023 15:57:20 +0000</pubDate>
      <link>https://dev.to/eddiej/flow-khng-oauth-20-2mk7</link>
      <guid>https://dev.to/eddiej/flow-khng-oauth-20-2mk7</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover image from &lt;a href="https://www.pexels.com/photo/red-metal-padlock-157203/" rel="noopener noreferrer"&gt;flickr, Pexels&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;เนื้อหาทั้งหมดเอามาจาก video ของ &lt;a href="https://www.youtube.com/watch?v=996OiexHze0" rel="noopener noreferrer"&gt;Okta Youtube channel&lt;/a&gt; และ &lt;a href="https://www.youtube.com/watch?v=h_1JAh3JPkI" rel="noopener noreferrer"&gt;productioncoder channel&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ตั้งใจเขียน Blog นี้เพราะว่าลืม flow ของ OAuth ทุกทีว่ามันทำงานยังไง สุดท้ายต้องมานั่งดู clip ย้อนหลังใหม่เรื่อยๆ รู้สึกว่าไม่ค่อยมี time efficiency เท่าไหร่เพราะ clip ก็นานเป็นชั่วโมงอยู่เลยมาเขียน Blog ซะเลย&lt;/p&gt;

&lt;p&gt;blog นี้พยายามจะเขียนครอบคลุมแค่เรื่อง Flow หลักๆ กับ PKCE เท่านั้นอาจจะไม่ได้ลงรายละเอียดมากเท่าไหร่&lt;/p&gt;

&lt;h2&gt;
  
  
  Terms
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Resource Owner&lt;/strong&gt;: เจ้าของ Resources ที่ app เราต้องการจะ access เช่น Google, Facebook, Twitter etc&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Client&lt;/strong&gt;: app ของเรา&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scope&lt;/strong&gt;: ข้อมูลที่เราอยากได้จาก Resource Owner&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Flow ของ OAuth2 ในภาพใหญ่จริงๆ มีแค่ 7 ขั้นตอน
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0uxy279im8n5z3cyfxg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0uxy279im8n5z3cyfxg.png" alt="OAuth2 Flow" width="800" height="586"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(1) Pre-register กับ Resource Owner&lt;/strong&gt;&lt;br&gt;
เราจำเป็นต้องทำการ pre register กับ Resource Owner ก่อนที่จะทำการ implement authorization ให้ลองนึกถึงการที่เราต้องไปสร้าง apps บน Facebook, Twitter, Google ก่อนเริ่ม ใน step นี้ Resource Owner อาจจะทำการสร้าง &lt;code&gt;secret key&lt;/code&gt; มาให้เราใช้งาน เราจำเป็นต้องเก็บไว้กับตัวเองที่ Backend server ของเรา&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(2) ส่ง request ไปที่ Authorization Server ของ Resource Owner&lt;/strong&gt; (Front channel)&lt;br&gt;
หลังจากที่เราทำการ implement ปุ่ม authorization แล้ว (Login with Facebook, Login with Google, Login with Twitter) เราจะทำการส่ง Request ไปที่ authorization Server ของ Resource Owner เพื่อทำการ authorize โดยขั้นตอนนี้เราจะทำการส่ง Scope ไปด้วยพร้อมกับ callback URI&lt;br&gt;
&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Redirect URI; myapp.com/callback
Scope: profile, contacts
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Resource Owner จะขึ้นหน้าเว็บให้เราทำการ signin&lt;br&gt;
&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsymy6mikhd8fe1n1xrm2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsymy6mikhd8fe1n1xrm2.png" alt="ตัวอย่างหน้า signin" width="551" height="634"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;(3) Resource Owner ทำการ redirect เพื่อขอ permission เราเพื่อให้ข้อมูลกับ client app&lt;/strong&gt; (Front channel)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5gkeuw75iqqnf7n1zvb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe5gkeuw75iqqnf7n1zvb.png" alt="ตัวอย่างหน้า permission" width="549" height="712"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(4) Resource Owner redirect กลับมาที่ Callback URI&lt;/strong&gt; (Front channel)&lt;br&gt;
เมื่อ user ทำการกดอนุญาตแล้ว Resource Owner จะทำการ redirect กลับมาที่ callback URI ที่ให้ไว้ที่ step แรก พร้อมกับ return &lt;strong&gt;authorization code&lt;/strong&gt; กลับมาด้วย&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(5) Exchange authorization code กับ accesstoken&lt;/strong&gt; (Back channel)&lt;br&gt;
เราจะทำการแลกเปลียน authorization code ที่ได้มาจาก step ที่ 4 กับ accessToken โดยทำการส่ง  &lt;code&gt;authorization code&lt;/code&gt; + &lt;code&gt;secret key&lt;/code&gt; ที่เราได้ตอน step ที่ 1 ไปที่ Authorization Server ของ Resource Owner&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(6) Authorization Server ของ Resource Owner คืน accessToken&lt;/strong&gt; (Back channel)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;(7) Client app นำ &lt;code&gt;accessToken&lt;/code&gt; (Back channel) ไปใช้เพื่อเข้าถึง resource&lt;/strong&gt; ตามที่ได้ระบุไว้ใน scope ที่ step แรก&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Back and Front Channels
&lt;/h2&gt;

&lt;p&gt;ใน step ที่ 5 เราจะไม่ได้ &lt;code&gt;accessToken&lt;/code&gt; returned มากลับตรงๆ แต่จะได้เป็น authorization code มาแทน สาเหตุหลักๆมาจากเรื่อง security ถ้าเกิดว่ามี malicious software ที่ทำหน้าที่ดักข้อมูลที่เรารับส่งที่ step นี้จะให้เกิดปัญหาได้ เราเลยจำเป็นต้องให้ Server ของเราเป็นคนส่ง request (Back Channel) และแนบ secret key ไปด้วยเพื่อขอ AccessToken แต่ในบางกรณีเราอาจจะไม่มี backend server เช่น app เราเป็น Static page web site นั่นทำให้เราจำเป็นที่จะต้องได้ AccessToken มาที่ step นี้ Flow นี้จะเรียกว่า &lt;strong&gt;Implicit Flow&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implicit Flow
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26qdrfartjqa7ej8bguu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F26qdrfartjqa7ej8bguu.png" alt="Implicit Flow" width="800" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Implicit Flow จะเหมือนกันกับ Flow ปกติต่างกันตรงที่ไม่มี Back channel นั่นทำให้ที่ Step 5 เราจะได้ AccessToken มาตรงๆ &lt;br&gt;
ข้อเสียที่ควรรู้ไว้คือ Implicit Flow จะมี security ที่แย่กว่า Flow ปกติ&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenID
&lt;/h2&gt;

&lt;p&gt;OAuth2 ถูกสร้างมาเพื่อใช้แค่สำหรับ Authorization เท่านั้น แต่การใช้งานของมันค่อนข้างแพร่หลายเลยทำให้มีการนำมาประยุกต์ใช้กับการ Authentication ด้วย โดยสิ่งที่ถูกสร้างมาเป็น extension ของ OAuth สำหรับการ Authentication คือ OpenID&lt;/p&gt;

&lt;p&gt;สิ่งที่เพิ่มเข้ามาจาก flow ปกติคือ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;OpenID scope&lt;/strong&gt;: เพื่อบอก Authorization Server ว่าเป็นการขอใช้ Authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;ID Token&lt;/strong&gt;: สำหรับการ fetch ข้อมูล user ที่ทำการ authentication&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;UserInfo endpoint&lt;/strong&gt;: สำหรับดึงข้อมูล UserInfo&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flq6uzgniaj8stsg39t2f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Flq6uzgniaj8stsg39t2f.png" alt="OpenID" width="800" height="605"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PKCE (Proof Key for Code Exchange)
&lt;/h2&gt;

&lt;p&gt;สมมติว่าเราต้่องการทำ OAuth บน mobile app ใน flow ปกติที่ไม่ใช่ implicit flow โดย:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;เราไม่มี backend server ที่ไว้ช่วยเก็บ secret key&lt;/li&gt;
&lt;li&gt;เราไม่สามารถเก็บ secret key ไว้ที่ client app เราได้ &lt;/li&gt;
&lt;li&gt;Authorization มี option ให้เลือกว่าจะไม่ใช้ secret key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ใน step ที่ (5) ที่เราทำการส่ง authorization code ไปที่ Authorization Server เพื่อทำการแลกเปลี่ยน access token บน mobile app มีโอกาสที่ malicious app ที่มาแอบดักตัว authorization code ก่อนเราแล้วไปทำการส่งไปที่ server เพื่อขอ Access token ได้ &lt;a href="https://www.rfc-editor.org/rfc/rfc7636" rel="noopener noreferrer"&gt;RFC-7636&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjf12e8rnil54h8yop8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ffjf12e8rnil54h8yop8d.png" alt="rfc7636" width="800" height="565"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;PKCE ช่วยแก้ปัญหานี้ด้วยการ  &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0nvtnpecc614fnxqq8e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fc0nvtnpecc614fnxqq8e.png" alt="PKCE" width="800" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;generate strings ที่มีความยาว 43-128 characters เรียกว่า &lt;strong&gt;code_verifier&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;hash &lt;strong&gt;code_verifier&lt;/strong&gt; ด้วยการ hash ตามมาตราฐาน&lt;/li&gt;
&lt;li&gt;ใน step ที่ 2 ให้ทำการส่ง code challenge และ code challenge method ไปที่ Authorization Server ด้วย โดย &lt;strong&gt;code challenge คือค่าที่ได้จากการ hash และ code challenge method คือวิธีในการ hash เช่น sha256&lt;/strong&gt; กระบวนการนี้จะทำให้ Authorization Server รู้ว่า ค่าที่ได้จากการ hash คือค่าอะไร และใช้กระบวนการ hash แบบไหน&lt;/li&gt;
&lt;li&gt;ใน step ที่ 5 ที่เราทำการส่ง authorization code ให้เราทำการส่ง &lt;strong&gt;code_verifier&lt;/strong&gt; ไปที่ authorization server ด้วย ตัว authorization server จะทำการ hash ค่า &lt;strong&gt;code_verifier&lt;/strong&gt; ด้วยวิธีการที่บอกก่อนหน้า (code challenge method) แล้ว check ค่าว่าได้ hash value ที่ตรงกันกับ code challenge หรือไม่&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>javascript</category>
      <category>express</category>
      <category>node</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Modernized Android architecture - JetPack Compose Part1</title>
      <dc:creator>Eddie Eddie</dc:creator>
      <pubDate>Fri, 15 Jan 2021 11:59:04 +0000</pubDate>
      <link>https://dev.to/eddiej/modernized-android-architecture-jetpack-compose-part1-3leo</link>
      <guid>https://dev.to/eddiej/modernized-android-architecture-jetpack-compose-part1-3leo</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover Photo by PixaBay from&lt;/em&gt; &lt;a href="https://www.pexels.com/photo/chords-sheet-on-piano-tiles-210764/" rel="noopener noreferrer"&gt;Pexels&lt;/a&gt;&lt;br&gt;
จากที่เกริ่นไว้ใน Part แรกว่า JetPack Compose เป็นเรื่องที่ตั้งใจจะเขียนไว้ตอนแรกแต่เนื่องจากว่าใน Sample project มีจุดน่าสนใจหลายอย่าง เลยต้องแตกออกมาเป็นอีกหัวข้อนึง เรื่อง JetPack Compose ที่จะเขียนในวันนี้ อาจจะไม่ครอบคลุมเนื้อหาทั้งหมด เพราะตัว JetPack Compose เองก็มีเนื้อหาเยอะมาก รวมถึง API เองก็ยังไม่ได้อยู่ในสถานะ Stable เลยคิดว่าน่าจะมี Breaking change พอสมควร เนื้อหาที่จะเขียนในนี้จึงขอ Scope เนื้อหาเอาไว้คร่าวๆละ Sample App ละกัน&lt;/p&gt;
&lt;h3&gt;
  
  
  เริ่มต้นสร้าง Project
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Jetpack Compose นั้น สามารถใช้งานได้บน &lt;a href="https://developer.android.com/studio/preview" rel="noopener noreferrer"&gt;Android Studio 4.2 (Preview)&lt;/a&gt; ขึ้นไปเท่านั้น เพราะฉะนั้นก่อนเริ่มสร้าง Project เราควรมั่นใจก่อนว่า Version ของ Android Studio เราถูกต้อง&lt;/li&gt;
&lt;li&gt;เมื่อกด New Project เราสามารถเลือก Empty Compose Activity ได้เลย
&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkro0jxmb3xk1f02i9xf3.jpg" alt="Alt Text"&gt;
ใน &lt;code&gt;app/build.gradle&lt;/code&gt; จะเห็นว่าเรามี Compose lib อยู่ข้างในด้วย
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.compose.ui:ui:$compose_version"&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.ui:ui-tooling:$compose_version"&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"androidx.compose.material:material:$compose_version"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;androidx.compose.ui:ui&lt;/code&gt;และ &lt;code&gt;androidx.ui:ui-tooling&lt;/code&gt; คือ JetPack Compose ที่เราจะใช้ &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;androidx.compose.material&lt;/code&gt; คือ Google Material Design system Library ที่ถูกสร้างครอบ JetPack Compose อีกที&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;หน้าตา Code หลังจากที่ New Project สำเร็จ&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxcon0vaqklo9tqieyoe1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxcon0vaqklo9tqieyoe1.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;จุดที่เราสามารถสังเกตได้ชัดๆคือใน Activity ของเรานั้นไม่มีการ เรียก &lt;code&gt;setContentView(R.layout.activity_main)&lt;/code&gt; อีกต่อไปแล้ว กลับกัน กับเรียก &lt;code&gt;setContent&lt;/code&gt; แทนที่เป็น Extension Function ที่รับ lamda ที่มี &lt;code&gt;@Composable&lt;/code&gt; ประกาศไว้ข้างหน้า&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fim3zu1j9zylo7wmx0jew.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fim3zu1j9zylo7wmx0jew.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
สิ่งที่ set เข้าไปใน lamda ของ setContent ก็คือ &lt;code&gt;MyApplicationTheme&lt;/code&gt; ซึ้งถ้าเราไปดู เจ้าตัว &lt;code&gt;MyApplicationTheme&lt;/code&gt; นั้นก็เป็น Function ที่มี &lt;code&gt;@Composable&lt;/code&gt; ไว้เช่นกัน&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flc3gz071o32b99k278yk.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flc3gz071o32b99k278yk.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;
  
  
  Composable
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@Composable&lt;/code&gt; คือ Annotation พื้นฐานสำหรับ JetPack Compose ที่ไว้ประกาศไว้หน้า Function เพื่อเป็นการบอกว่า Function นี้จะเป็น Block code ที่ไว้สำหรับ Built ด้วย Compose 
พูดง่ายๆคือเป็น UI Function ละกัน&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;
  
  
  Concept ของ UI เปลี่ยนไป
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw0ydf4t6nfdxdwo0hpu2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fw0ydf4t6nfdxdwo0hpu2.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ใน JetPack Compose Concept ของ UI นั้นจะไม่เหมือนกับ Android View System ดั้งเดิม คือ ทุกๆ Component นั้นเป็น Composable function ไม่ใช่ Object ที่สืบทอดมาจาก View การเปลี่ยนแปลงการแสดงผลของ UI นั้นจะเกิดขึ้นเมื่อ Function นั้นมีการ "Re-composition" เกิดขึ้น&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy3zkzvkgmu7xij2nv9g3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fy3zkzvkgmu7xij2nv9g3.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ถึงตรงนี้หลายคนอาจจะสงสัยว่าเมื่อไหร่ที่ Function จะทำการ Re-composition? โดยปกติแล้ว Composable Function จะทำการ Re-composition ก็ต่อเมื่อ &lt;strong&gt;State ของตัวมันเองเปลี่ยนไป&lt;/strong&gt; โดยเรื่อง State จะกล่าวถัดไป &lt;/p&gt;
&lt;h3&gt;
  
  
  Unidirectional Data Flow
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Unidirectional_Data_Flow_(computer_science)" rel="noopener noreferrer"&gt;Unidirectional Data Flow&lt;/a&gt; หรือ Single Directional Data Flow &lt;br&gt;
ย้อนกลับไปตอนที่เรายังเขียน Code เป็นแบบ &lt;a href="https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller" rel="noopener noreferrer"&gt;MVC Pattern&lt;/a&gt; &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ใน MVC เมื่อมี &lt;code&gt;Action&lt;/code&gt; บางอย่างเกิดขึ้นเช่น User เปิดแอพ, User คลิกปุ่ม ฯลฯ &lt;code&gt;Action&lt;/code&gt; จะถูกส่งไปให้ Controller เป็นคนจัดการ &lt;/li&gt;
&lt;li&gt;Controller จะทำการจัดการกับ &lt;code&gt;Action&lt;/code&gt; นั้นตามแต่ว่า Action นั้นคืออะไร เช่น User เปิดแอพ -&amp;gt; Controller ดึงข้อมูลจาก network เมื่อ Controller ได้ข้อมูลมาแล้ว นำข้อมูลไป parse เป็น model แล้วแสดงผลที่ View ให้ User เห็น&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7hvplki96abolsg5isco.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7hvplki96abolsg5isco.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
Flow การทำงานนี้คอนข้างเรียบง่ายถ้าเป็นแอพขนาดเล็ก แต่ถ้าหากว่าแอพเราใหญ่ขึ้น Flow การทำงานก็จะซับซ้อนขึ้น เช่น เมื่อ User เปิดแอพ เราต้อง Fetch ข้อมูลจาก API มาจาก &lt;code&gt;n&lt;/code&gt; Endpoints และแสดงผลใน View &lt;code&gt;n&lt;/code&gt; Views &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkd0jr7pyat6nas2obcie.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkd0jr7pyat6nas2obcie.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ขอบคุณทีม Facebook Engineer ที่ได้ คิดใหม่และกลายเป็นที่มาของ Flux, Redux ฯลฯ ในปัจจุบันฝั่ง web App Development&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzfxtf54p7qes6z7m44fv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fzfxtf54p7qes6z7m44fv.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Image from &lt;a href="https://www.youtube.com/watch?v=nYkdrAPrdcw" rel="noopener noreferrer"&gt;Hacker Way: Rethinking Web App Development at Facebook&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;ใครสนใจสามารถอ่านได้ที่ &lt;a href="https://facebook.github.io/flux/docs/in-depth-overview" rel="noopener noreferrer"&gt;Flux documentation&lt;/a&gt;&lt;br&gt;
สาเหตุที่จำเป็นต้องเกริ่นถึงเรื่องนี้เพราะตัว JetPack Compose เองมีสิ่งนึงที่ Build-in เข้ามาใน Library เลย นั่นก็คือ &lt;code&gt;State&lt;/code&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  State
&lt;/h3&gt;

&lt;p&gt;State เป็นเสมือนค่าสถานะของ Application ที่เปลี่ยนแปลงได้ตามเวลา ถ้าเราลองมองภาพกว้างๆ จะเห็นว่า Android App ของเราเองก็ทำการ แสดง State ต่างๆ ให้ User เห็นอยู่แล้ว เช่น:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;State ที่ทำการแสดง Snackbar ให้ User เห็นเมื่อไม่มี Internet&lt;/li&gt;
&lt;li&gt;State ที่ทำการแสดง Blog Post รวมถึง Comment ที่เกี่ยวข้อง&lt;/li&gt;
&lt;li&gt;State ที่ทำการแสดง Ripple animation บนปุ่มเมื่อ User กด
จะเห็นว่าแอพเราเองก็แสดง State ต่างๆ ให้ user เห็นผ่านทาง View อยู่แล้ว &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;แล้วเมื่อไหร่ที่ State ของหน้าแอพเรามันเปลี่ยนแปลงไปล่ะ?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;โดยปกติ State ของแอพเรามักจะเปลี่ยนแปลงเนื่องจากมี &lt;code&gt;Action&lt;/code&gt; หรือ &lt;code&gt;Event&lt;/code&gt; บางอย่างมากระทำให้ State เปลี่ยนแปลงไป&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F49m22zsqd9j653ezb5pk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F49m22zsqd9j653ezb5pk.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event&lt;/strong&gt; ในที่นี้อาจจะเป็น Action จากการกดปุ่ม หรือข้อมูลที่เกิดจากการ Fetch มาจาก Backend &lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Update state&lt;/strong&gt; class หรือ function ที่ทำหน้าที่เปลี่ยนแปลง State&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Display state&lt;/strong&gt; UI ที่ทำหน้าที่ Display ให้ User เห็น ตามแต่ละ State ที่เปลี่ยนแปลงไป&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;พูดอีกอย่างก็คือ เราจะแสดง UI ตาม State ที่เปลี่ยนแปลงไป ในขณะเดียวกัน State ก็อาจจะเปลี่ยนแปลงได้จากการที่ได้รับ Event บางอย่างมาจาก UI&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj3x67v3qxwronstzlslk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj3x67v3qxwronstzlslk.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ยกตัวอย่าง:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MainActivityBinding&lt;/span&gt;
   &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;

   &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="cm"&gt;/* ... */&lt;/span&gt;
       &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textUpdateButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
           &lt;span class="nf"&gt;updateHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Android"&lt;/span&gt;
                &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"JetPack"&lt;/span&gt;
                &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hilt"&lt;/span&gt;
                &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"People"&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;updateHello&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;helloText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, $name"&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Code ข้อบนชุดนี้คือ เราจะทำการ Update ค่าที่นำมาแสดงของ &lt;code&gt;helloText&lt;/code&gt; เมื่อ User มีการกดปุ่มเพื่อ random โดยตัวอย่างโค๊ตข้างบนสามารถทำงานได้ถูกต้อง 100% ทีนี้ปัญหาคืออะไร? 🤔&lt;/p&gt;

&lt;p&gt;เราลองนึกถึงแอพที่ Scale ใหญ่ขึ้น หน้าจอมีความซับซ้อนมากขึ้น การเขียนโค๊ตลักษณะนี้อาจจะก่อให้เกิดปัญหาหลายอย่างเช่นการ Test เนื่องจากว่าค่าที่นำมาแสดงผลอยู่ภายใน View (State ของ &lt;code&gt;helloText&lt;/code&gt; อยู่ใน View) การ test นั้นเป็นเรื่องค่อนข้างยาก หรือแอพมี Events มากขึ้นแล้วเราต้อง Update UI หรือ ค่า State ต่างๆ มันเป็นเรื่องง่ายมากที่เราจะลืมมาแก้ไข/เปลี่ยนแปลง Code ชุดนี้ รวมขึ้น Code Complexity ที่จะเกิดขึ้นในอนาคต&lt;/p&gt;

&lt;p&gt;ใช้ ViewModel และ LiveData ช่วยในการจัดการ State&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

   &lt;span class="c1"&gt;// LiveData holds state which is observed by the UI&lt;/span&gt;
   &lt;span class="c1"&gt;// (state flows down from ViewModel)&lt;/span&gt;
   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
   &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;

   &lt;span class="c1"&gt;// onNameChanged is an event we're defining that the UI can invoke&lt;/span&gt;
   &lt;span class="c1"&gt;// (events flow up from UI)&lt;/span&gt;
   &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNameChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;

   &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Android"&lt;/span&gt;
        &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"JetPack"&lt;/span&gt;
        &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hilt"&lt;/span&gt;
        &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"People"&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;helloViewModel&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;viewModels&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MainViewModel&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;()&lt;/span&gt;

   &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="cm"&gt;/* ... */&lt;/span&gt;

       &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;textUpdateButton&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;setOnClickListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="n"&gt;helloViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onNameChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
       &lt;span class="p"&gt;}&lt;/span&gt;

       &lt;span class="n"&gt;helloViewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt;
           &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;helloText&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, $name"&lt;/span&gt;
       &lt;span class="p"&gt;}&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะเห็นว่าสิ่งที่เกิดขึ้นใน Code ชุดข้างบนคือ เราให้ การกดปุ่มจะไป update ค่าของ LiveData แทนที่จะ Update UI ตรงๆ ทำการ observe LiveData ตัวนั้นเพื่อทำการเปลี่ยนแปลงค่าใน &lt;code&gt;helloText&lt;/code&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Event/Action&lt;/strong&gt; ในที่นี้ Event หรือ Action คือ การที่ User กดปุ่ม&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Updating&lt;/strong&gt; เกิดขึ้นที่ &lt;code&gt;onNameChanged&lt;/code&gt; เมื่อค่าของ LiveData เปลี่ยนแปลงไป เรียกว่าเราได้ทำการ Hoist State เอาไว้ที่ LiveData ของ ViewModel ของเรา (State Hoisting)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;State Displaying&lt;/strong&gt; เกิดขึ้น Observer เมื่อทำการเปลี่ยนแปลงค่าของ &lt;code&gt;helloText&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  ลอง Implement Code แบบเดียวกันด้วย JetPack Compose
&lt;/h4&gt;

&lt;p&gt;ผมจะลองสร้าง Sample Code ขึ้นมาให้หน้าตาและการทำงานมีลักษณะดังนี้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj7ycfcv04iaif8stkdpx.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fj7ycfcv04iaif8stkdpx.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
โดยทุกๆครั้งที่ User กดปุ่ม เราจะทำการ random ข้อความขึ้นมาใหม่และแสดงที่ &lt;code&gt;Text&lt;/code&gt; ตัวแอพจะแสดง Icon อยู่ทางขวาจะ random ขึ้นมาเหมือนกันแต่แค่ครั้งเดียวหลังจากที่เปิดแอพใหม่ โดยเราจะมี ViewModel อยู่แล้ว หน้าตาแบบนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="c1"&gt;// LiveData holds state which is observed by the UI&lt;/span&gt;
    &lt;span class="c1"&gt;// (state flows down from ViewModel)&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;

    &lt;span class="c1"&gt;// onNameChanged is an event we're defining that the UI can invoke&lt;/span&gt;
    &lt;span class="c1"&gt;// (events flow up from UI)&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNameChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;พร้อมกับ Function สำหรับ Random Text&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Android"&lt;/span&gt;
            &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"JetPack"&lt;/span&gt;
            &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"Hilt"&lt;/span&gt;
            &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"People"&lt;/span&gt;
            &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;"World"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  สร้าง UI ด้วย Column และ Row
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;Column&lt;/code&gt; และ &lt;code&gt;Row&lt;/code&gt; เป็น Layout พื้นฐานของ Compose โดย&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Column&lt;/code&gt; จะแสดง Child เรียงเป็นแนวตั้ง คล้ายกับ LinearLayout ที่มี &lt;code&gt;orientation="vertical"&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Row&lt;/code&gt; จะแสดง Child เรียงเป็นแนวนอน คล้ายกับ LinearLayout ที่มี &lt;code&gt;orientation="horizontal"&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;เราจะให้ Text และ Button อยู่ใน Column (กรอบสีแดง)เนื่องจากเรียงจากบนลงล่างและให้ตัว Column และ Icon อยู่ภายใน Row (กรอบสีน้ำเงิน)&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyavgnczqbwc6he51ja40.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fyavgnczqbwc6he51ja40.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;สร้าง Composable Function ในที่นี้ให้ชื่อว่า MyScreen&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม &lt;code&gt;Row&lt;/code&gt; โดยกำหนด Modifier ให้ แสดงผลเต็มทางแนวนอน และมี padding เป็น 16dp&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;     &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxWidth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;         &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;)){&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;     &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม &lt;code&gt;Column&lt;/code&gt; โดยกำหนด weight ให้ Column = 1&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxWidth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;         &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;+&lt;/span&gt;         &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม &lt;code&gt;Icon&lt;/code&gt;  ในเคสนี้เราต้องการให้ Icon ถูก random ขึ้นมา&lt;strong&gt;เฉพาะครั้งแรกที่เปิดแอพเท่านั้น&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxWidth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

         &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nc"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;VectorAsset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;VectorAsset&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;when&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nc"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;random&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;toInt&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Cloud&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudQueue&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudUpload&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;4&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudOff&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudDone&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;6&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;CloudDownload&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;7&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WbCloudy&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;8&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Wifi&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;9&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WifiCalling&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;10&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WifiLock&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;11&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WifiProtectedSetup&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;12&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WifiOff&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;13&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;WifiTethering&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="mi"&gt;14&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;PortableWifiOff&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Icons&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;Default&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;FavoriteBorder&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม &lt;code&gt;Text&lt;/code&gt; และ &lt;code&gt;Button&lt;/code&gt; เข้าไปที่ Column&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxWidth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;             &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;             &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Click Me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;             &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nc"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม &lt;code&gt;MyScreen&lt;/code&gt; เข้าไปที่ &lt;code&gt;onCreate&lt;/code&gt; ของ Activity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;MyAppTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Surface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MaterialTheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nc"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                        &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
                    &lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Preview
&lt;/h3&gt;

&lt;p&gt;เราสามารถ Preview หน้าตา UI ที่เราสร้างได้ด้วย &lt;code&gt;@Preview&lt;/code&gt; ให้เราทำการสร้าง Function แยก ชื่อว่า &lt;code&gt;PreviewMyScreen&lt;/code&gt; เพื่อใช้สำหรับ Preview อย่างเดียว&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showBackground&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;PreviewMyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;    &lt;span class="nc"&gt;ComposeStatePlaygroundTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;        &lt;span class="nc"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;showBackground = true&lt;/code&gt; เพื่อแสดง Background ของแอพ&lt;br&gt;
ทำการ Build app 1 ครั้งเพื่อ Preview&lt;br&gt;
หน้าตาที่ได้:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fghgshmghymtb59p6r6vq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fghgshmghymtb59p6r6vq.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
เรายังสามารถทำการกดปุ่ม Interactive เพื่อทำการลองเล่นหน้าตา UI ของเราก่อนที่จะ Run ลงเครื่องจริงๆ ได้ด้วย&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmhqjvbk1bo4evjfsdpt8.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmhqjvbk1bo4evjfsdpt8.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flyy6u5vqymsrjmc66nw8.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Flyy6u5vqymsrjmc66nw8.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;เนื่องจากเจ้า JetPack Compose นั้นเป็น Declarative UI โดยเจ้า  Declarative UI นั้นตัว Code เองคือตัวอธิบายว่าหน้าตา UI จะเป็นอย่างไร&lt;br&gt;
เมื่อ User กดปุ่ม เราต้องการให้ &lt;code&gt;Text&lt;/code&gt; แสดงค่า random Text จาก function ที่เราเตรียมไว้ หรือพูดง่ายๆก็คือ Update State ของ &lt;code&gt;Text&lt;/code&gt; นั่นเอง&lt;/p&gt;
&lt;h3&gt;
  
  
  State และ MutableState
&lt;/h3&gt;

&lt;p&gt;เป็น Build-in Interface ของ JetPack Compose โดยปกติ Composable Function จะทำการ "subscribe" กับ &lt;code&gt;value&lt;/code&gt; ของ &lt;code&gt;State&amp;lt;T&amp;gt;&lt;/code&gt; เมื่อ &lt;code&gt;value&lt;/code&gt; มีการเปลี่ยนแปลง Composable Function จะทำการ Recompose ตัวเองเพื่อ Update UI ใหม่&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Stable&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โดย value สามารถเปลี่ยนแปลงได้ผ่านทางการเรียก &lt;code&gt;MutableState&amp;lt;T&amp;gt;&lt;/code&gt; อีกที&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Stable&lt;/span&gt;
&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MutableState&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;State&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;T&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;value&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;T&lt;/span&gt;
    &lt;span class="o"&gt;....&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม State ให้ Function MyScreen&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;
    &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxWidth&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
              &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
              &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                  &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
             &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                 &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Click Me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
               &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nc"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Function &lt;code&gt;mutableStateOf&lt;/code&gt; จะทำการ return ค่า &lt;code&gt;MutableState&lt;/code&gt; โดยในที่นี้เราจะกำหนดค่าเริ่มต้นให้กับ State เลย ด้วยการเรียก &lt;code&gt;randomDisplayText()&lt;/code&gt; และเมื่อมีการกดปุ่มเราจะทำการ update ค่าของ text อีกครั้งด้วยการเรียก &lt;code&gt;text = randomDisplayText()&lt;/code&gt;&lt;br&gt;
อีกจุดนึงที่สังเกตเห็นได้คือมีการเรียกใช้ function &lt;code&gt;remember&lt;/code&gt; ซึ่งจะขออธิบายในลำดับถัดไป&lt;br&gt;
ลองรันแอพ:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkuwq8aarucjc85xhkgv1.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fkuwq8aarucjc85xhkgv1.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ทุกๆครั้งที่เรากดปุ่ม &lt;code&gt;Text&lt;/code&gt; ของเราอัพเดทถูกต้อง แต่จะเห็นว่า &lt;code&gt;Icon&lt;/code&gt; ก็โดนเปลี่ยนไปด้วย???? 🤨🤨🤨&lt;/p&gt;

&lt;p&gt;อย่างที่บอกไว้ก่อนหน้านั้น เนื่องจากว่า Composable function จะ "subscribe" ตัวเองกับ &lt;code&gt;State&lt;/code&gt; เมื่อ &lt;code&gt;State&lt;/code&gt; เปลี่ยน (ในที่นี้คือ &lt;code&gt;text&lt;/code&gt;) function จะมีการ Recompose เพื่อแสดงผลใหม่ ทำให้ ตัว Function เองโดนเรียกซ้ำทำให้ function &lt;code&gt;randomIconAsset&lt;/code&gt; โดนเรียกซ้ำอีกที&lt;/p&gt;

&lt;p&gt;ลองใส่ Log ที่ &lt;code&gt;MyScreen()&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Log&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;d&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"MyComposeApp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"MyScreen is called"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F19abh1cl8h0bsrzzv2i4.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F19abh1cl8h0bsrzzv2i4.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;สังเกตุได้ว่าค่าที่ Log ไม่ถูก Print เมื่อค่าที่ Random ได้ยังเป็นค่าเดิม&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;เอ๊ะแล้วแบบนี้มันแตกต่างกับ &lt;code&gt;randomDisplayText()&lt;/code&gt; ยังไง 🤔??&lt;/p&gt;
&lt;h3&gt;
  
  
  Memory ใน Function
&lt;/h3&gt;

&lt;p&gt;จุดที่แตกต่างสำคัญเลยระหว่าง &lt;code&gt;randomDisplayText&lt;/code&gt; &lt;code&gt;randomIconAsset&lt;/code&gt; ที่ชัดเจนเลยคือ:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;randomDisplayText&lt;/code&gt; เป็น Initiate value ของ State (เราเรียก &lt;code&gt;randomDisplayText&lt;/code&gt; ใน &lt;code&gt;mutableStateOf&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mutableStateOf&lt;/code&gt; ถูก wrap ด้วย &lt;code&gt;remember&lt;/code&gt;
Composable function จะมีความสามารถในการจดจำค่าก่อนหน้าว่าเป็นค่าอะไร เมื่อเกิดการ Recomposition ขึ้น ตัว composable function จะนำค่าที่จดจำอยู่มาแสดงแทน ในกรณีของเรา เรามีการจดจำ "&lt;code&gt;State&amp;lt;String&amp;gt;&lt;/code&gt;" ซึ่ง &lt;code&gt;value&lt;/code&gt; ของ &lt;code&gt;State&amp;lt;String&amp;gt;&lt;/code&gt; ก็คือ &lt;code&gt;text&lt;/code&gt; นั่นเอง
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;สามารถเขียนในอีกแบบได้เป็น&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nc"&gt;MutableState&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;())}&lt;/span&gt;
&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;           &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;               &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Click Me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  แก้ไม่ให้ Icon Update ทุกครั้ง
&lt;/h5&gt;

&lt;p&gt;วิธีการแก้ในเคสนี้เราสามารถทำได้สองแบบ &lt;br&gt;
&lt;strong&gt;แบบที่ 1:&lt;/strong&gt;&lt;br&gt;
เราสามารถใช้เจ้า &lt;code&gt;remember&lt;/code&gt; กับ &lt;code&gt;randomIconAsset&lt;/code&gt; ได้ เพื่อให้ค่าที่ถูก random มาครั้งแรก ถูกจดจำไว้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;asset&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nc"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;แบบที่ 2:&lt;/strong&gt;&lt;br&gt;
เราสามารถทำให้ &lt;code&gt;MyRandomIcon&lt;/code&gt; ไม่มีการ Share State กันระหว่างตัวมันเองกับ MyScreen โดยเราสามารถทำได้โดยย้าย &lt;code&gt;randomIconAsset&lt;/code&gt; ไปไว้ใน &lt;code&gt;MyRandomIcon&lt;/code&gt; แทน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nc"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  State hoisting
&lt;/h3&gt;

&lt;p&gt;จาก Code ชุดข้างบน เราจะเห็นว่าตัว Function &lt;code&gt;MyScreen&lt;/code&gt; เองนั้นเป็นคนถือ State เอาไว้ (Stateful) ในเคสนี้นั้นเราต้องการให้ ViewModel เป็นคนถือ State แทน เรียกว่า hoist/lift State ไปไว้ที่ LiveData ของ ViewModel แทน &lt;br&gt;
เมื่อ User กดปุ่ม เราจะ Update value ใน LiveData ที่อยู่ใน ViewModel เท่ากับเราต้องทำการ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Bind ค่าที่อยู่ใน LiveData กับ Text&lt;/li&gt;
&lt;li&gt;Bind action ของการกดปุ่มเข้ากับ &lt;code&gt;onNameChanged&lt;/code&gt; function ของ ViewModel&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ทำการเพิ่ม Parameter ใน Function เป็น String และ lambda สำหรับการแสดงผลและการกดปุ่มและนำ State ของ Function ออก&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;onButtonClick&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;Unit&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MutableState&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nc"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fillMaxWidth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;16&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;dp&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
           &lt;span class="nc"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;modifier&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Modifier&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mf"&gt;1f&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;             &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;             &lt;span class="nc"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;onClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;onButtonClick&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Click Me"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
             &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;asset&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;remember&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nf"&gt;randomIconAsset&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
           &lt;span class="nc"&gt;MyRandomIcon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;asset&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;asset&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@Preview&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;showBackground&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Composable&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;PreviewMyScreen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nc"&gt;ComposeStatePlaygroundTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;       &lt;span class="nc"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello Android"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt; 
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จาก Code ชุดข้างบนจะทำให้ function MyScreen ไม่มีการถือ State เอาไว้ สำหรับเปลี่ยนแปลงค่า displaying Text (Stateless)&lt;/p&gt;

&lt;h3&gt;
  
  
  observeAsState
&lt;/h3&gt;

&lt;p&gt;JetPack Compose ได้สร้าง extension function มาให้เราแล้วชื่อ &lt;code&gt;observeAsState&lt;/code&gt; เพื่อทำการ Convert LiveData ให้เป็น State&lt;/p&gt;

&lt;p&gt;ใน &lt;code&gt;onCreate&lt;/code&gt; ทำการ convert LiveData ใน ViewModel ให้เป็น State&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;setContent&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nc"&gt;MyAppTheme&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;Surface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MaterialTheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                     &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeAsState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="nc"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;                     &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
&lt;span class="p"&gt;+&lt;/span&gt;                     &lt;span class="n"&gt;onButtonClick&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;onNameChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ลองรันแอพอีกครั้ง&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmylnts1qcpw8g4vdat7g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fmylnts1qcpw8g4vdat7g.gif" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
แน่นอนว่าการทำงานยังเหมือนเดิม สิ่งที่แตกต่างคือ State นั้นอยู่ที่ LiveData ของ ViewModel แทน&lt;br&gt;
จริงๆเรายังสามารถให้ State อยู่ที่ ViewModel ได้โดยตรงด้วยโดย:&lt;/p&gt;

&lt;p&gt;เอา LiveData ออก&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt;     &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;_name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MutableLiveData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt;     &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;LiveData&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เปลี่ยนเป็น State แทน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.compose.runtime.mutableStateOf&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.compose.runtime.setValue&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;androidx.compose.runtime.getValue&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainViewModel&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ViewModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;     &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="nf"&gt;mutableStateOf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;         &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;แก้ไข function &lt;code&gt;onNameChanged&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onNameChanged&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;_name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;         &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;randomDisplayText&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใส่ &lt;code&gt;name&lt;/code&gt; เข้าไปตรงๆที่ MyScreen:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nc"&gt;Surface&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MaterialTheme&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;colors&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;text&lt;/span&gt; &lt;span class="k"&gt;by&lt;/span&gt; &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;observeAsState&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
   &lt;span class="nc"&gt;MyScreen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt;    &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="n"&gt;viewModel&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;onNameChanged&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลลัพธ์ที่ได้ก็ยังคงเหมือนเดิม&lt;br&gt;
&lt;em&gt;เราสามารถเรียกใช้ &lt;code&gt;mutableStateOf&lt;/code&gt; ใน ViewModel ได้เมื่อเรามั่นใจว่า View นั้นเป็น Compose แต่ถ้าเรายังต้องใช้ ViewModel contact กับ Android View System เดิม ใช้ &lt;code&gt;LiveData&lt;/code&gt; หรือ &lt;code&gt;State/Share Flow&lt;/code&gt; น่าจะเหมาะสมกว่า&lt;/em&gt;&lt;br&gt;
สำหรับคนที่สนใจ แนะนำว่าสามารถศึกษาเพิ่มเติมได้จาก &lt;a href="https://developer.android.com/courses/pathways/compose" rel="noopener noreferrer"&gt;JetPack Compose - Pathway&lt;/a&gt; ในบทความหน้าจะลองยกตัวอย่าง Compose UI ที่ซับซ้อนขึ้นเช่นการใช้ &lt;code&gt;LazyColumnFor&lt;/code&gt; (&lt;code&gt;RecycelerView&lt;/code&gt; ในโลกของ JetPack Compose) รวถึงการใช้ &lt;code&gt;State/ShareFlow&lt;/code&gt; หรือหากท่านใดสนใจ สามารถดู source code ตัวอย่างได้จากเจ้าของ Blog &lt;a href="https://github.com/jutikorn/ComposePlayground" rel="noopener noreferrer"&gt;ทางนี้เลย&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Reference:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/jetpack/compose/state" rel="noopener noreferrer"&gt;State and Jetpack Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/codelabs/jetpack-compose-state" rel="noopener noreferrer"&gt;Android Codelab - State in Compose&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/courses/pathways/compose" rel="noopener noreferrer"&gt;JetPack Compose - Pathway&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>jetpack</category>
      <category>compose</category>
    </item>
    <item>
      <title>Modernized Android architecture - Hilt</title>
      <dc:creator>Eddie Eddie</dc:creator>
      <pubDate>Sat, 02 Jan 2021 14:52:16 +0000</pubDate>
      <link>https://dev.to/eddiej/modernized-android-architecture-part1-hilt-hni</link>
      <guid>https://dev.to/eddiej/modernized-android-architecture-part1-hilt-hni</guid>
      <description>&lt;p&gt;&lt;em&gt;Cover Photo by Roman Koval from&lt;/em&gt; &lt;a href="https://www.pexels.com/photo/glowing-lightsaber-placed-on-white-table-3717321/" rel="noopener noreferrer"&gt;Pexels&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;แรกเริ่มเดิมทีว่าจะลองเขียน Blog เกี่ยวกับ JetPack Compose อย่างเดียว แต่ทำไปทำมาตอนลองทำ Sample Project แล้วมันดันมีจุดที่น่าสนใจหลายอย่างเลยคิดว่าถ้าเราเขียนเรื่อง JetPack Compose อย่างเดียวคงไม่จบ เลยอยากจะเขียนบทความนี้แยกเป็นหลายๆส่วน โดย Follow ตามตัวอย่าง code แบ่งตามเรื่องที่น่าสนใจดังนี้&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Hilt&lt;/li&gt;
&lt;li&gt;JetPack Compose (UI Component) &amp;amp; Unidirectional Data Flow&lt;/li&gt;
&lt;li&gt;จัดการ ใน JetPack Compose ด้วย LiveData และ State&lt;/li&gt;
&lt;li&gt;จัดการ ใน JetPack Compose ด้วย State/Share Flow&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Hilt
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://dagger.dev/hilt/" rel="noopener noreferrer"&gt;Hilt&lt;/a&gt; คือ Library ที่ Google เพิ่งจะออกมาสดๆร้อนๆ โดยถูกสร้าง on-top ด้วย Dagger2 อีกที ใช้สำหรับการทำ &lt;a href="https://en.wikipedia.org/wiki/Dependency_injection" rel="noopener noreferrer"&gt;Dependency Injection&lt;/a&gt; ใน Android ให้ง่ายขึ้น เรียกว่าเป็น Simplified version ของ Dagger Android ก็ว่าได้ &lt;/p&gt;

&lt;h3&gt;
  
  
  ทำไมต้องทำ Dependency Injection
&lt;/h3&gt;

&lt;p&gt;เพื่อให้เข้าใจภาพแบบง่ายขึ้น ยกตัวอย่าง สมมติเรามี class ที่ต้องทำหน้าที่ส่งข้อความโดยแรกเริ่มเดิมที่ ข้อความที่ส่งไปมันก็เป็น email ธรรมดา โดย function จะ return True หรือ False มาหากส่งข้อความสำเร็จหรือไม่สำเร็จ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="c1"&gt;// TO-DO email sending implementation is processed here&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;โดยเจ้า Class นี้ก็จะถูกเรียกใช้งานในอีก Layer นึง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageProcessor&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;sendProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;// doing many things to get message&lt;/span&gt;
 &lt;span class="n"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendEmail&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MessageProcessor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าดูจากการใช้งานแล้ว ในเคสนี้ก็ไม่น่ามีอะไร เจ้า &lt;code&gt;MessageProcessor&lt;/code&gt; ก็ไป process ข้อความมาเพื่อจะส่ง message จากนั้นก็ส่งผ่าน &lt;code&gt;EmailSender&lt;/code&gt; ก็จบ ดูแล้วก็ไม่น่าจะมีปัญหาตรงไหน 🤔&lt;/p&gt;

&lt;p&gt;⚠️ ประเด็นอยู่ตรงที่ว่า ถ้าเราสังเกตุดีๆ เราจะเห็นว่า &lt;code&gt;MessageProcessor&lt;/code&gt; นั้นมัน &lt;code&gt;depends&lt;/code&gt; กับตัว &lt;code&gt;EmailSender&lt;/code&gt; อยู่ ถ้าเราสร้าง class &lt;code&gt;MessageProcessor&lt;/code&gt; มาเมื่อไหร่ ตัว &lt;code&gt;EmailSender&lt;/code&gt; ก็จะถูกสร้างมาด้วยอัตโนมัติ ให้เราลองนึกถึงการเขียน Test เจ้าตัว &lt;code&gt;MessageProcessor&lt;/code&gt; คงเป็นเรื่องยากพอสมควร&lt;br&gt;
สมมติว่าเราสามารถเขียน Test มันได้ แล้ววันนึง Requirement มันเปลี่ยนแทนที่จะต้องส่ง email กลายเป็นว่าต้องส่ง sms แทนล่ะ เท่ากับว่า Test ที่เราเขียนไปอาจจะต้องแก้พอสมควรเลย แบบนี้ไม่ดีแน่ สิ่งที่เราควรทำคือ ลด dependency ระหว่าง class แต่ละ class ลงซะ เลยเป็นที่มาของการทำ Dependency Injection &lt;br&gt;
ในเคสนี้จะยกตัวอย่างการทำ &lt;em&gt;Constructor Injection&lt;/em&gt; เนื่องจากว่าเป็นวิธีที่ง่ายต่อความเข้าใจรวมถึงง่ายต่อการเทสกว่า มากๆ&lt;/p&gt;

&lt;p&gt;สร้าง interface MessageSender&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ให้ class &lt;code&gt;EmailSender&lt;/code&gt; extends &lt;code&gt;MessageSender&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// TO-DO email sending implementation is processed here&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ให้ class &lt;code&gt;SmsSender&lt;/code&gt; extends &lt;code&gt;MessageSender&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SmsSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;Boolean&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="c1"&gt;// TO-DO sms sending implementation is processed here&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;inject MessageSender ไปที่ constructor ของ MessageProcessor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageProcessor&lt;/span&gt; &lt;span class="k"&gt;internal&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;msgSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;sendProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;message&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="c1"&gt;// doing many things to get message&lt;/span&gt;
 &lt;span class="n"&gt;msgSender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Main&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MessageProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;SmsSender&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unit Test ของ &lt;code&gt;MessageProcessor&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageProcessorTest&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;msgSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageSender&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;mock&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;MessageProcessor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgSender&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nd"&gt;@Test&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;`test&lt;/span&gt; &lt;span class="nf"&gt;sendProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;msgSender&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;is&lt;/span&gt; &lt;span class="nf"&gt;called`&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sendProcessedMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
  &lt;span class="nc"&gt;Mockito&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;verify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msgSender&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;anyString&lt;/span&gt;&lt;span class="p"&gt;()))&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จริงๆ หลักการของ Dependency Injection มีง่ายๆแค่นี้ Dagger2, DaggerAndroid และ Hilt แค่ช่วยให้เราสามารถทำงานได้ง่ายขึ้นบน Android เท่านั้นเอง&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Hilt
&lt;/h3&gt;

&lt;p&gt;จริงๆ วิธีการ Setup นั้นไม่ยากเลย โดย Google ได้อธิบายเป็น Step เอาไว้ให้เราแล้ว สามารถเข้าไปทำตามได้ที่&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android" rel="noopener noreferrer"&gt;นี่&lt;/a&gt; ทั้งนี้ทั้งนั้นเผื่อคนที่ไม่อยาก Switch ไปอีกหน้า ผมจะเขียนวิธีการตาม Google เอาไว้ในนี้เลยละกัน&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ไปที่ file &lt;code&gt;build.gradle&lt;/code&gt; ที่ Root ของ Project เราแล้วใส่
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="k"&gt;buildscript&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
    &lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="o"&gt;...&lt;/span&gt;
        &lt;span class="n"&gt;classpath&lt;/span&gt; &lt;span class="s2"&gt;"com.google.dagger:hilt-android-gradle-plugin:$hilt_version"&lt;/span&gt;
    &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;ไปที่ file &lt;code&gt;build.gradle&lt;/code&gt; ของ module ที่ต้องการใช้ Hilt ในเคสนี้คือ &lt;code&gt;app/build.gradle&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'kotlin-kapt'&lt;/span&gt;
&lt;span class="n"&gt;apply&lt;/span&gt; &lt;span class="nl"&gt;plugin:&lt;/span&gt; &lt;span class="s1"&gt;'dagger.hilt.android.plugin'&lt;/span&gt;

&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;dependencies&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;implementation&lt;/span&gt; &lt;span class="s2"&gt;"com.google.dagger:hilt-android:$hilt_version"&lt;/span&gt;
    &lt;span class="n"&gt;kapt&lt;/span&gt; &lt;span class="s2"&gt;"com.google.dagger:hilt-android-compiler:$hilt_version"&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hilt ใช้ feature ของ Java8 จึงต้องประกาศด้วย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight gradle"&gt;&lt;code&gt;&lt;span class="n"&gt;android&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;...&lt;/span&gt;
  &lt;span class="n"&gt;compileOptions&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;sourceCompatibility&lt;/span&gt; &lt;span class="n"&gt;JavaVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VERSION_1_8&lt;/span&gt;
    &lt;span class="n"&gt;targetCompatibility&lt;/span&gt; &lt;span class="n"&gt;JavaVersion&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;VERSION_1_8&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sync Project ให้เรียบร้อย หลังจากนั้นทำการสร้าง Application class ของเราขึ้นมาแล้วใส่ &lt;code&gt;@HiltAndroidApp&lt;/code&gt; ให้เรียบร้อย&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;android.app.Application&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;dagger.hilt.android.HiltAndroidApp&lt;/span&gt;

&lt;span class="nd"&gt;@HiltAndroidApp&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ComposePlaygroundApplication&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ใน Activity ของเราใส่ &lt;code&gt;@AndroidEntryPoint&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เท่านี้เราก็พร้อมใช้งาน Hilt แล้ว &lt;/p&gt;

&lt;h5&gt;
  
  
  เทียบกับ Dagger
&lt;/h5&gt;

&lt;p&gt;ใน Hilt เราเพียงใส่ &lt;code&gt;@HiltAndroidApp&lt;/code&gt; ที่ Application Class ในขณะที่&lt;br&gt;
Dagger2 เราอาจจะต้องสร้าง &lt;code&gt;Component&lt;/code&gt; class ที่มี &lt;code&gt;fun inject(activity: MainActivity)&lt;/code&gt; ข้างใน หรือถ้าใครใช้ Dagger-Android วิธีการอาจจะซับซ้อนกว่านี้พอควร ในขณะที่ Hilt เพียงแค่เราประกาศ annotation ก็เพียงพอแล้ว&lt;/p&gt;
&lt;h3&gt;
  
  
  Field Injection
&lt;/h3&gt;

&lt;p&gt;ใน Hilt นั้น การ inject นั้นง่ายมากๆ ยกตัวอย่างให้เห็นภาพ เรามี Activity class แล้วต้องการจะ inject class นึงเข้าไปใน Activity สมมติง่ายๆว่าเป็น &lt;code&gt;EmailSender&lt;/code&gt; class ละกัน&lt;br&gt;
Activity ของเรา&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;class สำหรับส่ง email&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$msg is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ถ้าเราต้องการ inject &lt;code&gt;EmailSender&lt;/code&gt; เข้าไปใน Activity เราสามารถประกาศ &lt;code&gt;@Inject&lt;/code&gt; ที่ Constructor ได้เลยตามนี้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; 
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"$msg is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ภายใน Activity เราสามารถประกาศ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="n"&gt;laterinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพียงเท่านี้ &lt;code&gt;EmailSender&lt;/code&gt; ก็พร้อมใช้งานใน &lt;code&gt;MainActivity&lt;/code&gt; ของเรา &lt;/p&gt;

&lt;h3&gt;
  
  
  Constructor Injection
&lt;/h3&gt;

&lt;p&gt;จากตัวอย่างข้างบน สมมติเราต้องการจะ format message ก่อนจะส่งโดยเรียกใช้class MessageFormatter โดยเราต้องการ Inject  &lt;code&gt;MessageFormatter&lt;/code&gt; เข้าไปใน &lt;code&gt;EmailSender&lt;/code&gt; ผ่านทาง Constructor เราก็สามารถทำได้ยกตัวอย่าง&lt;/p&gt;

&lt;p&gt;class สำหรับ format ข้อความ&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;formatMessages&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"formatted $msg"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพิ่ม &lt;code&gt;@Inject constructor()&lt;/code&gt; ไปที่ &lt;code&gt;MessageFormatter&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; 
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"formatted $msg"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; 
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${formatter.format(msg)}is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  ปัญหา Injection กับ Interface
&lt;/h4&gt;

&lt;p&gt;จากตัวอย่างข้างบนเราทำการ inject class ตรงๆ เข้าไปใน constructor ซึ่งสามารถทำได้ แต่ในหลายๆครั้ง เราต้องการให้ code ของเรามีความ abstract มากขึ้น เพื่อง่ายต่อการ Test วิธีการส่วนมากที่เราทำกันนั้นคือการสร้าง interface มาครอบ class ของเราอีกที ซึ่งใน Hilt ไม่สามารถทำได้ตรงๆตามวิธีการข้างบน &lt;br&gt;
ยกตัวอย่าง:&lt;br&gt;
เรามี Class ที่ชื่อ EmailSender สำหรับส่ง email อยู่แล้วโดยเราต้องการที่จะ Format ข้อความเราก่อนจะส่ง โดยในที่นี้เราจะสร้าง Interface มาเพื่อทำการ format ข้อความชื่อ &lt;code&gt;MessageFormatter&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;สร้าง Interface ชื่อ MessageFormatter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง class ชื่อ MessageFormatterV1Impl ที่สืบทอดมาจาก MessageFormatter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatterV1Impl&lt;/span&gt; 
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"formatted $msg"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง class ชื่อ MessageFormatterV2Impl ที่สืบทอดมาจาก MessageFormatter&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatterV2Impl&lt;/span&gt; 
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"$msg is formatted"&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เรามี 2 classes ที่ extend มาจาก &lt;code&gt;MessageFormatter&lt;/code&gt; ชื่อ &lt;code&gt;MessageFormatterV1Impl&lt;/code&gt; และ &lt;code&gt;MessageFormatterV2Impl&lt;/code&gt; โดยทั้งสอง class ทำหน้าที่ format ข้อความเหมือนกัน แต่วิธีการ format ข้อความต่างกัน&lt;/p&gt;

&lt;p&gt;inject &lt;code&gt;MessageFormatter&lt;/code&gt; ที่เป็น Inteface เข้าไปใน constructor ของ &lt;code&gt;EmailSender&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; 
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"${formatter.format(msg)}is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Error หลังจาก Build:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error: [Dagger/MissingBinding] MessageFormatter cannot be provided without an @Provides-annotated method.
  public abstract static class ApplicationC implements ComposePlaygroundApplication_GeneratedInjector,
                         ^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จริงๆ Error นั้นเรียกว่า make sense มากๆ ตรงที่ code ของเราจะรู้ได้ยังไงว่าจะเอา instant ไหน inject เข้าไปใน Constructor กันล่ะในเมื่อมี 2 classes ที่ implement interface เดียวกัน ซึ่งวิธีการแก้ปัญหานั้นอาจจะต้องใช้ตัวช่วยสักหน่อย นั่นก็คือการสร้าง &lt;code&gt;@Module&lt;/code&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;หมายเหตุ&lt;/strong&gt; 💡 &lt;em&gt;ข้อดีของการทำ Constructor injection คือเราไม่จำเป็นต้องทำอะไรเพิ่มเติมเลยหากเราต้องการจะเขียน UnitTest ไม่ใช่แค่สำหรับ Hilt แต่ Dagger ด้วยก็เหมือนกัน โดยเฉพาะอย่างยิ่งการทำ Constructor injection ด้วย Interface นั้นทำให้การ Mock เป็นเรื่องง่ายมากๆครับ&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Component
&lt;/h3&gt;

&lt;p&gt;ก่อนจะเริ่มสร้าง Module นั้น สิ่งที่เราต้องทำความเข้าใจก่อนคือ &lt;a href="https://developer.android.com/training/dependency-injection/hilt-android#component-lifetimes" rel="noopener noreferrer"&gt;Component&lt;/a&gt; และ &lt;a href="https://developer.android.com/training/dependency-injection/hilt-android#component-scopes" rel="noopener noreferrer"&gt;Component Scope&lt;/a&gt; ตัว Hilt เองนั้นจะมีการ pre-create Hilt Components มาให้เราใช้งานแล้วโดยที่เราไม่จำเป็นต้องไปสร้าง Component เองเหมือนที่เราทำใน Dagger โดยสามารถแบ่งตามนี้&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9if0kr625x3avis7qpsk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F9if0kr625x3avis7qpsk.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
ถึงตรงนี้หลายคนอาจจะงงว่า Component นั้นคืออะไร ถ้าพูดให้เข้าใจง่ายคือ เปรียบเสมือน Layer ที่เราอยากจะให้ instance ที่เราสร้างเข้าไปอยู่ ยกตัวอย่าง เราอยากจะให้ &lt;code&gt;EmailSender&lt;/code&gt; class ของเราใช้ได้ Activity เราก็เพียงแค่ต้องมั่นใจว่า มันถูก "ใส่" เข้าไปใน (&lt;code&gt;@InstallIn&lt;/code&gt;) &lt;code&gt;ActivityComponent&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;แล้วเมื่อไหร่ที่ instance เราถูกสร้างและถูกทำลายล่ะ?&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7o26pgockf3b16t6yezb.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F7o26pgockf3b16t6yezb.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
instance ที่ถูก bound เข้าไปจะถูกสร้างและทำลายตามแต่ละ Component ที่ตัวมันเองโดน installed ลงไป&lt;/p&gt;
&lt;h3&gt;
  
  
  Scope
&lt;/h3&gt;

&lt;p&gt;โดยปกติแล้ว instance ที่ถูกสร้างขึ้นมาจะไม่มีการกำหนด scope ของการใช้งาน (unscoped) นั่นหมายความว่า ทุกๆครั้งที่มีการเรียกใช้ class นั้น instance นั้นจะถูกสร้างขึ้นมาใหม่ ยกตัวอย่าง:&lt;br&gt;
เรามี class EmailSender&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทำการ inject EmailSender ในอีก class นึงผ่านทาง Constructor ชื่อว่า MessageHandler แล้วลอง Print ค่าออกมาดู&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageHandler&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;sender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"emailSender from ${this::class.java} $sender"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทำการ inject ทั้ง EmailSender และ MessageHandler ใน Activity&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;messageHandler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageHandler&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"emailSender from ${this::class.java} $emailSender"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;เรา Inject &lt;code&gt;MessageHandler&lt;/code&gt; เพื่อให้ Hilt สร้าง instance ของ MessageHandler เพื่อดูค่า &lt;code&gt;EmailSender&lt;/code&gt; ที่เรา print ใน init ของ MessageHandler&lt;/li&gt;
&lt;li&gt;เรา Inject &lt;code&gt;EmailSender&lt;/code&gt; เพื่อให้ Hilt สร้าง instance ของ &lt;code&gt;EmailSender&lt;/code&gt; เพื่อดูค่า &lt;code&gt;EmailSender&lt;/code&gt; ที่เรา print ใน onCreate ของ Activity&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ค่าที่ได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-04 16:13:03.060 7374-7374/? I/System.out: emailSender from class MessageHandler EmailSender@cacc883
2021-01-04 16:13:03.102 7374-7374/? I/System.out: emailSender from class MainActivity EmailSender@72ec68a
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะเห็นว่า Instance นั้นเป็นคนละตัวกัน&lt;/p&gt;

&lt;p&gt;ลองกำหนด Scope ลงไปใน EmailSender ในเคสนี้จะลองกำหนด &lt;code&gt;@ActivityScoped&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@ActivityScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ค่าที่ได้:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-04 16:16:06.611 7714-7714/? I/System.out: emailSender from MessageHandler EmailSender@b6f3903
2021-01-04 16:16:06.634 7714-7714/? I/System.out: emailSender from class MainActivity EmailSender@b6f3903
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Scope เปรียบเสมือนขอบเขตของการใช้งานว่าเราอยากจะให้ Instance นั้นถูกใช้ได้ในขอบเขตไหนลงไปเป็นลำดับขั้น โดย Hilt เอง ก็ได้ทำการ Predefined เอาไว้แล้วตามนี้&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxs5oa0zwik8dlb8uo04a.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fxs5oa0zwik8dlb8uo04a.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;ยกตัวอย่าง:&lt;br&gt;
&lt;strong&gt;ตัวอย่างที่ 1&lt;/strong&gt; ต้องการให้ &lt;code&gt;class EmailSender&lt;/code&gt; ใช้งานได้ใน &lt;code&gt;Activity&lt;/code&gt; และให้ &lt;code&gt;class EmailSender&lt;/code&gt; และมีขอบเขตการใช้งานภายใน Activity ลงไป&lt;br&gt;
เทียบตาราง:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd8kybhhtdhxwcytdt7o3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Fd8kybhhtdhxwcytdt7o3.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ต้องให้ &lt;code&gt;class EmailSender&lt;/code&gt; ถูก Inject ใน &lt;code&gt;Activity&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ต้องให้ &lt;code&gt;class EmailSender&lt;/code&gt; มี Scope เป็น &lt;code&gt;ActivityScope&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง Code:&lt;br&gt;
&lt;em&gt;ประกาศ @ActivityScoped&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ActivityScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"msg is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ใช้งาน EmailSender ใน Activity&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ตัวอย่างที่ 2&lt;/strong&gt; ต้องการให้ &lt;code&gt;class EmailSender&lt;/code&gt; ใช้งานได้ใน &lt;code&gt;Fragment&lt;/code&gt; และให้ &lt;code&gt;class EmailSender&lt;/code&gt; และมีขอบเขตการใช้งานภายใน &lt;code&gt;Fragment&lt;/code&gt; ลงไป&lt;br&gt;
เทียบตาราง:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F048zacod6e1j2jt4ddmu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F048zacod6e1j2jt4ddmu.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ต้องให้ &lt;code&gt;class EmailSender&lt;/code&gt; ถูก Inject ใน &lt;code&gt;Fragment&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ต้องให้ &lt;code&gt;class EmailSender&lt;/code&gt; มี Scope เป็น &lt;code&gt;FragmentScope&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง Code:&lt;br&gt;
&lt;em&gt;ประกาศ @FragmentScoped&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@FragmentScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"msg is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ใช้งาน EmailSender ใน Fragment&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;ตัวอย่างที่ 3&lt;/strong&gt; ต้องการให้ &lt;code&gt;class EmailSender&lt;/code&gt; ใช้งานได้ใน &lt;code&gt;Fragment&lt;/code&gt; &lt;strong&gt;แต่&lt;/strong&gt;ยังให้ &lt;code&gt;class EmailSender&lt;/code&gt; และมีขอบเขตการใช้งานภายใน Activity ลงไป&lt;br&gt;
เทียบตาราง:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F48zd70dsrbq5x3z1vraz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2F48zd70dsrbq5x3z1vraz.png" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ต้องให้ &lt;code&gt;class EmailSender&lt;/code&gt; ถูก Inject ใน &lt;code&gt;Fragment&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;ต้องให้ &lt;code&gt;class EmailSender&lt;/code&gt; มี Scope เป็น &lt;code&gt;ActivityScope&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;ตัวอย่าง Code:&lt;br&gt;
&lt;em&gt;ประกาศ @ActivityScoped&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ActivityScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"msg is sent"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ใช้งาน EmailSender ใน Fragment&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyFragment&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Fragment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;เนื่องจากว่า ขอบเขตการใช้งานของ EmailSender อยู่ใน Activity แต่การใช้งานเรานำไปใช้ใน Fragment ซึ่งอยู่ภายใต้ Activity อีกที ในกรณีนี้นั้นสามารถทำได้&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ข้อควรระวัง&lt;/strong&gt; Scope กับ Component นั้นมีความสัมพันธ์กันเป็นลำดับชั้น ถ้าหากเราประกาศ Scope กับ Component ไม่ถูกต้องเราอาจจะเจอ Error ได้ยกตัวอย่าง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ให้ &lt;code&gt;class EmailSender&lt;/code&gt; ถูกใช้งานใน Activity&lt;/li&gt;
&lt;li&gt;แต่ให้ &lt;code&gt;class EmailSender&lt;/code&gt; มี Scope เป็น &lt;code&gt;FragmentScope&lt;/code&gt; เพราะต้องการให้ &lt;code&gt;Class EmailSender&lt;/code&gt; มีขอบเขตการใช้งานแค่ภายใน &lt;code&gt;Fragment&lt;/code&gt; &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Compile Error ที่เกิดขึ้น:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;error: [Dagger/IncompatiblyScopedBindings] ComposePlaygroundApplication_HiltComponents.ActivityC scoped with @dagger.hilt.android.scopes.ActivityScoped may not reference bindings with different scopes:
  public abstract static class ApplicationC implements ...,
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  แก้ไขปัญหา Constructor Injection กับ Interface
&lt;/h4&gt;

&lt;p&gt;จากที่บอกไปด้านบนคือ วิธีการแก้ไขนั้นทำได้ไม่ยากโดยการใช้ &lt;code&gt;Module&lt;/code&gt; ซึ่งวิธีการใช้งาน Module ของ Hilt นั้นมี 2 วิธีหลักๆ คือการ &lt;code&gt;@Binds&lt;/code&gt; และ &lt;code&gt;@Provides&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Binds module
&lt;/h3&gt;

&lt;p&gt;วิธีการ bind instance ด้วยการใช้ &lt;code&gt;@Binds&lt;/code&gt; ค่อนข้างเรียบง่ายและเหมาะกับการแก้ปัญหา constructor injection ด้วย interface ในกรณีที่เรามี class ที่เราต้องการ bind instance เข้าไป ยกตัวอย่าง:&lt;/p&gt;

&lt;p&gt;เรามี MessageFormatter ที่เป็น interface และมี class MessageFormatterImpl ที่เป็น class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;interface&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatterImpl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;format&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;"Formatted $msg"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ต้องการ inject เข้าไปที่ constructor ของ EmailSender class&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;formatter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เราต้องการ Inject &lt;code&gt;EmailSender&lt;/code&gt; เข้าไปที่ Activity โดยที่ Compile ผ่าน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เริ่มทำการสร้าง Module ในที่นี้จะให้ชื่อว่า &lt;code&gt;MessageSendingModule&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageSendingModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทำการประกาศว่าจะทำ Module ไปใช้ที่ไหน ในที่นี้ เราต้องการใช้ &lt;code&gt;EmailSender&lt;/code&gt; ที่ Activity เราจึงต้องประกาศ &lt;code&gt;@InstallIn(ActivityComponent::class)&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ActivityComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageSendingModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทำการ Bind Instance ของ &lt;code&gt;MessageFormatter&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ActivityComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageSendingModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Binds&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;bindMessageFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;impl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatterImpl&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;จุดสังเกตุ&lt;/strong&gt; ⚠️⚠️ เราใส่ &lt;code&gt;MessageFormatterImpl&lt;/code&gt; ที่เป็น &lt;code&gt;class&lt;/code&gt; ลงไปเป็น parameter ของ &lt;code&gt;bindMessageFormatter&lt;/code&gt; และให้ function return &lt;code&gt;MessageFormatter&lt;/code&gt; ที่เป็น &lt;code&gt;Interface&lt;/code&gt;&lt;br&gt;
ทำการประกาศ Scope ของ &lt;code&gt;MessageFormatter&lt;/code&gt; เคสนี้ เราต้องการให้มันมีขอบเขตการใช้งานภายใน Activity ลงไป ดังนั้นต้องใช้ &lt;code&gt;@ActivityScope&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ActivityComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="k"&gt;abstract&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MessageSendingModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="nd"&gt;@Binds&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@ActivityScope&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;bindMessageFormatter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;impl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatterImpl&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="nc"&gt;MessageFormatter&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพียงเท่านี้เราก็สามารถ compile ได้ผ่านฉลุย 🚀🚀🚀&lt;/p&gt;

&lt;h3&gt;
  
  
  Provide module
&lt;/h3&gt;

&lt;p&gt;Provide module มักใช้ในกรณีที่เราต้องการสร้าง Instance ของ Class ด้วยเราเอง ยกตัวอย่าง หากเราต้องการ Inject &lt;code&gt;Gson&lt;/code&gt; instance การใช้ @Binds ตามตัวอย่างข้างบนไม่สามารถทำได้ วิธีการใช้ Provide module จึงเหมาะสมมากกว่า&lt;br&gt;
ตัวอย่าง: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ต้องการให้ &lt;code&gt;Gson&lt;/code&gt; เข้าถูกใช้งานที่ใดก็ได้ใน &lt;strong&gt;Application&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;ต้องการให้ Gson  มีขอบเขตการใช้งานภายใน &lt;strong&gt;Application&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;สร้าง module ในที่นี้จะให้ชื่อว่า &lt;code&gt;GsonModule&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GsonModule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;จุดสังเกตุ&lt;/strong&gt; ⚠️ class GsonModule ไม่ใช่ abstract class เหมือนในกรณี &lt;code&gt;@Binds&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;ประกาศ &lt;code&gt;@InstallIn(ApplicationComponent::class)&lt;/code&gt; เนื่องจากว่าเราต้องการให้ Gson ถูกใช้งานที่ Application level ในกรณีนี้ instance ของ Gson จะถูกนำไปใช้งานได้ทุกที่ของ App (หาก inject Gson ด้วย Hilt)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GsonModule&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง Function ที่ทำหน้าที่ Provide Gson&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GsonModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;provideGson&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Gson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GsonBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ประกาศ &lt;code&gt;@Singleton&lt;/code&gt; เพื่อให้ Gson มี มีขอบเขตการใช้งานภายที่ &lt;strong&gt;Application&lt;/strong&gt; ลงไป &lt;/p&gt;

&lt;p&gt;จากนั้นประกาศ @Provides&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@InstallIn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;ApplicationComponent&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="k"&gt;class&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nd"&gt;@Module&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;GsonModule&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Singleton&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Provides&lt;/span&gt;
&lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;provideGson&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="nc"&gt;Gson&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;GsonBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;เพียงเท่านี้เราก็สามารถ Inject Gson ไปที่ไหนก็ได้ใน App เพราะ Gson จะมีขอบเขตการใช้งานที่ Application layer ลงไป&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;หมายเหตุ&lt;/strong&gt; 💡 วิธีการสร้าง Module จำเป็นต้องให้ component ที่เราจะระบุใน &lt;code&gt;@InstallIn&lt;/code&gt; ตรงกันกับ &lt;code&gt;Scope&lt;/code&gt; รวมถึงการนำไปใช้งาน (inject) ด้วย ตามตาราง:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feagoa82u2shx563iuqp1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fi%2Feagoa82u2shx563iuqp1.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;br&gt;
เช่น:&lt;br&gt;
ต้องการ EmailSender class ใช้งานใน Fragment ลงไป (Fragment, View, Service) เราสามารถระบุ&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;@InstallIn&lt;/code&gt; &lt;code&gt;ApplicationComonent&lt;/code&gt; หรือ &lt;code&gt;AcivityComponent&lt;/code&gt; หรือ &lt;code&gt;FragmentComponent&lt;/code&gt; ได้&lt;/li&gt;
&lt;li&gt;ระบุ Scope เป็น &lt;code&gt;@Singleton&lt;/code&gt; หรือ &lt;code&gt;@ActivityScope&lt;/code&gt; หรือ &lt;code&gt;@FragmentScope&lt;/code&gt; โดยต้องตรงกับ Component ที่ InstallIn&lt;/li&gt;
&lt;li&gt;สามารถ inject EmailSender ได้ใน Fragment, View และ Service&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;
  
  
  Monolithic components
&lt;/h3&gt;

&lt;p&gt;อีกเรื่องที่สำคัญสำหรับ Hilt คือ การที่ Hilt นั้นมีโครงสร้าง แบบ &lt;a href="https://dagger.dev/hilt/monolithic" rel="noopener noreferrer"&gt;Monolithic components&lt;/a&gt; นั่นหมายความว่า ของที่อยู่ใน Components จะ&lt;strong&gt;ถูกใช้ได้ในทุกที่ใน Layer เดียวกัน&lt;/strong&gt; &lt;br&gt;
ยกตัวอย่าง:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Application เรามี 3 Activities ชื่อ &lt;code&gt;MainActivity&lt;/code&gt;, &lt;code&gt;SecondActivity&lt;/code&gt;, &lt;code&gt;ThirdActivity&lt;/code&gt; โดยให้ทั้งสาม Activities สามารถใช้งาน Hilt ได้โดยการระบุ &lt;code&gt;@AndroidEntryPoint&lt;/code&gt; บน Activities ทั้ง 3 ตัว
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThirdActivity&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;ul&gt;
&lt;li&gt; ให้ &lt;code&gt;EmailSender&lt;/code&gt; มี Scope เป็น &lt;code&gt;ActivityScoped&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ActivityScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;inject &lt;code&gt;EmailSender&lt;/code&gt; ในทั้ง 3 Activities&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ThirdActivity&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;SecondActivity&lt;/span&gt;  &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทั้งนี้ทั้งนั้น ถึงแม้ว่าเราจะ inject มันได้ ทั้ง 3 ที่ แต่ instance ก็ยังคงเป็นคนละตัวกัน &lt;/p&gt;

&lt;p&gt;ทดสอบด้วยการ Print ออกมาใน onCreate ของแต่ละ Activity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"emailSender from ${this::class.java} $emailSender"&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลที่ได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-04 14:51:01.868 5198-5198/? I/System.out: emailSender from class MainActivity EmailSender@245bf98
2021-01-04 14:51:02.346 5198-5198/? I/System.out: emailSender from class SecondActivity EmailSender@50720c3
2021-01-04 14:51:02.675 5198-5198/? I/System.out: emailSender from class ThirdActivity EmailSender@2026848
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ลองเปลี่ยนให้ Scope เป็น &lt;code&gt;@Singleton&lt;/code&gt; แทน&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="nd"&gt;@ActivityScoped&lt;/span&gt;
&lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="nd"&gt;@Singleton&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลที่ได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-04 14:51:01.868 5198-5198/? I/System.out: emailSender from class MainActivity EmailSender@245bf98
2021-01-04 14:51:02.346 5198-5198/? I/System.out: emailSender from class SecondActivity EmailSender@245bf98
2021-01-04 14:51:02.675 5198-5198/? I/System.out: emailSender from class ThirdActivity EmailSender@245bf98
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ทีนี้เรามาลองอะไรเล่นๆดูบ้าง จากตัวอย่าง code ด้านบน ให้ scope เป็น &lt;code&gt;@ActivityRetainedScoped&lt;/code&gt; ดู&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ActivityRetainedScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลที่ได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-04 14:51:01.868 5198-5198/? I/System.out: emailSender from class MainActivity EmailSender@3ade714
2021-01-04 14:51:02.346 5198-5198/? I/System.out: emailSender from class SecondActivity EmailSender@5776b47
2021-01-04 14:51:02.675 5198-5198/? I/System.out: emailSender from class ThirdActivity EmailSender@8b35fe6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จะเห็นว่า Instance นั้นยังตงเป็นคนละตัวกัน เนื่องจากว่า เรามี &lt;code&gt;@AndroidEntryPoint&lt;/code&gt; อยู่สามที่นั่นทำให้ Hilt ทำการสร้าง Instance ของ emailSender แยกกัน&lt;/p&gt;

&lt;p&gt;ลองใช้ &lt;code&gt;@ActivityRetainedScoped&lt;/code&gt; เหมือนเดิม แต่เปลี่ยนให้มี &lt;code&gt;@AndroidEntryPoint&lt;/code&gt; เพียงที่เดียวบ้าง&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@ActivityRetainedScoped&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="p"&gt;){&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;msg&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;สร้าง ClassA และ ClassB โดย inject &lt;code&gt;emailSender&lt;/code&gt; ไปที่ constructor&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClassA&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"From $this EmailSender is $emailSender"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ClassB&lt;/span&gt; &lt;span class="nd"&gt;@Inject&lt;/span&gt; &lt;span class="k"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;init&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"From $this EmailSender is $emailSender"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Print ค่าใน Activity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="nd"&gt;@AndroidEntryPoint&lt;/span&gt;
&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainActivity&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;AppCompatActivity&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;emailSender&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;EmailSender&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;classA&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ClassA&lt;/span&gt;

    &lt;span class="nd"&gt;@Inject&lt;/span&gt;
    &lt;span class="k"&gt;lateinit&lt;/span&gt; &lt;span class="kd"&gt;var&lt;/span&gt; &lt;span class="py"&gt;classB&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;ClassB&lt;/span&gt;

    &lt;span class="k"&gt;override&lt;/span&gt; &lt;span class="k"&gt;fun&lt;/span&gt; &lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nc"&gt;Bundle&lt;/span&gt;&lt;span class="p"&gt;?)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;super&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;onCreate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;savedInstanceState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;setContentView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;R&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;main_activity&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"From $this EmailSender is $emailSender"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;ผลที่ได้&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;2021-01-05 10:33:21.296 13089-13089 From ClassA@5d9e5b2 EmailSender is EmailSender@b6f3903
2021-01-05 10:33:21.296 13089-13089 From ClassB@d0c6080 EmailSender is EmailSender@b6f3903
2021-01-05 10:33:21.362 13089-13089 From MainActivity@fa313f1  EmailSender is EmailSender@b6f3903
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;จบไปคร่าวๆ สำหรับเรื่อง Hiltเบื้องต้น หวังว่าจะนำไปใช้งานกันได้ไม่ยาก ส่วน Part หน้าจะมาพูดถึง JetPack Compose บ้าง ว่ามัน Revolutionize วิธีการเขียน UI ของ Android App เราอย่างไร &lt;/p&gt;

&lt;h3&gt;
  
  
  References:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dagger.dev/hilt/" rel="noopener noreferrer"&gt;Hilt documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://developer.android.com/training/dependency-injection/hilt-android" rel="noopener noreferrer"&gt;Dependency injection with Hilt&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://codingwithmitch.com/courses/hilt-dependency-injection/" rel="noopener noreferrer"&gt;Coding with Mitch - Hilt Dependency Injection&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>android</category>
      <category>kotlin</category>
      <category>hilt</category>
    </item>
  </channel>
</rss>
