SurfaceHolderを用いたライブ壁紙の実装
androidではiOSでは許諾されていない機能がアプリに許諾されている。
そのひとつがライブ壁紙(Live Wallpaper)と呼ばれるアプリを壁紙にすることができる機能である。
様々な表現を壁紙として実装することができる。
<実装ポイント>
・アニメーションする場合は、WallpaperService#EngineをRunnableにする。
・アニメーションしないシンプルな壁紙の場合は、WallpaperService#Engineで再帰的にThreadをHandler#postする。
・AndroidManifestでandroid:exportedを有効化しないとEngine#onSurfaceDestroyedされない。
・SurfaceViewはメインスレッドでなくても描画手続きができるので、通常のThread(Runnable)を描画スレッドとして利用出来る。
<ライブ壁紙実装のために最低限必要となるもの>
・AndroidManifest.xml
manifestファイルでライブ壁紙の定義を行う。
ここでandroid:exported="true" と定義しないとandroidからserviceを操作できないため、壁紙が変更されたときやプレビューから壁紙として登録する際に、Engine#onSurfaceDestroyedが呼ばれない。
< uses-feature android:name="android.software.live_wallpaper" />
< service android:name="MyWallpaper" android:enabled="true" android:exported="true" android:permission="android.permission.BIND_WALLPAPER">
< intent-filter>
< action android:name="android.service.wallpaper.WallpaperService" />
< /intent-filter>
< meta-data android:name="android.service.wallpaper" android:resource="@xml/myWallpaper" />
< /service>
・myWallpaper.xmlファイル
< ?xml version="1.0" encoding="utf-8"?>
< wallpaper xmlns:android="http://schemas.android.com/apk/res/android" />
・Java
public class MyWallpaper extends WallpaperService {
public class MyEngine extends Engine implements Runnable {
private Thread myThread;
@Override
public void onCreate(SurfaceHolder surfaceHolder) {
// 起動のとき
}
@Override
public void onVisibilityChanged(boolean visible) {
// スタンバイ、別アプリ起動のとき
}
@Override
public void onSurfaceCreated(SurfaceHolder holder) {
// 起動のとき
myThread = new Thread(this);
}
@Override
public void onSurfaceChanged(SurfaceHolder holder, int format,int width, int height) {
// SurfaceView画面解像度が変更されたとき
// Runnableスレッドを開始
if (myThread != null ) {
myThread.start();
}
}
public void run() {
// Runnableデリゲート
// 1秒間に60回実行される
while (myThread != null) {
// ここでCanvasに描画する
SurfaceHolder surfaceHolder = getSurfaceHolder();
if (surfaceHolder != null) {
Canvas canvas = null;
// 排他制御開始
canvas = surfaceHolder.lockCanvas();
if (canvas != null) {
canvas.save();
// Canvasに描画
canvas.translate(x, y);
drawable.draw(canvas);
// Canvasを元に戻す
canvas.restore();
// 排他制御終了
surfaceHolder.unlockCanvasAndPost(canvas);
}
}
}
}
}
・描画スレッドの実装方法
描画Thread実装には2つの方法がある。
1) Handlerから再帰的にThreadをpostする
handler.post(new Runnable() {
@Override
public void run() {
// Handlerはメインスレッドで実行される
// 描画手続きを行う
}
});
・バッテリー消費低減を優先する方法で、Home画面が非表示のときにはスレッド自体を生成しないことが可能となる。
・ボトルネックが発生するので、コマ落ちが発生しやすい。
2) Runnableスレッド手続きをwhileループさせる
・フレーム描画間でボトルネックが発生しないので、スムーズな描画ができる。
・Runnableスレッドは開始停止は一度だけなので、Home画面非表示時にもスレッドは動作し続けるので、バッテリー消費的には若干不利となる。
・SurfaceView(SurfaceHolder)はメインスレッドでなくても表示手続きができるので、ThreadをHandlerでpostする必要はない。
・Runnableの実行をなるべく軽くすること。特に端末ストアへのアクセスはRunnable以外で行うこと。
・バッテリー消費を抑える
Home画面が非表示状態のときには描画手続きを行わないことで、バッテリー消費を低減することができる。
Home画面表示が表示されているか非表示状態なのかは、Engine#onVisibilityChangedにコールバックされる。
次の状態を検知できる
・他のアプリやActivityが表示されたとき
・スタンバイ状態になったとき
・Manifest定義
AndroidManifestでライブ壁紙サービスについて android:exported を有効化定義しないとandroidからserviceを操作できないため、壁紙が変更されたときやプレビューから壁紙として登録する際に、Engine#onSurfaceDestroyedが呼ばれないことになる。
2023年12月 | ||||||
日 | 月 | 火 | 水 | 木 | 金 | 土 |
  |   |   |   |   | 1 | 2 |
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |   |   |   |   |   |   |
iOS
web
アプリの著作権
ブロックチェーン/暗号技術
新しい社会
禅・大乗仏教
日本のなりたち