1

我的应用程序在第一次运行时运行良好。然后当我终止它并再次运行它时,它只会弹出强制关闭窗口。在我强制关闭应用程序后,它再次运行良好。该应用程序在强制关闭之间交替并运行良好。

在应用程序终止之前我是否错过了一些清理工作?

以下是我的一些代码(包含三个类,foobar、actionview 和 actionthread:

foob​​ar.java:

public class foobar extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        setContentView(new ActionView(this));
    }

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

    @Override
    protected void onPause() {
        super.onPause();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }
}

public class ActionView extends SurfaceView implements SurfaceHolder.Callback {

    private ActionThread actionThread;

    public ActionView(Context context) 
    {
        super(context);
        getHolder().addCallback(this);
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) 
    {
        actionThread = new ActionThread(holder,this);
        actionThread.setRunning(true);
        actionThread.start();
        }


    @Override
    public void surfaceDestroyed(SurfaceHolder holder) 
    {
        boolean retry = true;
        while(retry)
        {
            try
            {
                actionThread.join();
                retry=false;
            }
            catch(InterruptedException e)
            {
            }
        }
    }

    protected void displayGameState(Canvas canvas) 
    {
        //code...
        }

        public void updateGameState() 
    {
        //code.. 
         if something happens then
    actionThread.setRunning(false);
    ((Activity)getContext()).finish();

        }
}

ActionThread.java:

public class ActionThread extends Thread {

    private boolean threadIsRunning;
    private SurfaceHolder surfaceHolder;
    private ActionView actionView;
    private final static int MAX_FPS = 50;
    private final static int MAX_FRAME_SKIPS = 5;
    private final static int FRAME_PERIOD = 1000/MAX_FPS;
    private static final String TAG = ActionThread.class.getSimpleName();

    public ActionThread(SurfaceHolder holder, ActionView actionView) {
        this.actionView= actionView;
        surfaceHolder = holder;
    }

    public void setRunning(boolean running)
    {
        threadIsRunning = running;
    }

    @Override
    public void run() 
    {
        long tickCount = 0L;
        long totalFramesSkipped = 0L;
        Canvas canvas = null;
        long beginTime; //time the cycle began
        long timeDiff;  //time it took for cycle to execute
        int sleepTime; //milliseconds to sleep (< 0 if time it took to complete cycle is longer than FRAME_PERIOD
        int framesSkipped; //# of frames being skipped

        while(threadIsRunning)
        {
            tickCount++;
            try
            {
                canvas = surfaceHolder.lockCanvas();
                synchronized(surfaceHolder)
                {
                    beginTime = System.currentTimeMillis();
                    framesSkipped = 0;

                    actionView.updateGameState();
                    actionView.displayGameState(canvas);

                    //calc how long the cycle took
                    timeDiff = System.currentTimeMillis() - beginTime;
                    //calc sleep time
                    sleepTime = (int)(FRAME_PERIOD - timeDiff);

                    if(sleepTime > 0)
                    {
                        //if sleepTime > 0 , didn't fall behind. Try to sleep
                        try
                        {
                            Thread.sleep(sleepTime);
                        }
                        catch(InterruptedException e){}
                    }
                    while(sleepTime < 0 && framesSkipped < MAX_FRAME_SKIPS)
                    {   //fell behind and need to catch up (update without displaying)
                        actionView.updateGameState();
                        sleepTime+=FRAME_PERIOD; //add frame period to check if in next frame
                        framesSkipped++;
                        totalFramesSkipped++;
                    }
                }
            }
            finally
            {
                if(canvas != null)
                {
                    surfaceHolder.unlockCanvasAndPost(canvas);
                }
            }
        }
    }

}

这是 logcat 错误:

