<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>안드로이드 &#8211; 솜삽 블로그</title>
	<atom:link href="https://somsap.somsap.com/tag/%EC%95%88%EB%93%9C%EB%A1%9C%EC%9D%B4%EB%93%9C/feed/" rel="self" type="application/rss+xml" />
	<link>https://somsap.somsap.com</link>
	<description>개발, 업무, 피아노 등등</description>
	<lastBuildDate>Sun, 03 May 2026 12:50:56 +0000</lastBuildDate>
	<language>ko-KR</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.5</generator>

<image>
	<url>https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2025/02/cropped-%EC%9D%B4%EB%AF%B8%EC%A7%80-1924-2.png?fit=32%2C32&#038;ssl=1</url>
	<title>안드로이드 &#8211; 솜삽 블로그</title>
	<link>https://somsap.somsap.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">241690237</site>	<item>
		<title>안드로이드 비디오 앱이 점점 느려지는 이유: ghostFaces 맵이 범인이었다</title>
		<link>https://somsap.somsap.com/2026/02/05/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-%eb%b9%84%eb%94%94%ec%98%a4-%ec%95%b1%ec%9d%b4-%ec%a0%90%ec%a0%90-%eb%8a%90%eb%a0%a4%ec%a7%80%eb%8a%94-%ec%9d%b4%ec%9c%a0-ghostfaces-%eb%a7%b5%ec%9d%b4/</link>
					<comments>https://somsap.somsap.com/2026/02/05/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-%eb%b9%84%eb%94%94%ec%98%a4-%ec%95%b1%ec%9d%b4-%ec%a0%90%ec%a0%90-%eb%8a%90%eb%a0%a4%ec%a7%80%eb%8a%94-%ec%9d%b4%ec%9c%a0-ghostfaces-%eb%a7%b5%ec%9d%b4/#respond</comments>
		
		<dc:creator><![CDATA[somsap]]></dc:creator>
		<pubDate>Wed, 04 Feb 2026 20:52:17 +0000</pubDate>
				<category><![CDATA[미분류]]></category>
		<category><![CDATA[Android]]></category>
		<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Face Detection]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[Map 최적화]]></category>
		<category><![CDATA[Memory Leak]]></category>
		<category><![CDATA[Performance]]></category>
		<category><![CDATA[Video Processing]]></category>
		<category><![CDATA[디버깅]]></category>
		<category><![CDATA[메모리누수]]></category>
		<category><![CDATA[비디오처리]]></category>
		<category><![CDATA[성능최적화]]></category>
		<category><![CDATA[안드로이드]]></category>
		<category><![CDATA[앱개발]]></category>
		<category><![CDATA[얼굴인식]]></category>
		<category><![CDATA[프로파일링]]></category>
		<guid isPermaLink="false">https://somsap.somsap.com/?p=2685</guid>

					<description><![CDATA[<p>얼굴 블러 처리 앱을 만들었는데, 이상한 현상이 발생했습니다. 처음엔 빠르게 잘 돌아가다가 시간이 지날수록 점점 느려지더니, 결국 앱이 뻗어버렸어요. 로그를 찍어보니 충격적인 결과가 나왔습니다. 블러 처리 시간이 9ms에서 시작해서 264ms까지 늘어났습니다. 거의 30배 느려진 거죠. 첫 번째 용의자: RenderScript Allocation 처음엔 당연히 RenderScript가 문제라고 생각했습니다. GPU 메모리 누수가 의심스러웠거든요. Allocation 재사용 구현 매번 Allocation을 생성하고 [&#8230;]</p>
<p>게시물 <a rel="nofollow" href="https://somsap.somsap.com/2026/02/05/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-%eb%b9%84%eb%94%94%ec%98%a4-%ec%95%b1%ec%9d%b4-%ec%a0%90%ec%a0%90-%eb%8a%90%eb%a0%a4%ec%a7%80%eb%8a%94-%ec%9d%b4%ec%9c%a0-ghostfaces-%eb%a7%b5%ec%9d%b4/">안드로이드 비디오 앱이 점점 느려지는 이유: ghostFaces 맵이 범인이었다</a>이 <a rel="nofollow" href="https://somsap.somsap.com">솜삽 블로그</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<p>얼굴 블러 처리 앱을 만들었는데, 이상한 현상이 발생했습니다. 처음엔 빠르게 잘 돌아가다가 시간이 지날수록 점점 느려지더니, 결국 앱이 뻗어버렸어요.</p>



<p>로그를 찍어보니 충격적인 결과가 나왔습니다.</p>



<pre class="wp-block-code"><code>&#091;프레임 0~30] 블러=9ms
&#091;프레임 90~120] 블러=73ms
&#091;프레임 210~240] 블러=150ms
&#091;프레임 450~480] 블러=264ms
</code></pre>



<p>블러 처리 시간이 9ms에서 시작해서 264ms까지 늘어났습니다. 거의 30배 느려진 거죠.</p>



<h3 class="wp-block-heading">첫 번째 용의자: RenderScript Allocation</h3>



<p>처음엔 당연히 RenderScript가 문제라고 생각했습니다. GPU 메모리 누수가 의심스러웠거든요.</p>



<h4 class="wp-block-heading">Allocation 재사용 구현</h4>



<p>매번 Allocation을 생성하고 해제하는 대신, 캐시해서 재사용하도록 수정했습니다.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin">private var cachedInput: Allocation? = null
private var cachedOutput: Allocation? = null

<em>// 크기가 같으면 재사용</em>
if (cachedInput == null || cachedWidth != w || cachedHeight != h) {
    cachedInput?.destroy()
    cachedOutput?.destroy()
    cachedInput = Allocation.createFromBitmap(renderScript, faceRegion)
    cachedOutput = Allocation.createTyped(renderScript, cachedInput!!.type)
} else {
    cachedInput!!.copyFrom(faceRegion)
}
</code></pre></div>



<p>결과는? 여전히 느려졌습니다. 조금 나아지긴 했지만 근본적인 해결책은 아니었어요.</p>



<h3 class="wp-block-heading">두 번째 용의자: Canvas 중복 생성</h3>



<p>혹시 Canvas를 루프 안에서 계속 생성하고 있나 싶어서 확인해봤습니다.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin"><em>// 잘못된 코드</em>
facesWithIntensity.forEach { (face, _) -&gt;
    val canvas = Canvas(output)  <em>// 매번 생성!</em>
    canvas.drawBitmap(faceRegion, ...)
}

<em>// 수정한 코드</em>
val canvas = Canvas(output)  <em>// 한 번만 생성</em>
facesWithIntensity.forEach { (face, _) -&gt;
    canvas.drawBitmap(faceRegion, ...)
}
</code></pre></div>



<p>이것도 고쳤지만&#8230; 여전히 느려졌습니다.</p>



<h3 class="wp-block-heading">진짜 범인: ghostFaces 맵</h3>



<p>얼굴이 화면에서 사라졌다가 다시 나타날 때를 대비해서 ghostFaces라는 맵을 만들었습니다. 얼굴이 잠깐 가려지거나 옆을 봐도 블러가 유지되도록 하려고요.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin"><em>// 사라진 얼굴들도 일시적으로 블러 유지</em>
ghostFaces.entries.removeAll { (faceId, rectCounter) -&gt;
    val (ghostRect, counter) = rectCounter
    
    val isNearCurrentFace = currentFaces.any { ... }
    val newCounter = if (isNearCurrentFace) 0 else counter + 1
    
    if (newCounter &gt; 60) {
        true  <em>// 60프레임 후 제거</em>
    } else {
        activeFaces.add(ghostRect to intensity)
        ghostFaces&#091;faceId] = ghostRect to newCounter
        false
    }
}
</code></pre></div>



<figure class="wp-block-image size-full"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="1024" height="559" src="https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-5.png?resize=1024%2C559&#038;ssl=1" alt="image 5" class="wp-image-2687" title="안드로이드 비디오 앱이 점점 느려지는 이유: ghostFaces 맵이 범인이었다 1" srcset="https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-5.png?w=1024&amp;ssl=1 1024w, https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-5.png?resize=300%2C164&amp;ssl=1 300w, https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-5.png?resize=768%2C419&amp;ssl=1 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></figure>



<p>문제는 Map.entries.removeAll이었습니다. 이 메서드는 내부적으로 매번 전체 맵을 순회하면서 조건을 체크합니다. ghostFaces 맵이 커질수록 점점 느려지는 거죠.</p>



<p>더 큰 문제는 제거 조건이 까다로워서 맵이 계속 커진다는 점이었습니다. 얼굴이 여러 번 나타났다 사라지면 ghostFaces에 수십 개의 항목이 쌓이고, 매 프레임마다 이걸 전부 순회하니 느려질 수밖에 없었어요.</p>



<h3 class="wp-block-heading">해결책: 별도 리스트로 수집 후 제거</h3>



<p>removeAll 대신 제거할 항목을 별도 리스트에 모은 다음, 한 번에 제거하도록 바꿨습니다.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin">val toRemove = mutableListOf&lt;String&gt;()

ghostFaces.forEach { (faceId, rectCounter) -&gt;
    val (ghostRect, counter) = rectCounter
    
    val isNearCurrentFace = currentFaces.any { ... }
    val newCounter = if (isNearCurrentFace) 0 else counter + 1
    
    if (newCounter &gt; 60) {
        toRemove.add(faceId)  <em>// 제거 목록에 추가</em>
    } else {
        activeFaces.add(ghostRect to intensity)
        ghostFaces&#091;faceId] = ghostRect to newCounter
    }
}

<em>// 한 번에 제거</em>
toRemove.forEach { ghostFaces.remove(it) }
</code></pre></div>



<p>추가로 안전장치도 넣었습니다.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin"><em>// 50프레임마다 맵이 너무 크면 강제 정리</em>
if (frameProcessed % 50 == 0 &amp;&amp; ghostFaces.size &gt; 10) {
    ghostFaces.clear()
}
</code></pre></div>



<h3 class="wp-block-heading">결과: 드디어 해결!</h3>



<figure class="wp-block-image size-full"><img data-recalc-dims="1" decoding="async" width="1024" height="559" src="https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-6.png?resize=1024%2C559&#038;ssl=1" alt="image 6" class="wp-image-2690" title="안드로이드 비디오 앱이 점점 느려지는 이유: ghostFaces 맵이 범인이었다 2" srcset="https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-6.png?w=1024&amp;ssl=1 1024w, https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-6.png?resize=300%2C164&amp;ssl=1 300w, https://i0.wp.com/somsap.somsap.com/wp-content/uploads/sites/6/2026/02/image-6.png?resize=768%2C419&amp;ssl=1 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></figure>



<p>이 수정 후 블러 시간이 안정화되었습니다.</p>



<pre class="wp-block-code"><code>&#091;프레임 0~30] 블러=11ms
&#091;프레임 30~60] 블러=30ms
&#091;프레임 60~90] 블러=52ms
&#091;프레임 90~120] 블러=71ms
&#091;프레임 120~150] 블러=95ms
&#091;프레임 150~180] 블러=20ms
&#091;프레임 180~210] 블러=37ms
이후 100ms 이하 유지.</code></pre>



<p>더 이상 시간이 증가하지 않습니다. 8~100ms 사이에서 안정적으로 유지되고 있어요.</p>



<h3 class="wp-block-heading">추가 최적화: 얼굴 감지</h3>



<p>ghostFaces 문제를 해결한 김에 다른 부분도 최적화했습니다.</p>



<h4 class="wp-block-heading">다운스케일 감지</h4>



<p>1080p 영상에서 얼굴을 찾는 건 과한 감이 있습니다. 절반 크기로 줄여서 감지하고, 좌표만 2배로 늘렸어요.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin"><em>// 50% 크기로 다운스케일</em>
val detectW = (bmp.width * 0.5f).toInt()
val detectH = (bmp.height * 0.5f).toInt()
val downscaled = Bitmap.createScaledBitmap(bmp, detectW, detectH, false)

<em>// 감지 후 좌표 스케일업</em>
val scaledFaces = rawFaces.map { (rect, conf) -&gt;
    Rect(rect.left * 2, rect.top * 2, rect.right * 2, rect.bottom * 2) to conf
}
</code></pre></div>



<p>결과: 얼굴 감지 속도 4배 향상</p>



<h4 class="wp-block-heading">감지 간격 확대</h4>



<p>매 3프레임마다 감지하던 걸 8프레임으로 늘렸습니다. 얼굴이 그렇게 빨리 움직이지 않으니까요.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin">if (frameProcessed % 8 == 0) {
    frameQueue.offer(frameProcessed to downscaled)
}
</code></pre></div>



<h3 class="wp-block-heading">성능 모니터링</h3>



<p>최적화 효과를 확인하려면 측정이 필요합니다. 30프레임마다 각 작업별 평균 시간을 로그로 남겼어요.</p>



<div class="my-codeblock-wrap"><div class="my-codeblock-label">Kotlin</div><pre><code class="language-kotlin">private data class PerformanceMetrics(
    var yuvConversionMs: Long = 0,
    var blurProcessingMs: Long = 0,
    var surfaceRenderMs: Long = 0,
    var encoderMs: Long = 0,
    var frameCount: Int = 0
)

<em>// 30프레임마다 출력</em>
Log.d("VideoPerf", "&#091;프레임 $start~$end] YUV=${avgYuv}ms, 블러=${avgBlur}ms, 렌더=${avgRender}ms")
</code></pre></div>



<p>이 로그 덕분에 ghostFaces가 문제라는 걸 정확히 찾아낼 수 있었습니다.</p>



<h3 class="wp-block-heading">최종 결과</h3>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>항목</th><th>최적화 전</th><th>최적화 후</th><th>개선율</th></tr></thead><tbody><tr><td>블러 시간 (초기)</td><td>9ms</td><td>8ms</td><td>11% 향상</td></tr><tr><td>블러 시간 (안정)</td><td>264ms</td><td>8~100ms</td><td>95% 향상</td></tr><tr><td>얼굴 감지 빈도</td><td>매 3프레임</td><td>매 8프레임</td><td>62% 감소</td></tr><tr><td>감지 해상도</td><td>100%</td><td>50%</td><td>4배 빠름</td></tr></tbody></table></figure>



<p>가장 중요한 건 시간이 지나도 성능이 일정하게 유지된다는 점입니다.</p>



<h3 class="wp-block-heading">배운 교훈 <s>by 개고생</s></h3>



<h4 class="wp-block-heading">1. Map.entries.removeAll은 생각보다 느리다</h4>



<h4 class="wp-block-heading">2. 컬렉션 크기를 제한하라</h4>



<h4 class="wp-block-heading">3. 성능 로그는 필수</h4>



<h4 class="wp-block-heading">4. 첫 번째 용의자가 범인이 아닐 수 있다</h4>



<h4 class="wp-block-heading">5. 작은 최적화도 쌓이면 크다</h4>



<h3 class="wp-block-heading">마치며</h3>



<p>성능 문제는 예상치 못한 곳에서 발생합니다. ghostFaces라는 작은 맵이 전체 앱을 느리게 만들 줄은 몰랐어요.</p>



<p>중요한 건 측정입니다. 로그를 찍고, 프로파일링하고, 데이터를 보면서 하나씩 개선해 나가면 됩니다.</p>



<p>이 글이 비슷한 문제를 겪는 분들께 도움이 되길 바랍니다.</p>



<p></p>
<p>게시물 <a rel="nofollow" href="https://somsap.somsap.com/2026/02/05/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-%eb%b9%84%eb%94%94%ec%98%a4-%ec%95%b1%ec%9d%b4-%ec%a0%90%ec%a0%90-%eb%8a%90%eb%a0%a4%ec%a7%80%eb%8a%94-%ec%9d%b4%ec%9c%a0-ghostfaces-%eb%a7%b5%ec%9d%b4/">안드로이드 비디오 앱이 점점 느려지는 이유: ghostFaces 맵이 범인이었다</a>이 <a rel="nofollow" href="https://somsap.somsap.com">솜삽 블로그</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://somsap.somsap.com/2026/02/05/%ec%95%88%eb%93%9c%eb%a1%9c%ec%9d%b4%eb%93%9c-%eb%b9%84%eb%94%94%ec%98%a4-%ec%95%b1%ec%9d%b4-%ec%a0%90%ec%a0%90-%eb%8a%90%eb%a0%a4%ec%a7%80%eb%8a%94-%ec%9d%b4%ec%9c%a0-ghostfaces-%eb%a7%b5%ec%9d%b4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2685</post-id>	</item>
		<item>
		<title>어제오늘날씨 &#8211; 어제와 오늘 날씨를 비교하는 앱 만들기</title>
		<link>https://somsap.somsap.com/2025/11/13/%ec%96%b4%ec%a0%9c%ec%98%a4%eb%8a%98%eb%82%a0%ec%94%a8-%ec%96%b4%ec%a0%9c%ec%99%80-%ec%98%a4%eb%8a%98-%eb%82%a0%ec%94%a8%eb%a5%bc-%eb%b9%84%ea%b5%90%ed%95%98%eb%8a%94-%ec%95%b1-%eb%a7%8c%eb%93%a4/</link>
					<comments>https://somsap.somsap.com/2025/11/13/%ec%96%b4%ec%a0%9c%ec%98%a4%eb%8a%98%eb%82%a0%ec%94%a8-%ec%96%b4%ec%a0%9c%ec%99%80-%ec%98%a4%eb%8a%98-%eb%82%a0%ec%94%a8%eb%a5%bc-%eb%b9%84%ea%b5%90%ed%95%98%eb%8a%94-%ec%95%b1-%eb%a7%8c%eb%93%a4/#respond</comments>
		
		<dc:creator><![CDATA[somsap]]></dc:creator>
		<pubDate>Thu, 13 Nov 2025 12:52:41 +0000</pubDate>
				<category><![CDATA[개발/프로그래밍]]></category>
		<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[NodeJS]]></category>
		<category><![CDATA[날씨앱]]></category>
		<category><![CDATA[안드로이드]]></category>
		<category><![CDATA[토이프로젝트]]></category>
		<category><![CDATA[풀스택]]></category>
		<guid isPermaLink="false">https://somsap.somsap.com/?p=2166</guid>

					<description><![CDATA[<p>🧥 아침마다 옷장 앞에서 망부석? AI 코디가 해결해 드립니다! &#8216;어제오늘&#8217; 앱 전격 출시! &#8220;아… 오늘 뭐 입지?&#8221; 매일 아침, 우리 모두가 마주하는 심오한 철학적 질문이죠. 어제 입었던 옷을 또 입자니 왠지 찝찝하고, 새 옷을 꺼내자니 날씨에 안 맞을까 봐 걱정되고… 그렇게 옷장 앞에서 10분, 20분… 소중한 아침 시간이 흘러갑니다. 😭 혹시 이런 생각 해보셨나요? &#8220;어제 [&#8230;]</p>
<p>게시물 <a rel="nofollow" href="https://somsap.somsap.com/2025/11/13/%ec%96%b4%ec%a0%9c%ec%98%a4%eb%8a%98%eb%82%a0%ec%94%a8-%ec%96%b4%ec%a0%9c%ec%99%80-%ec%98%a4%eb%8a%98-%eb%82%a0%ec%94%a8%eb%a5%bc-%eb%b9%84%ea%b5%90%ed%95%98%eb%8a%94-%ec%95%b1-%eb%a7%8c%eb%93%a4/">어제오늘날씨 &#8211; 어제와 오늘 날씨를 비교하는 앱 만들기</a>이 <a rel="nofollow" href="https://somsap.somsap.com">솜삽 블로그</a>에 처음 등장했습니다.</p>
]]></description>
										<content:encoded><![CDATA[
<h1 class="wp-block-heading">🧥 아침마다 옷장 앞에서 망부석? AI 코디가 해결해 드립니다! &#8216;어제오늘&#8217; 앱 전격 출시!</h1>



<p>&#8220;아… 오늘 뭐 입지?&#8221;</p>



<p>매일 아침, 우리 모두가 마주하는 심오한 철학적 질문이죠. 어제 입었던 옷을 또 입자니 왠지 찝찝하고, 새 옷을 꺼내자니 날씨에 안 맞을까 봐 걱정되고… 그렇게 옷장 앞에서 10분, 20분… 소중한 아침 시간이 흘러갑니다. 😭</p>



<p>혹시 이런 생각 해보셨나요? <strong>&#8220;어제 날씨랑만 비교해도 옷 입기 훨씬 편할 텐데!&#8221;</strong></p>



<p>바로 그 생각, 저희가 현실로 만들었습니다!</p>



<h3 class="wp-block-heading">✨ 날씨 기반 AI 패션 코디네이터, &#8216;어제오늘&#8217; 앱을 소개합니다!</h3>



<p>&#8216;어제오늘&#8217;은 단순히 날씨만 알려주는 앱이 아닙니다. <strong>어제와 오늘의 기온을 직관적인 그래프로 비교</strong>해주고, <strong>가장 핫한 K-패션 트렌드</strong>를 반영한 오늘의 착장을 AI가 직접 추천해주는, 당신의 손안에 생긴 전문 스타일리스트입니다.</p>



<p><img data-recalc-dims="1" decoding="async" src="https://i0.wp.com/via.placeholder.com/800x450.png?ssl=1" alt="앱 스크린샷" title="어제오늘날씨 - 어제와 오늘 날씨를 비교하는 앱 만들기 4"><br><em>(앱의 멋진 스크린샷을 여기에 넣어보세요!)</em></p>



<h3 class="wp-block-heading">&#8216;어제오늘&#8217; 앱의 핵심 기능 3가지!</h3>



<h4 class="wp-block-heading">1. 한눈에 끝! 어제 vs 오늘 기온 배틀 📈</h4>



<p>더 이상 숫자를 보고 머리 아파하지 마세요. &#8216;어제오늘&#8217; 앱은 어제와 오늘의 시간대별 기온 변화를 <strong>하나의 그래프</strong>에 깔끔하게 보여줍니다.</p>



<ul class="wp-block-list">
<li>&#8220;어? 오늘 아침은 어제보다 쌀쌀하네? 가디건 챙겨야지!&#8221;</li>



<li>&#8220;오후엔 어제보다 훨씬 덥구나! 외투는 차에 두고 가도 되겠다.&#8221;</li>
</ul>



<p>그래프만 쓱- 봐도 오늘 하루 기온 변화를 완벽하게 예측하고 대비할 수 있습니다.</p>



<h4 class="wp-block-heading">2. 내 손안의 AI 스타일리스트 🤖</h4>



<p>이 앱의 진짜 주인공! 바로 <strong>AI 패션 코디네이터</strong>입니다. 현재 날씨와 기온 변화에 맞춰, 가장 트렌디한 스타일을 추천해줘요.</p>



<ul class="wp-block-list">
<li><strong>힙스터를 위한 &#8216;캐주얼룩&#8217;</strong>: 요즘 서울에서 가장 핫한 와이드 팬츠, 오버핏 셔츠 스타일링을 만나보세요.</li>



<li><strong>직장인을 위한 &#8216;비즈니스룩&#8217;</strong>: 꾸민 듯 안 꾸민 듯, 단정하면서도 세련된 출근룩을 제안합니다.</li>



<li><strong>성별에 따른 맞춤 추천</strong>: 남성/여성별로 각각 다른 스타일을 제공하는 건 기본이죠!</li>
</ul>



<p>이제 &#8220;패알못&#8221;도 매일 아침 인스타그램 패셔니스타가 될 수 있습니다.</p>



<h4 class="wp-block-heading">3. 전 세계 어디서든, 설정은 내 마음대로 🌍</h4>



<p>여행을 가셨나요? 출장 중이신가요? &#8216;어제오늘&#8217;은 <strong>전 세계 모든 도시의 날씨</strong>를 지원합니다. GPS로 현재 위치를 자동으로 잡거나, 원하는 도시를 직접 검색할 수도 있어요.</p>



<p>물론, 앱 내 설정에서 언어를 직접 바꾸는 것도 가능합니다. 내게 가장 편한 방식으로 앱을 사용해 보세요!</p>



<h3 class="wp-block-heading">이런 분들께 강력 추천합니다!</h3>



<p>✅ 매일 아침 &#8216;입을 옷이 없다&#8217;고 느끼는 분<br>✅ 패션에 관심은 많지만, 어떻게 입어야 할지 막막한 분<br>✅ 출근룩, 등교룩 고민으로 10분을 허비하는 직장인과 학생<br>✅ 어제와 오늘의 미세한 기온 차이까지 챙기는 섬세한 날씨 요정🧚‍♀️</p>



<h3 class="wp-block-heading">이제 고민은 그만!</h3>



<p>더 이상 날씨 앱과 패션 앱을 따로 보지 마세요. &#8216;어제오늘&#8217; 앱 하나면 충분합니다.</p>



<p>지금 바로 다운로드하고, 매일 아침 10분의 여유와 스타일을 모두 챙기세요!</p>



<p>👇 <strong>지금 바로 다운로드하기</strong> 👇</p>



<div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex">
<div class="wp-block-button"><a class="wp-block-button__link wp-element-button" href="https://play.google.com/apps/testing/com.somsap.ydaytday" target="_blank" rel="noreferrer noopener">[Google Play Store 링크]</a></div>
</div>



<hr class="wp-block-separator has-alpha-channel-opacity" />



<p><strong>기술 스택:</strong>&nbsp;Kotlin, Node.js, Express, OpenWeatherMap API, Room Database, Retrofit, MPAndroidChart, SQLite, Coroutines</p>



<p></p>



<h1 class="wp-block-heading" id="Privacy-Policy">개인정보처리방침 (Privacy Policy)</h1>



<p><strong>최종 수정일: 2025년 11월 27일</strong></p>



<p>본 개인정보처리방침은 Yesterday-Today(이하 &#8216;앱&#8217;)가 사용자의 개인정보를 수집, 이용, 공유하는 방식에 대해 설명합니다. 앱을 사용함으로써 귀하는 본 방침에 동의하는 것으로 간주됩니다.</p>



<h3 class="wp-block-heading">1. 수집하는 정보</h3>



<p>저희는 앱의 핵심 기능을 제공하기 위해 다음과 같은 최소한의 정보를 수집합니다.</p>



<ul class="wp-block-list">
<li><strong>위치 정보 (위도 및 경도):</strong>
<ul class="wp-block-list">
<li><strong>수집 목적:</strong> 현재 위치의 날씨 정보와 그에 맞는 의상 추천을 제공하기 위함입니다.</li>



<li><strong>수집 방식:</strong>
<ol class="wp-block-list">
<li><strong>GPS 기반 현재 위치:</strong> 사용자가 명시적으로 위치 권한(ACCESS_FINE_LOCATION/ACCESS_COARSE_LOCATION)을 허용한 경우에만 기기의 GPS를 통해 현재 위치 좌표를 수집합니다.</li>



<li><strong>수동 검색 위치:</strong> 사용자가 앱 내에서 직접 도시 이름을 검색할 경우, 해당 지역의 위치 정보를 수집합니다.</li>
</ol>
</li>
</ul>
</li>



<li><strong>언어 및 지역 설정:</strong>
<ul class="wp-block-list">
<li><strong>수집 목적:</strong> 앱의 UI를 사용자 기기의 언어로 표시하고, 지역명을 현지 언어로 보여주기 위함입니다.</li>



<li><strong>수집 방식:</strong> 사용자 기기의 기본 언어 및 지역 설정을 확인하거나, 앱 내 설정에서 사용자가 직접 선택한 언어 정보를 수집합니다.</li>
</ul>
</li>



<li><strong>광고 식별자:</strong>
<ul class="wp-block-list">
<li><strong>수집 목적:</strong> 사용자에게 맞춤형 광고를 제공하기 위함입니다.</li>



<li><strong>수집 방식:</strong> Google AdMob SDK를 통해 광고 식별자(ADID)를 수집할 수 있습니다. 이는 기기 설정에서 재설정하거나 비활성화할 수 있습니다.</li>
</ul>
</li>



<li><strong>서비스 이용 기록:</strong>
<ul class="wp-block-list">
<li><strong>수집 목적:</strong> 서비스 안정성 확보, 오류 해결 및 성능 개선을 위함입니다.</li>



<li><strong>수집 방식:</strong> 앱과 서버 간의 통신 과정에서 IP 주소, User-Agent와 같은 기술적 정보가 서버 로그에 자동으로 기록될 수 있습니다.</li>
</ul>
</li>
</ul>



<h3 class="wp-block-heading">2. 정보의 이용</h3>



<p>수집된 정보는 오직 다음과 같은 목적으로만 사용됩니다.</p>



<ul class="wp-block-list">
<li><strong>핵심 기능 제공:</strong> 사용자의 위치에 기반한 날씨 정보 및 의상 이미지 추천</li>



<li><strong>서비스 개선:</strong> 오류 분석 및 사용자 경험 향상을 위한 통계 분석</li>



<li><strong>광고 제공:</strong> Google AdMob을 통한 맞춤형 광고 표시</li>
</ul>



<h3 class="wp-block-heading">3. 정보의 제3자 제공 및 공유</h3>



<p>저희는 사용자의 개인정보를 판매하거나 임의로 제3자에게 제공하지 않습니다. 다만, 원활한 서비스 제공을 위해 다음과 같이 신뢰할 수 있는 외부 서비스와 정보를 공유할 수 있습니다.</p>



<ul class="wp-block-list">
<li><strong>Open-Meteo &amp; OpenWeatherMap:</strong> 날씨 정보 조회 및 위치 검색(지오코딩/역-지오코딩)을 위해 사용자의 위치 좌표와 언어 설정을 전송합니다.</li>



<li><strong>Google (Vertex AI &amp; Places API):</strong> 의상 이미지 생성 및 도시 이름 검색 시 오타 수정을 위해 서버에서 해당 API를 호출합니다. 이때 사용자의 개인 식별 정보는 전송되지 않습니다.</li>



<li><strong>Google AdMob:</strong> 맞춤형 광고를 표시하기 위해 광고 식별자를 공유합니다.</li>
</ul>



<p>각 서비스의 개인정보처리방침은 아래 링크에서 확인하실 수 있습니다.</p>



<ul class="wp-block-list">
<li><a href="https://policies.google.com/privacy" target="_blank" rel="noopener">Google Privacy Policy</a></li>



<li><a href="https://open-meteo.com/en/privacy-policy" target="_blank" rel="noopener">Open-Meteo Privacy Policy</a></li>



<li><a href="https://openweather.co.uk/privacy-policy" target="_blank" rel="noopener">OpenWeatherMap Privacy Policy</a></li>
</ul>



<h3 class="wp-block-heading">4. 데이터 보관 및 보안</h3>



<ul class="wp-block-list">
<li><strong>클라이언트 (앱):</strong> 빠른 서비스 제공을 위해, 날씨 및 의상 정보는 최대 6시간 동안 사용자 기기의 내부 저장소(<code>SharedPreferences</code>)에 캐시(저장)됩니다. 이 데이터는 앱을 삭제하면 함께 제거됩니다.</li>



<li><strong>서버:</strong> 서비스 성능 향상을 위해 날씨 및 의상 이미지 데이터를 서버 데이터베이스에 캐시합니다. 이 데이터는 개인을 식별할 수 없는 형태로 저장되며, 주기적으로 삭제됩니다.</li>



<li>저희는 수집된 정보를 보호하기 위해 합리적인 기술적, 관리적 조치를 취하고 있습니다.</li>
</ul>



<h3 class="wp-block-heading">5. 사용자의 권리 및 선택</h3>



<ul class="wp-block-list">
<li><strong>위치 정보:</strong> 언제든지 기기 설정에서 앱의 위치 정보 접근 권한을 비활성화할 수 있습니다. 이 경우, 현재 위치 기반 서비스는 제한되며 수동으로 지역을 검색해야 합니다.</li>



<li><strong>언어 설정:</strong> 앱 내 설정 메뉴를 통해 언제든지 표시 언어를 변경할 수 있습니다.</li>



<li><strong>맞춤형 광고:</strong> 기기의 광고 설정에서 광고 ID를 재설정하거나 맞춤형 광고 수신을 거부할 수 있습니다.</li>
</ul>



<h3 class="wp-block-heading">6. 아동의 개인정보 보호</h3>



<p>저희 앱은 <strong>만 13세 미만의 어린이</strong>를 대상으로 하지 않으며, 의도적으로 해당 연령의 사용자로부터 개인정보를 수집하지 않습니다. 만약 만 13세 미만 아동의 개인정보가 수집된 사실을 인지하게 될 경우, 즉시 해당 정보를 삭제할 것입니다.</p>



<h3 class="wp-block-heading">7. 개인정보처리방침의 변경</h3>



<p>본 방침은 법령이나 서비스의 변경사항을 반영하기 위해 개정될 수 있습니다. 방침이 변경될 경우, 스토어 등록정보 페이지를 통해 공지하겠습니다.</p>



<h3 class="wp-block-heading">8. 문의처</h3>



<p>본 개인정보처리방침에 대해 궁금한 점이 있으시면 아래 이메일로 문의해 주시기 바랍니다.</p>



<ul class="wp-block-list">
<li><strong>이메일:</strong> rome777@gmail.com</li>
</ul>
<p>게시물 <a rel="nofollow" href="https://somsap.somsap.com/2025/11/13/%ec%96%b4%ec%a0%9c%ec%98%a4%eb%8a%98%eb%82%a0%ec%94%a8-%ec%96%b4%ec%a0%9c%ec%99%80-%ec%98%a4%eb%8a%98-%eb%82%a0%ec%94%a8%eb%a5%bc-%eb%b9%84%ea%b5%90%ed%95%98%eb%8a%94-%ec%95%b1-%eb%a7%8c%eb%93%a4/">어제오늘날씨 &#8211; 어제와 오늘 날씨를 비교하는 앱 만들기</a>이 <a rel="nofollow" href="https://somsap.somsap.com">솜삽 블로그</a>에 처음 등장했습니다.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://somsap.somsap.com/2025/11/13/%ec%96%b4%ec%a0%9c%ec%98%a4%eb%8a%98%eb%82%a0%ec%94%a8-%ec%96%b4%ec%a0%9c%ec%99%80-%ec%98%a4%eb%8a%98-%eb%82%a0%ec%94%a8%eb%a5%bc-%eb%b9%84%ea%b5%90%ed%95%98%eb%8a%94-%ec%95%b1-%eb%a7%8c%eb%93%a4/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2166</post-id>	</item>
	</channel>
</rss>
