<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>dev-seon</title>
    <link>https://seon-dev.tistory.com/</link>
    <description>seon-dev 님의 블로그 입니다.</description>
    <language>ko</language>
    <pubDate>Mon, 20 Jul 2026 00:16:03 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Seon Dev Notes</managingEditor>
    <image>
      <title>dev-seon</title>
      <url>https://tistory1.daumcdn.net/tistory/7280953/attach/d00bbee6f9d641daafc0ac042bfac1a0</url>
      <link>https://seon-dev.tistory.com</link>
    </image>
    <item>
      <title>자료구조 Stack, Queue, Dequeue</title>
      <link>https://seon-dev.tistory.com/35</link>
      <description>&lt;h2&gt;&lt;strong&gt;Stack(스택)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Stack은 삽입과 삭제 같은 쪽에서만 이루어지는 LIFO(Last In First Out)형식의 선형 자료구조이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-23 201801.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;468&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/KmGfR/dJMcaciaQRB/MIgdkOmDnQL0ENmKglnb7k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/KmGfR/dJMcaciaQRB/MIgdkOmDnQL0ENmKglnb7k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/KmGfR/dJMcaciaQRB/MIgdkOmDnQL0ENmKglnb7k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FKmGfR%2FdJMcaciaQRB%2FMIgdkOmDnQL0ENmKglnb7k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;979&quot; height=&quot;468&quot; data-filename=&quot;스크린샷 2026-03-23 201801.png&quot; data-origin-width=&quot;979&quot; data-origin-height=&quot;468&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;스택은 쌓는다는 뜻이다.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Stack 주요 용어&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;주요 용어&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;설명&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Top&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;삽입과 삭제가 일어나는 위치를 의미합니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Push&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;스택의 맨 위(top)에 데이터를 추가하는 연산입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;스택의 맨 위(top)에서 데이터를 삭제하고 반환하는 연산입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Peek&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;스택의 맨 위(top)에 있는 데이터를 제거하지 않고 반환하는 연산입니다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;&lt;strong&gt;예시&lt;/strong&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;stack = []

stack.append(10)
stack.append(20)
stack.append(30)

print(stack)  # [10, 20, 30]

print(stack.pop())  # 30
print(stack)        # [10, 20]&lt;/code&gt;&lt;/pre&gt;&lt;h2&gt;&lt;strong&gt;Queue(큐)&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;큐는 한쪽(rear)에서 삽입이 이루어지고, 다른 한쪽(front)에서 삭제가 이루어지는 FIFO(First In First Out) 형식의 선형 자료구조이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;스크린샷 2026-03-23 204226.png&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;381&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bstg7M/dJMcacP0sFq/miGK6Xztaczz7WQ9WmFLQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bstg7M/dJMcacP0sFq/miGK6Xztaczz7WQ9WmFLQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bstg7M/dJMcacP0sFq/miGK6Xztaczz7WQ9WmFLQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbstg7M%2FdJMcacP0sFq%2FmiGK6Xztaczz7WQ9WmFLQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1129&quot; height=&quot;381&quot; data-filename=&quot;스크린샷 2026-03-23 204226.png&quot; data-origin-width=&quot;1129&quot; data-origin-height=&quot;381&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;큐는 대기줄이라는 것이다.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Queue 주요 용어&lt;/strong&gt;&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;주요 용어&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;설명&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Enqueue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;큐의 맨 뒤(rear)에서 데이터를 추가하는 연산이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dequeue&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;큐의 맨 앞(front)에서 데이터를 꺼내는(삭제하는) 연산이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;rear&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;큐의 맨 뒤에 위치한 데이터를 가리키는 포인터이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;front&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;큐의 맨 앞에 위치한 데이터를 가리키는 포인터이다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;예시&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from collections import deque

queue = deque()

queue.append(10)
queue.append(20)
queue.append(30)

print(queue)  # deque([10, 20, 30])

queue.popleft()
print(queue)  # deque([20, 30])

queue.popleft()
print(queue)  # deque([30])&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Deque(덱)&lt;/h2&gt;
&lt;p&gt;Deque는 Stack과 Queue와 달리 양쪽 끝에서 삽입과 삭제가 가능한 자료구조를 의미한다.&lt;br&gt;그래서 Stack, Queue 연산을 모두 지원한다. &lt;/p&gt;
&lt;h2&gt;주요 용어&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;strong&gt;주요 용어&lt;/strong&gt;&lt;/th&gt;
&lt;th&gt;&lt;strong&gt;설명&lt;/strong&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;append(x)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;덱의 맨 뒤에 데이터를 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;appendleft(x)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;덱의 맨 앞에 데이터를 추가한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pop()&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;덱의 맨 뒤에서 데이터를 제거하고 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;popleft()&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;덱의 맨 앞에서 데이터를 제거하고 반환한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;예시&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-python&quot;&gt;from collections import deque

dq = deque()

dq.append(10)
dq.append(20)

dq.appendleft(5)

print(dq)  # deque([5, 10, 20])

dq.pop()
dq.popleft()

