0

ブーツのアニメーションからシンプルなライブ壁紙を作ろうとしています。つまり、基本的に、ドローアブルフォルダに約50の.pngがあります。アニメーションを約10〜20フレームに設定でき、うまく機能します。しかし、約30フレームに設定すると、OutOfMemoryエラーが発生します。誰かが私のコードを見て、もっと多くのフレームを達成する方法の例を教えてくれることを望んでいましたか?それは私がこれを何時間も見てきたのでとても助けになるでしょう><

これが私のコードです:

package com.androidnetwork.animlivewp;

import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.os.Handler;
import android.os.SystemClock;
import android.service.wallpaper.WallpaperService;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;

public class AnimatedLiveWallpaper extends WallpaperService {

    private final Handler mHandler = new Handler();

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Override
    public Engine onCreateEngine() {
        return new CubeEngine();
    }

    class CubeEngine extends Engine {

        private final Paint mPaint = new Paint();
        private float mPosY;
        private boolean mAnime = true;
        private Matrix mMatrix = new Matrix();

        private final Runnable mDrawAnim = new Runnable() {
            public void run() {
                drawFrame();
            }
        };
        private boolean mVisible;

        private static final int NUM_RES = 30;
        private final Bitmap[] mPics = new Bitmap[NUM_RES];
        CubeEngine() {
            Resources res = getResources();
            for (int i = 0; i< NUM_RES; i++) {
                int id = res.getIdentifier("boot_00" + (100 + (i + 1)), "drawable", "com.androidnetwork.animlivewp");
                mPics[i] = BitmapFactory.decodeResource(res, id);
            }
        }

        @Override
        public void onCreate(SurfaceHolder surfaceHolder) {
            super.onCreate(surfaceHolder);

            setTouchEventsEnabled(false);
        }

        @Override
        public void onDestroy() {
            super.onDestroy();
            mHandler.removeCallbacks(mDrawAnim);
        }

        @Override
        public void onVisibilityChanged(boolean visible) {
            mVisible = visible;
            if (visible) {
                drawFrame();
            } else {
                mHandler.removeCallbacks(mDrawAnim);
            }
        }

        @Override
        public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
            super.onSurfaceChanged(holder, format, width, height);

            float w = mPics[0].getWidth();
            float h = mPics[0].getHeight();
            float s = width / (float)w;
            mMatrix.reset();
            mMatrix.setScale(s, s);

            mPosY = (height - (h * s)) / 2f;
            drawFrame();
        }

        @Override
        public void onSurfaceCreated(SurfaceHolder holder) {
            super.onSurfaceCreated(holder);
        }

        @Override
        public void onSurfaceDestroyed(SurfaceHolder holder) {
            super.onSurfaceDestroyed(holder);
            mVisible = false;
            mHandler.removeCallbacks(mDrawAnim);
        }

        @Override
        public void onOffsetsChanged(float xOffset, float yOffset,
                float xStep, float yStep, int xPixels, int yPixels) {
            drawFrame();
        }


        @Override
        public void onTouchEvent(MotionEvent event) {
            if (event.getAction() == MotionEvent.ACTION_MOVE) {
                mAnime = !mAnime;
            }
            super.onTouchEvent(event);
        }


        void drawFrame() {
            final SurfaceHolder holder = getSurfaceHolder();

            Canvas c = null;
            try {
                c = holder.lockCanvas();
                if (c != null) {
                    // draw something
                    drawAnim(c);
                    //drawTouchPoint(c);
                }
            } finally {
                if (c != null) holder.unlockCanvasAndPost(c);
            }

            // Reschedule the next redraw
            mHandler.removeCallbacks(mDrawAnim);
            if (mVisible && mAnime) {
                mHandler.postDelayed(mDrawAnim, 1000 / 10);
            }
        }


        private int idx = 0;
        void drawAnim(Canvas c) {
            c.save();
            c.translate(0, mPosY);
            c.drawBitmap(mPics[idx], mMatrix, mPaint);
            if (mAnime) ++idx;
            if (idx == NUM_RES) idx = 0;

            c.restore();
        }



    }
}

そして、それがまったく役立つなら、ここにlogcatがあります:

