英文:
Garbage Collection issue with infinite ImageViews
问题
代码正在以固定速率创建ImageViews(目标的图像),这些图像在UI上显示,并将在3秒后或单击后从主布局中删除。问题是垃圾回收在创建这些ImageViews时会导致延迟,从而延迟了后续ImageViews的创建。
这是一个创建ImageView的调用示例,在while循环中进行:
//对于每个出现率值的倍数,将生成一个目标
while (currentTimeOfGame % spawnRate == 0) {
createTarget(context);
//相对于游戏开始时间更新游戏的当前时间
currentTimeOfGame = ((new Date().getTime()) - startTime);
}
然后在createTarget()
中,我创建了一个扩展了ImageView的Target类的实例:
//用于创建目标的方法
public void createTarget(Context context) {
//主相对布局的尺寸
int width = getWidth();
int height = getHeight();
//实例化要生成的目标
final Target target = new Target(context);
target.setParams(width, height);
}
在被单击后,它会从布局中删除。这可以正确地删除目标,但在一些目标之后,垃圾收集器引起的延迟会导致延迟,从而延迟了下一个生成。
Runnable thread = () -> target.setOnClickListener(v -> {
Handler subMainHandler = new Handler(context.getMainLooper());
Runnable subThread = new Runnable() {
@Override
public void run() {
target.setVisibility(View.INVISIBLE);
removeView(target);
target.setImageDrawable(null);
spawnTarget.interrupt();
}
};
subMainHandler.post(subThread);
});
这是Target类的定义:
public class Target extends androidx.appcompat.widget.AppCompatImageView {
public long spawnTime = new Date().getTime();
public Target(Context context) {
super(context);
this.setBackgroundResource(R.drawable.target_shape);
this.setVisibility(View.VISIBLE);
}
public void setParams(int width, int height) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Random r = new Random();
this.setLayoutParams(params);
int randomLeftMargin = r.nextInt(width);
int randomTopMargin = r.nextInt(height);
params.leftMargin = randomLeftMargin;
params.topMargin = randomTopMargin;
this.setLayoutParams(params);
}
}
这是目标的XML文件:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/PrimaryBlue" />
<stroke
android:width="1dp"
android:color="@color/LightGrey" />
<size
android:width="30dp"
android:height="30dp" />
</shape>
如何防止垃圾收集器导致长达300毫秒的延迟?这是否与每次创建新目标时都创建Target类的新实例有关?
编辑:
处理每个目标生命周期的3秒计时器的代码。如果目标在3秒内未被点击,则会将其移除;每次都会减少一个生命值,一旦生命值为零,则不再生成目标。延迟的问题是由以下代码块引起的,其中玩家仍然有生命,但目标在被点击后被移除,因此这个线程会被点击事件中的onClickLister
中断。
Thread handleTarget = new Thread() {
public void run() {
// 更新目标的位置以确保它不会与边缘重叠
Runnable setTargetParamsThread = () -> {
int targetWidth = target.getMeasuredWidth();
int targetHeight = target.getMeasuredHeight();
if (targetHeight != 0 && targetWidth != 0) {
target.setParams(width, height, targetWidth, targetHeight);
target.setVisibility(View.VISIBLE);
}
};
mainHandler.post(setTargetParamsThread);
while (true) {
// 检查目标是否在3秒内未被点击
if (new Date().getTime() > target.spawnTime + 3000) {
if (lives == 0) {
// 游戏结束
// ...
Thread.currentThread().interrupt();
} else if (target.getVisibility() == View.VISIBLE) {
// 移除目标并减少生命值
// ...
Thread.currentThread().interrupt();
}
break;
}
}
}
};
英文:
My code is creating ImageViews (image of a target) at a set rate that are displayed on the UI and will be removed from the main layout after 3 seconds or once it has been clicked on. The problem is the garbage collection causes delay when I create these ImageViews, which delays the creation of further ImageViews
Here I spawn call for the ImageView to be created in a while loop:
//for each multiple of the spawn rate value, a target will be spawned
while (currentTimeOfGame % spawnRate == 0) {
createTarget(context);
//update the time of game relative to the game's start time
currentTimeOfGame = ((new Date().getTime()) - startTime);
}
And then in createTarget() I create an instance of the Target class which extends ImageView.
//method for creating the targets
public void createTarget(Context context) {
//dimensions of the main relative layout
int width = getWidth();
int height = getHeight();
//instantiate a target to spawn
final Target target = new Target(context);
target.setParams(width, height);
Here it is removed from the layout once it is clicked. This removes the targets fine but after a few of them, it causes delays caused by the garbage collector, which only delays the next spawn.
Runnable thread = () -> target.setOnClickListener(v -> {
Handler subMainHandler = new Handler(context.getMainLooper());
Runnable subThread = new Runnable() {
@Override
public void run() {
target.setVisibility(View.INVISIBLE);
removeView(target);
target.setImageDrawable(null);
// Log.d("target clicked", String.valueOf(currentTimeOfGame));
// Interrupting the thread that tracks the target's timer
spawnTarget.interrupt();
}
};
subMainHandler.post(subThread);
});
This is the class for the Target.
public class Target extends androidx.appcompat.widget.AppCompatImageView {
public long spawnTime = new Date().getTime();
public Target(Context context) {
super(context);
this.setBackgroundResource(R.drawable.target_shape);
this.setVisibility(View.VISIBLE);
}
public void setParams(int width, int height) {
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
Random r = new Random();
this.setLayoutParams(params);
int randomLeftMargin = r.nextInt(width);
int randomTopMargin = r.nextInt(height);
params.leftMargin = randomLeftMargin;
params.topMargin = randomTopMargin;
this.setLayoutParams(params);
}
}
This is the XML file of the target
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@color/PrimaryBlue" />
<stroke
android:width="1dp"
android:color="@color/LightGrey" />
<size
android:width="30dp"
android:height="30dp" />
</shape>
How do I prevent the garbage collector from causing delays up to 300 milliseconds? Is this to do with creating a new instance of the Target class every time I create a new Target?
EDIT:
Code for handling the 3 second timer for each targets life span. a target is removed whenever a target isn't clicked within 3 seconds, after 3 seconds. a life is deducted each time, and once there are 0 lives, no more targets are spawned. The issue with the delay is caused by this block of code where the player still has lives and the target is removed with a click, so this thread is interrupted by the onClickListener.
Thread handleTarget = new Thread() {
public void run() {
//updating the location of the target to ensure it doesn't overlap with the edge
Runnable setTargetParamsThread = () -> {
int targetWidth = target.getMeasuredWidth();
int targetHeight = target.getMeasuredHeight();
if (targetHeight != 0 && targetWidth != 0) {
target.setParams(width, height, targetWidth, targetHeight);
target.setVisibility(View.VISIBLE);
}
};
mainHandler.post(setTargetParamsThread);
while (true) {
//check if the target has reached 3 seconds without being tapped
if (new Date().getTime() > target.spawnTime + 3000) {
if (lives == 0) {
gameOver = true;
//discontinue of the number of lives = 0 as the game is over
target.setClickable(false);
//fade out animation for target on end of game for remaining targets
Animation fadeOut = new AlphaAnimation(1, 0);
fadeOut.setDuration(250);
AnimationSet animFadeOut = new AnimationSet(true);
animFadeOut.addAnimation(fadeOut);
target.setAnimation(animFadeOut);
Handler mainHandler = new Handler(context.getMainLooper());
Runnable thread = () -> removeView(target);
mainHandler.post(thread);
Thread.currentThread().interrupt();
}
//if the target is visible remove it and deduct a life.
else if (target.getVisibility() == View.VISIBLE) {
//remove the target and deduct a life
target.setImageDrawable(null);
Handler mainHandler2 = new Handler(context.getMainLooper());
Runnable thread = () -> removeView(target);
mainHandler2.post(thread);
// Log.d("target removed", String.valueOf(currentTimeOfGame));
lives--;
// Log.v("lives", String.valueOf(gameOver));
//discontinue the thread for this target once it has been removed as it no longer needs to be referenced
Thread.currentThread().interrupt();
}
break;
}
}
}
};
答案1
得分: 0
替换匿名内部类并处理线程中断解决了这个问题。
英文:
Replacing anonymous inner classes and handling Thread interruptions resolved the issue.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论