print(dq)  # deque([10])&lt;/code&gt;&lt;/pre&gt;</description>
      <category>자료구조</category>
      <category>deque</category>
      <category>Queue</category>
      <category>stack</category>
      <category>자료구조</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/35</guid>
      <comments>https://seon-dev.tistory.com/35#entry35comment</comments>
      <pubDate>Mon, 23 Mar 2026 23:42:48 +0900</pubDate>
    </item>
    <item>
      <title>DevOps Research - CI/CD</title>
      <link>https://seon-dev.tistory.com/34</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요 오늘은 &lt;b&gt;소프트웨어 배포 과정에서 매우 중요한 개념인 CI/CD&lt;/b&gt;에 대해 알아보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;소프트웨어 개발 과정에서 여러 개발자가 동시에 작업을 하게 되면 코드 충돌이 발생하거나 배포 과정에서 오류가 발생할 가능성이 높습니다. 또한 수동으로 빌드와 배포를 진행할 경우 시간이 오래 걸리고 실수가 발생할 가능성도 존재합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이러한 문제를 해결하기 위해 등장한 것이 &lt;b&gt;CI/CD&lt;/b&gt;이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CI란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CI(Continuous Integration)&lt;/b&gt; 는 여러 개발자가 작성한 코드를 하나의 저장소에 &lt;b&gt;지속적으로 통합&lt;/b&gt;하는 과정을 의미합니다.&lt;br /&gt;개발자가 코드를 저장소에 업로드하면 자동으로 빌드와 테스트가 실행되면서, 문제가 없는 경우에만 코드가 통합됩니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CD란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CD(Continuous Delivery / Continuous Deployment)&lt;/b&gt; 는 통합된 코드를 실제 운영 환경에 자동으로 배포하는 과정을 의미합니다.&lt;br /&gt;상황에 따라서 &lt;b&gt;지속적 제공(Continuous Delivery)&lt;/b&gt; 또는 &lt;b&gt;지속적 배포(Continuous Deployment)&lt;/b&gt; 라는 두 가지의 의미로 쓰입니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;지속적 제공 (Continuous Delivery)&lt;/b&gt;: CI 프로세스를 거친 코드가 신뢰할 수 있는 상태로 유지되면서 언제든 배포할 준비가 된 상태를 의미합니다. 마지막 배포 단계는 사람의 승인을 거칩니다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;지속적 배포 (Continuous Deployment)&lt;/b&gt;: 코드 수정 사항이 파이프라인을 통과하면 별도의 수동 개입 없이 실제 운영 환경까지 자동으로 배포되는 단계입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 CI/CD를 도입할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD를 도입하면 개발과 배포 과정에서 많은 장점들을 가질 수 있다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;빠른 배포가 가능하다&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드가 변경될 때마다 자동으로 빌드와 테스트, 배포 과정이 진행되기 때문에 새로운 기능이나 수정 사항을 빠르게 서비스에 반영할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;오류의 조기 발견&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코드가 통합될 때마다 자동 테스트가 실행되기 때문에 버그나 오류를 빠르게 발견하고 수정할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;개발 생산성 향상&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드와 테스트, 서버 배포와 같은 반복적인 작업이 자동화되면서 개발자는 이러한 작업을 직접 수행할 필요 없이 기능 개발에 더 집중할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;b&gt;안정적인 서비스 운영&lt;/b&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;자동화된 테스트와 배포 과정을 통해 사람이 직접 서버에 접속하여 배포할 때 발생할 수 있는 버전 오류나 파일 누락과 같은 실수를 줄일 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CI/CD 파이프라인&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD가 구축된 환경에서는 개발자가 코드를 병합하는 단계부터 서비스에 배포하는 단계까지 순차적으로 진행됩니다. 이러한 자동화된 배포 과정을 &lt;b&gt;CI/CD 파이프라인(Pipeline)&lt;/b&gt; 이라고 부릅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;CI/CD 파이프라인(Pipeline)흐름도&lt;/b&gt;&lt;/p&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;Developer &amp;rarr; Git Push
               &amp;darr;
             Build
               &amp;darr;
              Test
               &amp;darr;
             Deploy
               &amp;darr;
           Production&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발자가 코드를 저장소에 업로드하면 자동으로 빌드와 테스트가 진행됩니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드 단계: 소스 코드를 컴파일하고, 필요한 라이브러리를 다운로드하며, 애플리케이션을 패키징 합니다.&lt;/li&gt;
&lt;li&gt;테스트 단계: 유닛 테스트, 통합 테스트, 기능 테스트 등을 실행하여 코드의 품질을 검증합니다.&lt;/li&gt;
&lt;li&gt;배포 단계: 테스트가 통과된 코드를 스테이징 환경이나 프로덕션 환경에 배포합니다. 여기에는 Docker 이미지 생성 및 배포, Kubernetes 클러스터에 배포 등이 포함될 수 있습니다.&lt;/li&gt;
&lt;li&gt;모니터링 단계: 배포된 애플리케이션의 성능과 안정성을 모니터링하고, 로그 및 사용자 피드백을 수집합니다. 이를 통해 발생한 문제를 빠르게 해결할 수 있습니다.&lt;br /&gt;CI/CD 파이프라인에서는 이러한 단계를 거치면서 빌드, 테스트, 배포 과정이 자동으로 수행됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;CI/CD 개발도구&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD 환경에서는 자동화된 빌드와 테스트, 배포를 위해 다양한 도구들이 사용됩니다.&lt;br /&gt;대표적인 CI/CD 도구는 아래와 같은 도구들이 있습니다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Jenkins&lt;/li&gt;
&lt;li&gt;Github Actions&lt;/li&gt;
&lt;li&gt;GitLab CI/CD&lt;br /&gt;또한 컨테이너 기반 배포 환경에서는 아래와 같은 기술들이 함께 사용됩니다.&lt;/li&gt;
&lt;li&gt;Docker&lt;/li&gt;
&lt;li&gt;Kubernetes&lt;br /&gt;이러한 도구들을 활용하면 빌드, 테스트, 배포 과정을 자동화하여 보다 효율적인 개발 환경을 구축할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;GitHub Actions를 활용한 CD 자동화 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음은 GitHub Actions 를 활용하여 Android 애플리케이션을 자동으로 빌드하고 배포하는 CI/CD 파이프라인 예시입니다.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. Workflow 실행 조건&lt;/h3&gt;
&lt;pre class=&quot;dts&quot;&gt;&lt;code&gt;on:
  push:
    branches: [ &quot;master&quot; ]&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2. 실행 환경 설정&lt;/h3&gt;
&lt;pre class=&quot;yaml&quot;&gt;&lt;code&gt;- name: Setup JDK 17
  uses: actions/setup-java@v4

- name: Setup Android SDK
  uses: android-actions/setup-android@v3&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. Gradle 캐싱&lt;/h3&gt;
