gpt4 book ai didi

Android Surfaceview 线程和内存泄漏

转载 作者:塔克拉玛干 更新时间:2023-11-02 18:56:53 41 4
gpt4 key购买 nike

我在 android 中创建游戏,我注意到该游戏存在内存泄漏。我设法将内存泄漏隔离到一个较小的应用程序中,这样我就可以很好地了解如何解决它。

该应用程序为其 View 使用表面 View ,并附加了一个线程,以便将所有绘图绘制到屏幕上。当我开始一项新 Activity 并关闭我当前正在使用的 Activity 时,就会发生内存泄漏。当我在我的测试应用程序上进行内存转储时,我可以看到这一点,因为它所做的只是打开和关闭一个 Activity ( Activity a -> Activity b -> Activity a)。关于如何解决这个问题,我有点想不通了,因为我试图让我对 View (在线程内)创建的所有引用都无效,当我销毁 View 时,我尝试从表面 View 中删除回调,而且在 Activity 中,它似乎没有任何区别。

内存泄漏 Activity .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;
}
}

内存泄漏.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, MotionEvent e2, 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;
}
}

测试 Activity .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;
}
}

测试.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 format, int width, 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 h, int oldw, 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, MotionEvent e2, float velocityX, float velocityY) {
return false;
}

@Override
public void onLongPress(MotionEvent e) {}

@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}

@Override
public void onShowPress(MotionEvent e) {}

@Override
public boolean onSingleTapUp(MotionEvent e) {
Intent helpScreenIntent =new Intent(this.context, MemoryLeakActivity.class);
this.context.startActivity(helpScreenIntent);

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

return true;
}
}

--编辑--我对 View 类的 surfaceDestroyed(SurfaceHolder holder) 进行了更改,以便在告知线程停止时将线程必须设置为 null 的 View 。我所做的更改是

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;
}

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

最佳答案

在 onSurfaceCreated 中创建线程时,不应在构造函数中创建新线程。将您的代码与我的示例进行比较:How can I use the animation framework inside the canvas?

关于Android Surfaceview 线程和内存泄漏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7227624/

41 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com