スマートフォンアプリ作成

AppStoreにて無料公開中! ”システム手帳”で検索! - AppStoreへ iPad版 - iPhone版

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が呼ばれないことになる。

2018年11月
    123
45678910
11121314151617
18192021222324
252627282930 
android
iOS
アプリの著作権
ブロックチェーン/暗号技術
日本のなりたち

AppStoreにて無料公開中! ”システム手帳”で検索! - AppStoreへ iPad版 - iPhone版
スマートフォンアプリ作成