我在

android中创建一个游戏,我注意到游戏有内存泄漏.我设法将内存泄漏隔离到一个较小的应用程序,以便我可以看到很好的尝试和解决,如何解决它.

该应用程序使用一个surfaceview作为其视图,并附加一个线程,以便完成所有绘图到屏幕.当我开始一个新活动并关闭我当前正在使用的活动时,会发生内存泄漏.当我在我的测试应用程序上执行内存转储时,我可以看到这一点,因为它只是打开并关闭一个活动(活动a – >活动b – >活动a).我有点想法如何解决这个问题,因为iv尝试将我创建的所有引用归零(在线程内),iv尝试在我销毁视图时从surfaceview中删除回调,并且在活动中,它似乎没有任何区别.

MemoryLeakActivity.java

package memory.leak;

import memory.leak.view.MemoryLeak;

import android.app.Activity;

import android.os.Bundle;

public class MemoryLeakActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(new MemoryLeak(this));

}

}

MemoryLeakViewThread.java

package memory.leak.thread;

import memory.leak.view.MemoryLeak;

import android.view.SurfaceHolder;

import android.graphics.Canvas;

public class MemoryLeakViewThread extends Thread {

private MemoryLeak view;

private boolean run =false;

public MemoryLeakViewThread(MemoryLeak view) {

this.view =view;

}

public void setRunning(boolean run) {

this.run =run;

}

@Override

public void run() {

Canvas canvas =null;

SurfaceHolder holder =this.view.getHolder();

while(this.run) {

canvas =holder.lockCanvas();

if(canvas !=null) {

this.view.onDraw(canvas);

holder.unlockCanvasAndPost(canvas);

}

}

holder =null;

this.view =null;

}

}

MemoryLeak.java

package memory.leak.view;

import memory.leak.TestActivity;

import memory.leak.thread.MemoryLeakViewThread;

import android.app.Activity;

import android.content.Context;

import android.content.Intent;

import android.graphics.Canvas;

import android.graphics.Color;

import android.view.GestureDetector;

import android.view.MotionEvent;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

import android.view.GestureDetector.OnGestureListener;

public class MemoryLeak extends SurfaceView implements SurfaceHolder.Callback,OnGestureListener {

private GestureDetector gesture;

private MemoryLeakViewThread vThread;

private Context context;

public MemoryLeak(Context context) {

super(context);

this.getHolder().addCallback(this);

this.vThread =new MemoryLeakViewThread(this);

this.gesture =new GestureDetector(this);

this.context =context;

}

public void surfaceChanged(SurfaceHolder holder,int format,int width,int height) {}

public void surfaceCreated(SurfaceHolder holder) {

if(!this.vThread.isAlive()) {

this.vThread =new MemoryLeakViewThread(this);

this.vThread.setRunning(true);

this.vThread.start();

}

}

public void surfaceDestroyed(SurfaceHolder holder) {

boolean retry = true;

if(this.vThread.isAlive()) {

this.vThread.setRunning(false);

while(retry) {

try {

this.vThread.join();

retry =false;

} catch(Exception ee) {}

}

}

this.vThread =null;

this.context =null;

}

public boolean onTouchEvent(MotionEvent event) {

return this.gesture.onTouchEvent(event);

}

@Override

protected void onSizeChanged(int w,int h,int oldw,int oldh) {

}

@Override

public void onDraw(Canvas canvas) {

canvas.drawColor(Color.WHITE);

}

@Override

public boolean onDown(MotionEvent e) {

return true;

}

@Override

public boolean onFling(MotionEvent e1,MotionEvent e2,float velocityX,float velocityY) {

return false;

}

@Override

public void onLongPress(MotionEvent e) {}

@Override

public boolean onScroll(MotionEvent e1,float distanceX,float distanceY) {

return false;

}

@Override

public void onShowPress(MotionEvent e) {}

@Override

public boolean onSingleTapUp(MotionEvent e) {

Intent helpScreenIntent =new Intent(this.context,TestActivity.class);

this.context.startActivity(helpScreenIntent);

if (this.context instanceof Activity)

((Activity) this.context).finish();

return true;

}

}