05-03 22:47:45.449: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 36955K/38794K, paused 32ms
05-03 22:47:45.488: I/dalvikvm-heap(30596): Clamp target GC heap from 43.427MB to 42.000MB
05-03 22:47:45.488: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37165K/38794K, paused 18ms
05-03 22:47:45.535: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37165K/38794K, paused 29ms
05-03 22:47:45.574: I/dalvikvm-heap(30596): Clamp target GC heap from 43.674MB to 42.000MB
05-03 22:47:45.582: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37418K/38794K, paused 18ms
05-03 22:47:45.613: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37244K/38794K, paused 30ms
05-03 22:47:45.652: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.652: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.684: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 27ms
05-03 22:47:45.699: E/dalvikvm-heap(30596): 258908-byte external allocation too large for this process.
05-03 22:47:45.723: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.723: D/dalvikvm(30596): GC_FOR_MALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.723: D/GraphicsJNI(30596): Waiting for heap walker to free more memory
05-03 22:47:45.723: D/GraphicsJNI(30596): Heap walker done, retry to allocate
05-03 22:47:45.754: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37298K/38794K, paused 27ms
05-03 22:47:45.793: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.793: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.832: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 26ms
05-03 22:47:45.840: E/dalvikvm-heap(30596): 313968-byte external allocation too large for this process.
05-03 22:47:45.871: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.871: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.871: D/GraphicsJNI(30596): Waiting for heap walker to free more memory
05-03 22:47:45.871: D/GraphicsJNI(30596): Heap walker done, retry to allocate
05-03 22:47:45.902: D/dalvikvm(30596): GC_EXTERNAL_ALLOC freed <1K, 43% free 3126K/5447K, external 37551K/38794K, paused 30ms
05-03 22:47:45.910: E/dalvikvm-heap(30596): 313968-byte external allocation too large for this process.
05-03 22:47:45.941: I/dalvikvm-heap(30596): Clamp target GC heap from 43.804MB to 42.000MB
05-03 22:47:45.941: D/dalvikvm(30596): GC_FOR_MALLOC freed 0K, 43% free 3126K/5447K, external 37551K/38794K, paused 17ms
05-03 22:47:45.941: E/GraphicsJNI(30596): VM won't let us allocate 313968 bytes
05-03 22:47:45.957: D/AndroidRuntime(30596): Shutting down VM
05-03 22:47:45.957: W/dalvikvm(30596): threadid=1: thread exiting with uncaught exception (group=0x4001e560)
05-03 22:47:45.965: E/AndroidRuntime(30596): FATAL EXCEPTION: main
05-03 22:47:45.965: E/AndroidRuntime(30596): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.nativeCreate(Native Method)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.createBitmap(Bitmap.java:507)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.createBitmap(Bitmap.java:474)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.graphics.Bitmap.createScaledBitmap(Bitmap.java:379)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.Element.Element.resizeBitmap(Element.java:48)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.Element.Element.<init>(Element.java:31)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.Element.MobileElement.<init>(MobileElement.java:24)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.somecomany.foobar.ActionView.surfaceCreated(ActionView.java:156)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.SurfaceView.updateWindow(SurfaceView.java:543)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.SurfaceView.dispatchDraw(SurfaceView.java:348)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.drawChild(ViewGroup.java:1644)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.View.draw(View.java:6883)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.drawChild(ViewGroup.java:1646)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewGroup.dispatchDraw(ViewGroup.java:1373)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.View.draw(View.java:6883)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.widget.FrameLayout.draw(FrameLayout.java:357)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:2106)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewRoot.draw(ViewRoot.java:1562)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewRoot.performTraversals(ViewRoot.java:1298)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.view.ViewRoot.handleMessage(ViewRoot.java:1911)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.os.Handler.dispatchMessage(Handler.java:99)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.os.Looper.loop(Looper.java:130)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at android.app.ActivityThread.main(ActivityThread.java:3821)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at java.lang.reflect.Method.invokeNative(Native Method)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at java.lang.reflect.Method.invoke(Method.java:507)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:839)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:597)
05-03 22:47:45.965: E/AndroidRuntime(30596):    at dalvik.system.NativeStart.main(Native Method)
05-03 22:47:49.996: I/Process(30596): Sending signal. PID: 30596 SIG: 9
4

2 回答 2

1

从日志来看,您在创建位图时似乎存在内存泄漏,这种情况发生在您有一些大型对象挂起时,可能是在应用程序第二次运行时通过静态数据结构。

另一种变体场景是当您在静态变量中引用 Context 或 Activity 时,这基本上会阻止以前的 Activity 被垃圾收集。

发生这种情况是因为当您在 Android 中“退出”应用程序时,其进程不一定会终止。这样当你再次运行它时,操作系统可以跳过一些耗时的步骤,并且可以更快地启动应用程序。当您保留一些数据以供快速重用时,这很好,当您无意中保留一些(巨大的)数据然后尝试再次重新创建这些数据时,这非常糟糕,这就是事情发展的时候。

于 2012-05-04T03:50:02.683 回答
0

尝试将 Activity 的 LaunchMode 设置为 SingleTop。

并且你应该在Activity onDestroy 时释放资源。祝你好运。

于 2012-05-04T02:58:46.247 回答