我一直试图用开机动画制作一个简单的动态壁纸。所以基本上我的drawable文件夹中有大约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)
答案 0 :(得分:3)
每次绘制画布时,只创建一个位图并重新加载每个png。例如,创建一个简单的例程,将每个图像重新加载到相同的位图分配中。我还建议您将png文件转换为jpg文件,因为png是无损格式。使用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);
答案 1 :(得分:0)
android.graphics.Bitmap.createScaledBitmap(Bitmap.java:340)
表示Android会生成一个新的Bitmap,因为您没有正确使用drawable- * dpi文件夹...这可能会增加所需的内存使用量
答案 2 :(得分:0)
您无法将如此多的位图加载到内存中。
您可以将限制数位图加载到内存中,当需要显示其他图片时。
您可以使用位图的recycle()方法释放一些内存,并创建新的位图。 如果等待GC进行垃圾回收,那么内存已经不够了。
关键是在视图中不显示时不要加载太多位图和循环()。
答案 3 :(得分:-1)
回到我上一家在移动平台上工作的公司,我们遇到了一些相当严重的性能问题。我们做了相当多的调查,但我们通常看到一切都运行缓慢,无法确定原因。最后,我们向芯片组供应商寻求有关运行缓慢的原因的帮助。过了一段时间,他们回答说:“你执行的代码太多了。”
有一定的道理。
类似的答案在这里可能是合适的:你使用的内存太多了。
您只需要减少正在使用的位图的数量或大小。