&lt;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;- name: Cache Gradle packages&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;4. 앱 빌드&lt;/h3&gt;
&lt;pre class=&quot;applescript&quot;&gt;&lt;code&gt;- name: Assemble Release Bundle
  run: ./gradlew clean bundleRelease&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;5. 앱 서명&lt;/h3&gt;
&lt;pre class=&quot;excel&quot;&gt;&lt;code&gt;- name: Sign Release
  uses: r0adkll/sign-android-release@v1&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;6. Google Play 배포&lt;/h3&gt;
&lt;pre class=&quot;delphi&quot;&gt;&lt;code&gt;- name: Deploy to production
  uses: r0adkll/upload-google-play@v1&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;7. 배포 결과 알림&lt;/h3&gt;
&lt;pre class=&quot;apache&quot;&gt;&lt;code&gt;# 성공 시
if: ${{ success() }}

# 실패 시
if: ${{ failure() }}&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;마무리&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CI/CD는 소프트웨어 개발 과정에서 &lt;b&gt;코드 통합, 테스트, 배포 과정을 자동화하여 빠르고 안정적인 서비스 제공을 가능하게 하는 DevOps의 핵심 기술&lt;/b&gt; 입니다.&lt;/p&gt;</description>
      <category>CD</category>
      <category>CI</category>
      <category>DevOps Research</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/34</guid>
      <comments>https://seon-dev.tistory.com/34#entry34comment</comments>
      <pubDate>Mon, 16 Mar 2026 10:54:37 +0900</pubDate>
    </item>
    <item>
      <title>Android Kotlin 변수와 자료형</title>
      <link>https://seon-dev.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요 오늘은 Kotlin에서 사용하는 변수와 자료형에 대해서 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;변수&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #001d35; text-align: start;&quot;&gt;프로그래밍에서 데이터를 저장하고 관리하는 데 사용되는 이름이 지정된 메모리 공간이다.&lt;/span&gt;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Kotlin의 변수 선언&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;var: 수정 가능한(mutable) 변수&lt;/li&gt;
&lt;li&gt;val: 불변(immutable) 변수&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;var name = &quot;선우&quot;   // 변경 가능
val age = 18        // 한번 초기화 후 변경 불가&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;상황에 따라 불변성을 유지하는 val을 우선 사용하길 권장한다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 자료형&lt;/h2&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;자료형&lt;/th&gt;
&lt;th&gt;예시 값&lt;/th&gt;
&lt;th&gt;설명&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Int&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;12&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;정수형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Double&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;3.14&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;소수 점 포함 숫자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Float&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2.71f&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;단정밀도 소수점 숫자&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Boolean&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;true&lt;/code&gt; / &lt;code&gt;false&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;논리형&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;String&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;hello&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;문자열&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;코틀린은 변수 선언 시 타입을 생략할 수 있으며, 값에 따라 자동 추론된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;val name: String = &quot;선우&quot;
val level: Int = 5
val pi: Double = 3.14159&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;자료형 변환(Type Casting)&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코틀린에서는 명시적 변환이 필요하다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;val num = 10
val doubleNum = num.toDouble() // 10 &amp;rarr; 10.0&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;toInt(), toDouble(), toFloat(), toString() 등 다양한 함수들이 있음&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;실습 예제&lt;/h2&gt;
&lt;pre class=&quot;stylus&quot;&gt;&lt;code&gt;var a = 10
var b = 5
val sum = a + b
println(&quot;합계는 $sum 입니다.&quot;)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코틀린에서는 ${변수} 혹은 $변수를 문자열에 바로 넣을 수 있다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;val username = &quot;선우&quot;
val point = 80

println(&quot;안녕하세요, $username님! 점수는 $point점입니다.&quot;)&lt;/code&gt;&lt;/pre&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>변수</category>
      <category>자료형</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/33</guid>
      <comments>https://seon-dev.tistory.com/33#entry33comment</comments>
      <pubDate>Tue, 17 Jun 2025 17:12:07 +0900</pubDate>
    </item>
    <item>
      <title>Android XML Layout</title>
      <link>https://seon-dev.tistory.com/32</link>
      <description>&lt;p&gt;오늘은 안드로이드 앱을 만들 때 가장 먼저 구성하게 되는 것이 바로 화면, 즉 UI입니다. 그리고 이 UI를 만드는 대표적인 방법이 XML Layout에 대해 알아보겠다!&lt;/p&gt;
&lt;h2&gt;XML Layout&lt;/h2&gt;
&lt;p&gt;XML Layout은 안드로이드에서 앱의 화면에 보여질 UI 요소들을 배치하고 구성하는 파일이다.&lt;br&gt;버튼, 텍스트, 이미지 등 뷰(View)를 어떤 위치에 어떤 스타일로 보여줄지를 미리 선언적으로 작성할 수 있다.&lt;/p&gt;
&lt;h2&gt;기본 구조&lt;/h2&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;LinearLayout
    xmlns:android=&amp;quot;http://schemas.android.com/apk/res/android&amp;quot;
    android:layout_width=&amp;quot;match_parent&amp;quot;
    android:layout_height=&amp;quot;match_parent&amp;quot;
    android:orientation=&amp;quot;vertical&amp;quot;&amp;gt;

    &amp;lt;TextView
        android:layout_width=&amp;quot;wrap_content&amp;quot;
        android:layout_height=&amp;quot;wrap_content&amp;quot;
        android:text=&amp;quot;안녕하세요!&amp;quot; /&amp;gt;

    &amp;lt;Button
        android:layout_width=&amp;quot;wrap_content&amp;quot;
        android:layout_height=&amp;quot;wrap_content&amp;quot;
        android:text=&amp;quot;확인&amp;quot; /&amp;gt;