08-22 19:45:05.508: ERROR/AndroidRuntime(12277): FATAL EXCEPTION: main
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.Bitmap.nativeCreate(Native Method)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.Bitmap.createBitmap(Bitmap.java:468)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.Bitmap.createBitmap(Bitmap.java:435)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.BitmapFactory.finishDecode(BitmapFactory.java:488)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.BitmapFactory.decodeStream(BitmapFactory.java:462)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.BitmapFactory.decodeResourceStream(BitmapFactory.java:323)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:346)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.graphics.BitmapFactory.decodeResource(BitmapFactory.java:372)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at com.androidnetwork.animlivewp.AnimatedLiveWallpaper$CubeEngine.<init>(AnimatedLiveWallpaper.java:55)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at com.androidnetwork.animlivewp.AnimatedLiveWallpaper.onCreateEngine(AnimatedLiveWallpaper.java:32)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.service.wallpaper.WallpaperService$IWallpaperEngineWrapper.executeMessage(WallpaperService.java:814)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:61)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.os.Handler.dispatchMessage(Handler.java:99)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.os.Looper.loop(Looper.java:123)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at android.app.ActivityThread.main(ActivityThread.java:4627)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at java.lang.reflect.Method.invokeNative(Native Method)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at java.lang.reflect.Method.invoke(Method.java:521)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    08-22 19:45:05.508: ERROR/AndroidRuntime(12277):     at dalvik.system.NativeStart.main(Native Method)
4

4 に答える 4

3

キャンバスを描画するたびに、ビットマップを1つだけ作成し、各pngをリロードします。たとえば、各画像を同じビットマップ割り当てに再読み込みする簡単なルーチンを作成します。また、pngはロスレス形式であるため、pngファイルをjpgファイルに変換することをお勧めします。jpgを使用すると、各フレームをわずかに圧縮できます。

public void updateBG() {

idx += 1;
if (idx == NUM_RES) {idx = 0;}
switch (bgcycle) {
    case 0: myBg = BitmapFactory.decodeResource(getResources(),R.drawable.frame1); break;
    case 1: myBg = BitmapFactory.decodeResource(getResources(),R.drawable.frame2); break;
    case 2: myBg = BitmapFactory.decodeResource(getResources(),R.drawable.frame3); break;
            case etc....
        }}

または、bootanimationにリンクしたい場合は、これを使用できると思います

int id = res.getIdentifier("boot_00" + (100 + (idx + 1)), "drawable", "com.androidnetwork.animlivewp");
            myBg = BitmapFactory.decodeResource(res, id);

次に、DrawAnimコードで

updateBG();
c.drawBitmap(myBg, mMatrix, null);
于 2010-09-14T09:42:09.210 に答える
0

android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)つまり、drawable- * dpiフォルダーを正しく使用しなかったため、Androidが新しいビットマップを生成します...これにより、必要なメモリ使用量が2倍になる可能性があります

于 2010-08-25T08:34:32.050 に答える
0

それほど多くのビットマップをメモリにロードすることはできません。

制限数のビットマップをメモリにロードしたり、他の画像を表示する必要がある場合にロードしたりできます。

ビットマップのrecycle()メソッドを使用してメモリを解放し、新しいビットマップを作成できます。GCがガベージコレクションを行うのを待つ場合、メモリはすでに十分ではありません。

重要な点は、ビューに表示されていないときに、あまり多くのビットマップとrecycle()をロードしないことです。

于 2010-09-03T10:29:10.683 に答える
-1

私がモバイルプラットフォームで作業していた最後の会社に戻ると、かなり深刻なパフォーマンスの問題が発生していました。かなりの量の調査を行いましたが、一般的に、すべてが遅くなり、理由を特定するのに苦労していることがわかりました。最終的に、私たちはチップセットベンダーに、物事が遅くなっている理由について助けを求めました。しばらくすると、彼らは「あなたはあまりにも多くのコードを実行している」という答えを返しました。

それには確かな真実があります。

そして、同様の答えがおそらくここで適切です:あなたはあまりにも多くのメモリを使用しています。

使用しているビットマップの数またはサイズを減らす必要があります。

于 2010-08-25T08:37:28.487 に答える