라이브 월페이퍼의 핵심 메커니즘
Android 12에서 WallpaperService는 정적 이미지를 넘어서 실시간 렌더링이 가능한 동적 배경 화면을 구현하는 핵심 컴포넌트다. 이 서비스는 SurfaceHolder를 통해 직접 그래픽스 버퍼에 접근하며, 프레임별 갱신이나 사용자 터치 반응 등 다양한 인터랙티브한 시각 효과를 구현할 수 있다.
엔진 클래스 설계 및 구현
월페이퍼의 실제 렌더링 로직은 WallpaperService.Engine을 상속받은 내부 클래스에서 처리한다. 다음은 기본 엔진 구조를 재구성한 예시다.
import android.service.wallpaper.WallpaperService;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.view.SurfaceHolder;
public class ParticleWallpaperService extends WallpaperService {
@Override
public Engine onCreateEngine() {
return new ParticleRenderEngine();
}
private class ParticleRenderEngine extends Engine {
private Paint brush;
private int backgroundHue;
private boolean isVisible;
ParticleRenderEngine() {
brush = new Paint(Paint.ANTI_ALIAS_FLAG);
backgroundHue = 0xFF1A237E; // 딥 인디고
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
super.onSurfaceCreated(holder);
isVisible = true;
scheduleNextFrame();
}
@Override
public void onSurfaceDestroyed(SurfaceHolder holder) {
super.onSurfaceDestroyed(holder);
isVisible = false;
}
@Override
public void onVisibilityChanged(boolean visible) {
isVisible = visible;
if (visible) {
scheduleNextFrame();
}
}
void scheduleNextFrame() {
if (!isVisible) return;
backgroundHue = (backgroundHue == 0xFF1A237E) ? 0xFF880E4F : 0xFF1A237E;
renderFrame();
// 16ms 간격으로 약 60fps 목표
getSurfaceHolder().getSurface().getHandler().postDelayed(
this::scheduleNextFrame, 16
);
}
void renderFrame() {
Rect bounds = getSurfaceHolder().getSurfaceFrame();
Canvas target = getSurfaceHolder().lockCanvas();
if (target == null) return;
target.drawColor(backgroundHue);
// 추가 그래픽 요소 렌더링
getSurfaceHolder().unlockCanvasAndPost(target);
}
}
}
매니페스트 선언 및 권한 설정
월페이퍼 서비스는 android.permission.BIND_WALLPAPER 권한이 필수이며, 적절한 인텐트 필터와 메타데이터를 선언해야 시스템에서 인식한다.
<service
android:name=".ParticleWallpaperService"
android:permission="android.permission.BIND_WALLPAPER"
android:exported="true">
<intent-filter>
<action android:name="android.service.wallpaper.WallpaperService" />
</intent-filter>
<meta-data
android:name="android.service.wallpaper"
android:resource="@xml/live_wallpaper_config" />
</service>
XML 메타데이터 구성
res/xml/live_wallpaper_config.xml 파일에서 미리보기 썸네일과 설명 리소스를 정의한다.
<?xml version="1.0" encoding="utf-8"?>
<wallpaper
xmlns:android="http://schemas.android.com/apk/res/android"
android:thumbnail="@drawable/preview_thumb"
android:description="@string/wallpaper_desc"
android:settingsActivity=".WallpaperSettingsActivity" />
터치 이벤트 연동 및 상태 관리
사용자 입력을 반영하여 월페이퍼의 시각적 피드백을 즉각적으로 처리할 수 있다. onTouchEvent를 오버라이드하여 터치 좌표에 따른 파티클 생성이나 색상 변화를 구현한다.
import android.view.MotionEvent;
@Override
public void onTouchEvent(MotionEvent motion) {
switch (motion.getActionMasked()) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_MOVE:
float touchX = motion.getX();
float touchY = motion.getY();
// 터치 위치 기반 효과 계산
updateParticleSource(touchX, touchY);
renderFrame();
break;
case MotionEvent.ACTION_UP:
resetParticleVelocity();
break;
}
}
private void updateParticleSource(float x, float y) {
// 터치 좌표를 파티클 발생점으로 매핑
brush.setColor(0xFFFF6F00); // 앰버
// ...
}
리소스 최적화 고려사항
라이브 월페이퍼는 배터리 소모가 크므로 다음 사항을 고려해야 한다:
onVisibilityChanged에서 화면이 보이지 않을 때 렌더링 루프 중단- 표면 파괴 시
Handler콜백 완전 제거 - 비트맵 캐싱 및 객체 풀링 적용
- Android 12의
setFrameRateAPI로 적절한 주사율 명시