&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;최상단 태그는 보통 ViewGroup (LinearLayout, ConstraintLayout 등)&lt;/li&gt;
&lt;li&gt;android:layout_width, android:layout_height는 모든 View에 필수이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;layout_width / layout_height 속성&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;match_parent: 부모 크기에 맞게 채움&lt;/li&gt;
&lt;li&gt;wrap_content: 내용 크기만큼만 공간 차지&lt;/li&gt;
&lt;li&gt;dp: 고정 크기 지정 (Density-independent Pixel)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;주요 layout 종류&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;LinearLayout&lt;/code&gt;&lt;br&gt;뷰들을 수직 또는 수평 방향으로 일렬 배치&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;android:orientation=&amp;quot;vertical&amp;quot; 또는 &amp;quot;horizontal&amp;quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;LinearLayout android:orientation=&amp;quot;vertical&amp;quot;&amp;gt; 
  &amp;lt;TextView ... /&amp;gt; 
  &amp;lt;Button ... /&amp;gt; 
&amp;lt;/LinearLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imagegridblock&quot;&gt;
  &lt;div class=&quot;image-container&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ldkji/btsOtn7zmVs/q62YcrFBnYZe57pG1j1OTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ldkji/btsOtn7zmVs/q62YcrFBnYZe57pG1j1OTK/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;844&quot; data-origin-height=&quot;732&quot; data-filename=&quot;스크린샷 2025-06-09 175240.png&quot; width=&quot;221&quot; height=&quot;192&quot; style=&quot;width: 49.3582%; margin-right: 10px;&quot; data-widthpercent=&quot;49.94&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ldkji/btsOtn7zmVs/q62YcrFBnYZe57pG1j1OTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fldkji%2FbtsOtn7zmVs%2Fq62YcrFBnYZe57pG1j1OTK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;844&quot; height=&quot;732&quot;/&gt;&lt;/span&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c8zoFk/btsOtr9VHcE/FNOXd9QWUhT5drMp5hAPx1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c8zoFk/btsOtr9VHcE/FNOXd9QWUhT5drMp5hAPx1/img.png&quot; data-is-animation=&quot;false&quot; data-origin-width=&quot;853&quot; data-origin-height=&quot;738&quot; data-filename=&quot;스크린샷 2025-06-09 175418.png&quot; width=&quot;221&quot; height=&quot;191&quot; style=&quot;width: 49.479%;&quot; data-widthpercent=&quot;50.06&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c8zoFk/btsOtr9VHcE/FNOXd9QWUhT5drMp5hAPx1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc8zoFk%2FbtsOtr9VHcE%2FFNOXd9QWUhT5drMp5hAPx1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;853&quot; height=&quot;738&quot;/&gt;&lt;/span&gt;&lt;/div&gt;
  &lt;figcaption&gt;이렇게&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;RelativeLayout&lt;/code&gt;&lt;br&gt;뷰들을 서로의 위치 기준으로 배치 (예: 다른 뷰 아래, 오른쪽 등)&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;RelativeLayout&amp;gt;
    &amp;lt;TextView android:id=&amp;quot;@+id/title&amp;quot; ... /&amp;gt;
    &amp;lt;Button android:layout_below=&amp;quot;@id/title&amp;quot; ... /&amp;gt;
&amp;lt;/RelativeLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1301&quot; data-origin-height=&quot;798&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct0R9B/btsOsz8EyIc/Hg8PaxaxFcRg2HmFDtuJq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct0R9B/btsOsz8EyIc/Hg8PaxaxFcRg2HmFDtuJq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct0R9B/btsOsz8EyIc/Hg8PaxaxFcRg2HmFDtuJq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct0R9B%2FbtsOsz8EyIc%2FHg8PaxaxFcRg2HmFDtuJq0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1301&quot; height=&quot;798&quot; data-origin-width=&quot;1301&quot; data-origin-height=&quot;798&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ConstraintLayout&lt;/code&gt;&lt;br&gt;뷰에 &lt;strong&gt;제약 조건(Constraint)&lt;/strong&gt; 을 주어 유연하고 효율적인 배치 가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;복잡한 레이아웃도 중첩 없이 한 번에 구성 가능&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FwMjw/btsOtsHJCj7/BPoBSOYIhhIb5qzThXN5vk/img.png&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;androidx.constraintlayout.widget.ConstraintLayout&amp;gt;
  &amp;lt;TextView app:layout_constraintTop_toTopOf=&amp;quot;parent&amp;quot; app:layout_constraintStart_toStartOf=&amp;quot;parent&amp;quot; /&amp;gt; &amp;lt;/androidx.constraintlayout.widget.ConstraintLayout&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;XML Layout 사용 시 팁&lt;/h2&gt;
&lt;p&gt;미리보기 기능(Preview)을 활용하면 실제 UI 형태를 즉시 확인 가능&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tools: 속성을 이용하면 디자인 전용 더미 데이터를 넣을 수 있음&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-xml&quot;&gt;&amp;lt;TextView
    android:layout_width=&amp;quot;wrap_content&amp;quot;
    android:layout_height=&amp;quot;wrap_content&amp;quot;
    tools:text=&amp;quot;디자인 전용 텍스트&amp;quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;RelativeLayout은 간단한 화면에서는 유용하지만, 복잡한 레이아웃에서는 중첩이 많아져 성능에 영향을 줄 수 있다.&lt;/li&gt;
&lt;li&gt;ConstraintLayout은 그 단점을 보완하고, 더 복잡하고 유연한 UI를 한 단계로 처리할 수 있게 설계된 최신 레이아웃이다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>layout</category>
      <category>xml</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/32</guid>
      <comments>https://seon-dev.tistory.com/32#entry32comment</comments>
      <pubDate>Mon, 9 Jun 2025 18:14:36 +0900</pubDate>
    </item>
    <item>
      <title>2025 AI Expo Korea 회고</title>
      <link>https://seon-dev.tistory.com/30</link>
      <description>&lt;p&gt;안녕하세요! 오늘은 2025년 AI Expo Korea에 참가하고 다른 기업이나 학교의 부스들을 구경한 회고를 써보겠습니다!&lt;/p&gt;