TestActivity.java

package memory.leak;

import memory.leak.view.Test;

import android.app.Activity;

import android.os.Bundle;

public class TestActivity extends Activity {

/** Called when the activity is first created. */

@Override

public void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(new Test(this));

}

}

TestViewThread.java

package memory.leak.thread;

import memory.leak.view.Test;

import android.view.SurfaceHolder;

import android.graphics.Canvas;

public class TestViewThread extends Thread {

private Test panel;

private boolean run =false;

public TestViewThread(Test panel) {

this.panel =panel;

}

public void setRunning(boolean run) {

this.run =run;

}

@Override

public void run() {

Canvas canvas =null;

SurfaceHolder holder =this.panel.getHolder();

while(this.run) {

canvas =holder.lockCanvas();

if(canvas !=null) {

this.panel.onDraw(canvas);

holder.unlockCanvasAndPost(canvas);

}

}

holder =null;

this.panel =null;

}

}

Test.java

package memory.leak.view;

import memory.leak.MemoryLeakActivity;

import memory.leak.thread.TestViewThread;

import android.app.Activity;

import android.content.Context;

import android.content.Intent;

import android.graphics.Canvas;

import android.graphics.Color;

import android.view.GestureDetector;

import android.view.MotionEvent;

import android.view.SurfaceHolder;

import android.view.SurfaceView;

import android.view.GestureDetector.OnGestureListener;

public class Test extends SurfaceView implements SurfaceHolder.Callback,OnGestureListener {

private GestureDetector gesture;

private TestViewThread vThread;

private Context context;

public Test(Context context) {

super(context);

this.getHolder().addCallback(this);

this.vThread =new TestViewThread(this);

this.gesture =new GestureDetector(this);

this.context =context;

}

public void surfaceChanged(SurfaceHolder holder,int height) {}

public void surfaceCreated(SurfaceHolder holder) {

if(!this.vThread.isAlive()) {

this.vThread =new TestViewThread(this);

this.vThread.setRunning(true);

this.vThread.start();

}

}

public void surfaceDestroyed(SurfaceHolder holder) {

boolean retry = true;

if(this.vThread.isAlive()) {

this.vThread.setRunning(false);

while(retry) {

try {

this.vThread.join();

retry =false;

} catch(Exception ee) {}

}

}

this.vThread =null;

this.context =null;

}

public boolean onTouchEvent(MotionEvent event) {

return this.gesture.onTouchEvent(event);

}

@Override

protected void onSizeChanged(int w,int oldh) {

}

@Override

public void onDraw(Canvas canvas) {

canvas.drawColor(Color.RED);

}

@Override

public boolean onDown(MotionEvent e) {

return true;

}

@Override

public boolean onFling(MotionEvent e1,MemoryLeakActivity.class);

this.context.startActivity(helpScreenIntent);

if (this.context instanceof Activity)

((Activity) this.context).finish();

return true;

}

}

– 编辑 –

我将视图类更改为其surfaceDestroyed(SurfaceHolder持有者),以便在线程被告知停止时,它将设置线程必须为null的视图.我所做的改变是

public void surfaceDestroyed(SurfaceHolder holder) {

boolean retry = true;

if(this.vThread.isAlive()) {

this.vThread.setRunning(false);

while(retry) {

try {

this.vThread.join();

retry =false;

} catch(Exception ee) {}

}

this.vThread.setRunning(false,null);

}

this.vThread =null;

this.context =null;

this.gesture =null;

}

您还需要将surfaceCreated(SurfaceHolder holder)方法更改为

public void surfaceCreated(SurfaceHolder holder) {

if(!this.vThread.isAlive()) {

this.vThread =new MemoryLeakViewThread();

this.vThread.setRunning(true,this);

this.vThread.start();

}

}

然后在线程类我们需要更改以下内容

public MemoryLeakViewThread() {

}

public void setRunning(boolean run) {

this.run =run;

}

public void setRunning(boolean run,MemoryLeak view) {

this.run =run;

this.view =view;

}

通过这样做似乎解决了问题,现在唯一的问题是线程似乎留在内存中,由于线程类和线程组.但我认为这可能是由于调试器.

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