&lt;h2&gt;어떻게 갔을까?&lt;/h2&gt;
&lt;p&gt;사실 나는 AI Expo Korea라는 행사 자체도 모르고 있었다. 그런데 선배가 곰스로 가는거 어떠냐고 하면서 신청하셨다고 해서 AI Expo를 가게되었다, 구성원은 3학년 선배 1명, 그리고 나를 포함한 2학년 4명으로 총 5명이었다. 5월 14일 부터 16일까지 진행이 되는거라서 하루 전날인 13일에 서울 코엑스에 가서 세팅을 진행했다.&lt;/p&gt;
&lt;h2&gt;AI Expo 행사장!&lt;/h2&gt;
&lt;p&gt;행사장에 도착하자마자 가장 먼저 느낀 건 &lt;strong&gt;진짜 규모가 크다&lt;/strong&gt;였다. 코엑스 전시관을 가득 메운 수많은 기업, 학교, 기관들이 각각의 기술과 서비스를 소개하려고 준비 중이었고 엄청 신기한 것들이 많이 보였다.&lt;/p&gt;
&lt;p&gt;부스들은 대기업의 부스부터 시작해서, 스타트업, 대학생분들의 프로젝트까지 전시되어 있었고 마이스터고만 쭉 있는 쪽으로 해서 마이스터고 부스들이 자리하고 있었다. &lt;/p&gt;
&lt;h2&gt;우리 부스&lt;/h2&gt;
&lt;p&gt;우리가 준비한 부스는 GOMS라는 이름의 프로젝트였다.&lt;br&gt;GOMS는 GSM Outing Management Solution의 약자로, &lt;strong&gt;광주소프트웨어마이스터고(GSM)&lt;/strong&gt; 에서 학생들의 외출을 보다 효율적으로 관리하기 위한 앱이다.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;핵심 기능은 QR 기반 외출 시스템이다.&lt;/strong&gt;&lt;br&gt;학생이 외출을 하겠다고 앱을 켜서 QR을 찍으려고 하면, 학생회들이 QR을 생성해서 학생에게 보여주고 외출을 한다.&lt;br&gt;이 과정을 통해 학생회는 누가 언제 외출했고, 지금 외출 중인 사람이 누구인지를 실시간으로 확인할 수 있고, 정해진 시간까지 들어오지 않으면 패널티를 부여한다. 그리고 핸드폰이 배터리가 없어서 QR을 못 찍거나 카메라가 안 좋아서 못 찍는 학생을 강제 외출해주는 기능도 있다.&lt;/p&gt;
&lt;p&gt;실제로 관람객들에게 시연을 보여줄 때,&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;“학교에서 이런 걸 직접 만든다고요?”&lt;/li&gt;
&lt;li&gt;“QR코드로 외출을 관리한다고요?”&lt;br&gt;라는 반응이 많았고, 특히 학교 내 실사용 중이라는 점에 많은 사람들이 놀라워했다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;인상 깊었던 부스&lt;/h2&gt;
&lt;p&gt;인상 깊었던 부스는 NVIDIA의 파트너 부스들에서 엄청나게 화려한 것들을 본 것이다. 특히 10억원 상당의 어떤 기계를 설명한 것이 인상깊었다.&lt;br&gt;그리고 다른 인상 깊었던 부스로는 같은 마이스터고 부스들이 인상깊었다.&lt;br&gt;그 중에서 기억에 남는건 결혼 할 때 청첩장을 만들어주고 꾸며주고 그걸 다른 사람들한테도 공유할 수 있고 돈도 받을 수 있는 그 프로젝트가 가장 기억에 남는다.&lt;/p&gt;
&lt;h2&gt;느낀점&lt;/h2&gt;
&lt;p&gt;이번에 부스를 하게 되어서 AI Expo Korea를 처음 왔는데 여기서 관람객 분들한테 GOMS를 이런식으로 해보면 어떨지에 대해서 듣기도 하면서 도움이 많이 되는 시간이었고 다른 부스들도 AI를 활용하고 AI를 보여주면서 굉장히 신기하고도 소중했떤 시간이었던 것 같다.&lt;/p&gt;</description>
      <category>회고록</category>
      <category>ai expo korea</category>
      <category>회고록</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/30</guid>
      <comments>https://seon-dev.tistory.com/30#entry30comment</comments>
      <pubDate>Sat, 31 May 2025 20:11:27 +0900</pubDate>
    </item>
    <item>
      <title>Android TextField에서 사용하는 VisualTransformation</title>
      <link>https://seon-dev.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요. 오늘은 Jetpack Compose에서 텍스트 입력 필드를 더욱 유연하고 효율적으로 다룰 수 있도록 도와주는 VisualTransformation에 대해 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;VisualTransformation&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VisualTransformation은 Jetpack Compose에서 텍스트의 표시 방식을 변형하는 데 사용되는 도구이다. 사용자로부터 텍스트 입력을 받는 TextField와 같은 컴포넌트에서 텍스트가 화면에 어떻게 보일지를 조정할 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;왜 사용해야할까?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거의 텍스트 필드는 사용자가 직접 입력한 데이터를 그대로 화면에 보여준다. 하지만 입력되는 데이터는 때로 특정 형식을 필요로 한다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;예를 들어, 비밀번호는 *로 보이게 하거나, 전화번호는 010-1234-5678과 같은 형식을 보여주고 싶을 때. 이럴 때 VisualTransformation을 사용하면 입력된 텍스트를 화면에 표시할 때만 변형할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본 예시&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가장 기본적인 형태는 &lt;code&gt;BasicTextField&lt;/code&gt;나 &lt;code&gt;TextField&lt;/code&gt;에 &lt;code&gt;visualTransformation&lt;/code&gt; 파라미터를 설정해주는 방식입니다.&lt;/p&gt;
&lt;pre class=&quot;jboss-cli&quot;&gt;&lt;code&gt;TextField(
    value = value,
    onValueChange = { value = it },
    visualTransformation = PasswordVisualTransformation()
)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;화면에는 &lt;b&gt;****&lt;/b&gt;으로 보이지만, 실제 값은 그대로 유지된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;또 다른 예시&lt;/h2&gt;
&lt;pre class=&quot;xl&quot;&gt;&lt;code&gt;val phoneVisualTransformation = VisualTransformation { text -&amp;gt;
    val trimmed = text.text.take(11)
    val formatted = when (trimmed.length) {
        in 0..3 -&amp;gt; trimmed
        in 4..7 -&amp;gt; &quot;${trimmed.substring(0,3)}-${trimmed.substring(3)}&quot;
        else -&amp;gt; &quot;${trimmed.substring(0,3)}-${trimmed.substring(3,7)}-${trimmed.substring(7)}&quot;
    }
    TransformedText(AnnotatedString(formatted), OffsetMapping.Identity)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;출력&lt;/p&gt;
&lt;table data-ke-align=&quot;alignLeft&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;입력값 (&lt;code&gt;text.text&lt;/code&gt;)&lt;/th&gt;
&lt;th&gt;trimmed&lt;/th&gt;
&lt;th&gt;formatted&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;0&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;0&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;0&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;0101&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;0101&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;010-1&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;0101234&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;0101234&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;010-1234&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;&quot;01012345678&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;01012345678&quot;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&quot;010-1234-5678&quot;&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OffsetMapping&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OffsetMapping은 예를 들어 &quot;0101&quot;을 입력했을 때&lt;/p&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;입력값 길이는 4 (0, 1, 0, 1)

보이는 값은 &quot;010-1&quot; (길이 5)&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때 커서를 정확히 매핑하려면, 입력값과 보이는 값의 인덱스를 매핑해주는 도구가 필요하다. 그게 OffsetMapping이다.&lt;/p&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;interface OffsetMapping {
    fun originalToTransformed(offset: Int): Int
    fun transformedToOriginal(offset: Int): Int
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>visualtransformation</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/29</guid>
      <comments>https://seon-dev.tistory.com/29#entry29comment</comments>
      <pubDate>Wed, 7 May 2025 18:04:37 +0900</pubDate>
    </item>
    <item>
      <title>Android Module &amp;amp; Multi-Module</title>
      <link>https://seon-dev.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요 오늘은 Android 개발에서 프로젝트를 체계적으로 관리하기 위해 꼭 알아야 할 개념, Module과 Multi-Module에 대해 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Module&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Module은 하나의 독립적인 코드 단위이다.&lt;br /&gt;모듈은 독자적인 &lt;code&gt;build.gradle.kts&lt;/code&gt; 파일을 가지고 있고, 독립적으로 빌드하거나 테스트할 수 있다.&lt;/p&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Application Module: 최종 앱 실행용 모듈 (com.android.application)&lt;/li&gt;
&lt;li&gt;Library Module: 코드나 리소스를 제공하는 모듈 (com.android.library)&lt;/li&gt;
&lt;li&gt;Java/Kotlin Library Module: 안드로이드 의존성이 없는 Java 또는 Kotlin 기반 모듈&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Module 만드는 법&lt;/h2&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;870&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7LXj6/btsNDIqQxNU/8Vvm5EjaCRO3pBbyZHeNb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7LXj6/btsNDIqQxNU/8Vvm5EjaCRO3pBbyZHeNb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7LXj6/btsNDIqQxNU/8Vvm5EjaCRO3pBbyZHeNb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7LXj6%2FbtsNDIqQxNU%2F8Vvm5EjaCRO3pBbyZHeNb1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;265&quot; height=&quot;342&quot; data-origin-width=&quot;674&quot; data-origin-height=&quot;870&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;new -&amp;gt; module을 누르고&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;991&quot; data-origin-height=&quot;763&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bPxnJT/btsNDa9bvqY/NUqqKfRsKFQmoh8dmukAiK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bPxnJT/btsNDa9bvqY/NUqqKfRsKFQmoh8dmukAiK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bPxnJT/btsNDa9bvqY/NUqqKfRsKFQmoh8dmukAiK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbPxnJT%2FbtsNDa9bvqY%2FNUqqKfRsKFQmoh8dmukAiK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;991&quot; height=&quot;763&quot; data-origin-width=&quot;991&quot; data-origin-height=&quot;763&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Templates에서 하나를 고른 후 Finish를 누르면 끝난다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Multi-Module&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Multi-Module은 프로젝트를 여러 개의 작은 모듈로 나누어 구성하는 방식이다. 대규모 프로젝트에서는 여러 모듈로 나누어 관리하는 것이 빌드 속도와 유지보수 측면에서 매우 유리하다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Multi-Module의 장점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;빌드 속도 최적화: 필요한 모듈만 다시 빌드할 수 있어서 전체 빌드 시간을 줄일 수 있다.&lt;/li&gt;
&lt;li&gt;유지보수성 향상: 기능별로 모듈을 분리하여 수정할 때 다른 부분에 미치는 영향을 최소화한다.&lt;/li&gt;
&lt;li&gt;협업 효율성: 여러 명의 개발자가 동시에 작업할 수 있어 협업 하기 더 편하다.&lt;/li&gt;
&lt;li&gt;코드 재사용성: 여러 프로젝트에서 공통으로 사용할 수 있는 코드나 기능을 모듈화하면 재사용성이 높아진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Multi-Module 단점&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;초기 설정 복잡도: 프로젝트를 여러 모듈로 나누는 초기 설정이 복잡하고 시간이 걸릴 수 있다.&lt;/li&gt;
&lt;li&gt;모듈 간 의존성 관리: 모듈 간 의존성을 잘못 설정하면 순환 의존성 문제가 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;빌드 시간 증가: 의존성이 많아지면 전체 빌드 시간이 길어질 수 있으며, 빌드 최적화가 필요하다.&lt;/li&gt;
&lt;li&gt;디버깅 어려움: 여러 모듈 간의 상호작용에서 문제가 발생하면 디버깅이 더 복잡해질 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예시 구조&lt;/h2&gt;
&lt;pre class=&quot;arduino&quot;&gt;&lt;code&gt;```
project-root/
│
├── app/                  // 최종 Application 모듈
│
├── core/                 // 공통 기능 모듈
│   ├── core-ui/          // 공통 UI 컴포넌트
│   ├── core-network/     // 공통 네트워크 처리
│   ├── core-model/       // 공통 데이터 모델
│
├── feature/              // 기능별 모듈
│   ├── feature-login/    // 로그인 화면
│   ├── feature-home/     // 홈 화면
│
│
└── build.gradle (root)
```&lt;/code&gt;&lt;/pre&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>clickable</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/28</guid>
      <comments>https://seon-dev.tistory.com/28#entry28comment</comments>
      <pubDate>Tue, 29 Apr 2025 13:46:49 +0900</pubDate>
    </item>
    <item>
      <title>Android clickable</title>
      <link>https://seon-dev.tistory.com/27</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 Jetpack Compose에서 UI에 인터랙션을 부여할 때 자주 사용되는 도구, Modifier.clickable에 대해 알아보겠습니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;clickable&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;clickable&lt;/code&gt;은 Jetpack Compose에서 UI 요소를 클릭할 수 있도록 만들어주는 Modifier이다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Modifier.clickable {
    // 클릭되었을 때 실행할 코드
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이렇게 Modifier에 clickable을 붙이면, 해당 요소는 터치 이벤트를 받을 수 있는 상태가 되며, 사용자가 해당 요소를 누르면 onClick 람다가 호출된다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;기본 동작과 특징&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;Ripple 효과 제공&lt;br /&gt;머터리얼 디자인의 터치 피드백인 Ripple 효과가 기본으로 적용된다.&lt;/li&gt;
&lt;li&gt;접근성 자동 지원&lt;br /&gt;클릭 가능한 요소로 인식되기 때문에, 스크린 리더 등 접근성 기능과 자연스럽게 통합된다.&lt;/li&gt;
&lt;li&gt;활성화 여부 제어 가능&lt;br /&gt;&lt;code&gt;enabled = false&lt;/code&gt;로 비활성화하면 클릭이 되지 않고, 시각적 피드백도 사라진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Ripple 효과&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Ripple은 사용자가 터치한 위치에서 퍼져 나가는 애니메이션 효과이다. 머터리얼 디자인에서 기본적으로 사용하는 피드백 방식으로, 사용자가 &quot;내가 눌렀다&quot;는 것을 직관적으로 인지할 수 있게 해준다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Modifier.clickable(
    indication = rememberRipple(), // 기본 ripple
    onClick = { /* ... */ }
)&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;OnClick&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clickable의 가장 핵심 기능은 바로 onClick이다.&lt;/p&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;Modifier.clickable {
    Log.d(&quot;Click&quot;, &quot;클릭됨&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;사용자가 UI 요소를 클릭했을 때 호출되는 람다 함수이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 안에 네비게이션, 상태 변경, Toast 출력 등 원하는 동작을 자유롭게 넣을 수 있다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;combinedClickable&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;clickable이 단순 클릭만 처리하는 반면, combinedClickable은 롱클릭이나 더블클릭 등 복합적인 제스처를 처리할 수 있게 해준다.&lt;/p&gt;
&lt;pre class=&quot;stata&quot;&gt;&lt;code&gt;Modifier.combinedClickable(
    onClick = { Log.d(&quot;Click&quot;, &quot;일반 클릭&quot;) },
    onLongClick = { Log.d(&quot;Click&quot;, &quot;롱 클릭&quot;) },
    onDoubleClick = { Log.d(&quot;Click&quot;, &quot;더블 클릭&quot;) } // 선택사항
)&lt;/code&gt;&lt;/pre&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;특징&lt;/h3&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;하나의 Modifier로 여러 제스처를 처리할 수 있다&lt;/li&gt;
&lt;li&gt;사용자 인터랙션이 많은 UI에 적합하다&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>clickable</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/27</guid>
      <comments>https://seon-dev.tistory.com/27#entry27comment</comments>
      <pubDate>Fri, 25 Apr 2025 23:14:18 +0900</pubDate>
    </item>
    <item>
      <title>Android build-logic</title>
      <link>https://seon-dev.tistory.com/26</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 안드로이드 프로젝트의 빌드 관리를 더 효율적으로 만들어주는 핵심 도구, build-logic에 대해 알아보겠습니다&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;build-logic이란?&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;공통된 빌드 설정을 한 곳에 모아 플러그인 형태로 정의하고,&lt;br /&gt;각 모듈에서 간단하게 재사용할 수 있도록 만든 구조&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;build-logic을 사용하는 이유&lt;/h2&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;반복되는 설정을 제거해 코드 간결하게 해준다.&lt;/li&gt;
&lt;li&gt;설정 일관성있게 유지해서 버그 감소시킨다&lt;/li&gt;
&lt;li&gt;모듈 추가 시 빠르고 쉽게 설정 가능하다.&lt;/li&gt;
&lt;li&gt;빌드 스크립트 가독성 향상된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;프로젝트 구조 예시&lt;/h2&gt;
&lt;pre class=&quot;reasonml&quot;&gt;&lt;code&gt;root/
├── build-logic/
│   └── convention/
│       ├── build.gradle.kts
│       └── src/main/java/com/school_of_company/convention/
│           ├── AndroidApplicationConventionPlugin.kt
│           ├── AndroidComposeConventionPlugin.kt
│           ├── AndroidCoreConventionPlugin.kt
│           ├── AndroidFeatureConventionPlugin.kt
│           ├── AndroidHiltConventionPlugin.kt
│           ├── AndroidLintConventionPlugin.kt
│           └── JvmLibraryConventionPlugin.kt
├── app/
├── core/
├── features/
└── settings.gradle.kts&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Convention Plugin 적용 방식&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;code&gt;settings.gradle.kts&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;pluginManagement {
    includeBuild(&quot;build-logic&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;모듈에서 사용&lt;/p&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;```
// 예: feature 모듈의 build.gradle.kts
plugins {
  id(&quot;com.school_of_company.convention.android.feature&quot;)
  id(&quot;com.school_of_company.convention.android.compose&quot;)
  id(&quot;com.school_of_company.convention.android.hilt&quot;)
}
```&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;주요 플러그인 설명&lt;/h2&gt;
&lt;pre class=&quot;css&quot;&gt;&lt;code&gt;AndroidApplicationConventionPlugin
com.android.application 플러그인 적용

앱 모듈에 필요한 compileSdk, defaultConfig, viewBinding 등 기본 설정 포함&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;AndroidComposeConventionPlugin
Jetpack Compose 관련 설정 일괄 적용&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;armasm&quot;&gt;&lt;code&gt;AndroidFeatureConventionPlugin
기능(feature) 모듈을 위한 설정

보통 android-library, viewBinding 등 적용​

composeOptions {
    kotlinCompilerExtensionVersion = &quot;1.4.3&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;AndroidCoreConventionPlugin
공통 설정: Kotlin, Java version, warning 설정 등

모든 모듈에 적용 가능한 기본 설정들 포함&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;AndroidHiltConventionPlugin
DI 프레임워크 Hilt 설정 자동화

Hilt 플러그인 적용, 의존성 추가, kapt 설정 포함&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;isbl&quot;&gt;&lt;code&gt;dependencies {
    implementation(&quot;com.google.dagger:hilt-android:2.48&quot;)
    kapt(&quot;com.google.dagger:hilt-compiler:2.48&quot;)
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;properties&quot;&gt;&lt;code&gt;AndroidLintConventionPlugin  
Lint 설정 일괄 적용

빌드 품질 유지 및 자동 점검 목적&lt;/code&gt;&lt;/pre&gt;
&lt;pre class=&quot;mipsasm&quot;&gt;&lt;code&gt;JvmLibraryConventionPlugin
순수 Kotlin(JVM) 라이브러리 모듈용

Java 버전 설정, kotlin(&quot;jvm&quot;) 플러그인 등 적용&lt;/code&gt;&lt;/pre&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>build-logic</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/26</guid>
      <comments>https://seon-dev.tistory.com/26#entry26comment</comments>
      <pubDate>Mon, 14 Apr 2025 21:08:36 +0900</pubDate>
    </item>
    <item>
      <title>Android Okhttp</title>
      <link>https://seon-dev.tistory.com/25</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은 Android 앱 개발 시 자주 쓰이는 HTTP 통신 라이브러리, 바로 &lt;b&gt;OkHttp&lt;/b&gt;에 대해 정리해보려 합니다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Okhttp&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OkHttp는 Square에서 만든 HTTP 클라이언트 라이브러리이다. Retrofit도 내부적으로 OkHttp를 사용하고 있을 정도로 핵심적인 라이브러리이다.&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;Okhttp의 장점&lt;/h2&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;간편한 사용법.&lt;br /&gt;OkHttp는 복잡한 설정 없이도 바로 HTTP 요청을 보낼 수 있다.&lt;/li&gt;
&lt;li&gt;비동기 요청 지원.&lt;br /&gt;기본적으로 비동기 방식인 enqueue()를 제공하기 때문에 네트워크 요청으로 인해 UI가 멈추는 문제를 방지할 수 있다.&lt;/li&gt;
&lt;li&gt;인터셉터를 통한 요청/응답 제어.&lt;br /&gt;인터셉터를 활용하면 요청 전에 헤더를 추가하거나 응답 후 공통 처리를 하는 등 전처리/후처리를 자유롭게 설정할 수 있다.&lt;/li&gt;
&lt;li&gt;로깅과 디버깅 용이하다.&lt;br /&gt;HttpLoggingInterceptor를 추가하면 요청 URL, 응답 코드, 응답 body 등을 로그로 쉽게 확인할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;예제&lt;/h2&gt;
&lt;pre class=&quot;kotlin&quot;&gt;&lt;code&gt;val client = OkHttpClient()

val request = Request.Builder()
    .url(&quot;https://jsonplaceholder.typicode.com/posts/1&quot;)
    .build()

client.newCall(request).enqueue(object : Callback {
    override fun onFailure(call: Call, e: IOException) {
        Log.e(&quot;OkHttp&quot;, &quot;네트워크 요청 실패&quot;, e)
    }

    override fun onResponse(call: Call, response: Response) {
        if (response.isSuccessful) {
            val responseData = response.body?.string()
            Log.d(&quot;OkHttp&quot;, &quot;응답 내용: $responseData&quot;)
        } else {
            Log.e(&quot;OkHttp&quot;, &quot;응답 실패: ${response.code}&quot;)
        }
    }
})&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;OkHttpClient()로 클라이언트를 생성하고,&lt;/li&gt;
&lt;li&gt;Request.Builder()로 요청을 구성하고,&lt;/li&gt;
&lt;li&gt;enqueue()를 통해 비동기로 서버에 요청을 보낸다.&lt;/li&gt;
&lt;li&gt;결과는 onResponse()에서 확인할 수 있고, 실패 시 onFailure()에서 예외를 처리한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre id=&quot;code_1744040525880&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;val logging = HttpLoggingInterceptor().apply {
    level = HttpLoggingInterceptor.Level.BODY
}

val client = OkHttpClient.Builder()
    .addInterceptor(logging)
    .build()&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이거는 요청/응답 정보를 로그로 확인하고 싶다면 아래처럼 로깅 인터셉터를 추가하는 예제이다.&lt;/p&gt;</description>
      <category>android</category>
      <category>android</category>
      <category>okhttp</category>
      <author>Seon Dev Notes</author>
      <guid isPermaLink="true">https://seon-dev.tistory.com/25</guid>
      <comments>https://seon-dev.tistory.com/25#entry25comment</comments>
      <pubDate>Tue, 8 Apr 2025 00:43:46 +0900</pubDate>
    </item>
  </channel>
</rss>