【发布时间】:2018-02-26 11:21:46
【问题描述】:
在 Android Studio 中开发游戏时遇到了一个重大问题。我创建了一个创建单独线程的类。它的目的是成为一个云移动的动画:
package com.example.j9.triqshot;
import android.content.Context;
import android.content.res.Resources;
import android.support.v7.widget.AppCompatImageView;
import android.util.AttributeSet;
import android.view.View;
public class Cloud extends AppCompatImageView {
private int width;
private int height;
private int ScreenWidth;
private int ScreenHeight;
public long X;
public int Y;
public int speed = 1;
private long beginTime;
private long endTime;
private boolean MayMove = true;
private static int framerate = 12;
private Thread threadCloud;
public Cloud(Context context){
super(context);
}
public Cloud(Context context, AttributeSet attrs){
super(context, attrs);
}
public Cloud(Context context, AttributeSet attrs, int defStyle){
super(context, attrs, defStyle);
}
public void setWidth(int width){
this.setMaxWidth(width);
this.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
this.width = this.getMeasuredWidth();
}
public void setHeight(int height){
this.setMaxWidth(height);
this.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
this.height = this.getMeasuredHeight();
}
public void Move(){
ScreenHeight = Resources.getSystem().getDisplayMetrics().heightPixels; //Define screen height
ScreenWidth = Resources.getSystem().getDisplayMetrics().widthPixels; //Define screen width
beginTime = System.currentTimeMillis();
threadCloud = new Thread(new Runnable(){
@Override
public void run() {
while(MayMove) {
endTime = System.currentTimeMillis();
long TimeDifference = endTime - beginTime;
if(TimeDifference >= (1000/framerate)) {
X += (speed * (TimeDifference/(1000/framerate)));
beginTime = endTime;
setXY(X, Y);
}
if(X > ScreenWidth){
X = 0 - width;
}
}
}});
threadCloud.start();
}
private void setXY(float X,float Y) {
this.setX(X);
this.setY(Y);
}
public void stopThread(){
threadCloud.interrupt();
}
}
当我在主活动中创建一个云时,按钮仍然可以工作,但是当我创建多个时,按钮大部分时间都不起作用。
此外,如果按钮有效并且已经发送了转到下一个活动的意图,则会发生错误:
02-26 12:13:59.209 4370-4394/com.example.j9.triqshot E/AndroidRuntime: FATAL EXCEPTION: Thread-4
Process: com.example.j9.triqshot, PID: 4370
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views. at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6891) at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:1083) at android.view.ViewGroup.invalidateChild(ViewGroup.java:5205) at android.view.View.invalidateInternal(View.java:13656) at android.view.View.invalidate(View.java:13620) at android.view.View.invalidateViewProperty(View.java:13740) at android.view.View.setTranslationX(View.java:12848) at android.view.View.setX(View.java:12748) at com.example.j9.triqshot.Cloud.setXY(Cloud.java:87) at com.example.j9.triqshot.Cloud.access$400(Cloud.java:14) at com.example.j9.triqshot.Cloud$1.run(Cloud.java:75) at java.lang.Thread.run(Thread.java:761)
我从来没有遇到过这样的错误,我也不完全理解它的确切含义。
主要活动:
package com.example.j9.triqshot;
import android.content.Intent;
import android.content.res.Resources;
import android.os.CountDownTimer;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ImageView;
public class MainActivity extends AppCompatActivity {
ImageView BG; //Initialize background Image
ImageView GameName; //Initialize GameName Image
ImageView MenuBox; //Initialize MenuBox Image
ImageView MadeBy; //Initialize MadeBy Image
ImageButton playButton; //Initialize play button
ImageButton optionsButton; //Initialize options button
ImageButton shareButton; //Initialize share button
int width; //Initialize screen width
int height; //Initialize screen height
Cloud Cloud1;
Cloud Cloud2;
Cloud Cloud3;
boolean Moving = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
height = Resources.getSystem().getDisplayMetrics().heightPixels; //Define screen height
width = Resources.getSystem().getDisplayMetrics().widthPixels; //Define screen width
BG = (ImageView)findViewById(R.id.BG_MENU); //Assign Background
GameName = (ImageView)findViewById(R.id.GameName); //Assign GameName
MenuBox = (ImageView)findViewById(R.id.MenuBox); //Assign MenuBox
MadeBy = (ImageView)findViewById(R.id.MadeBy); //Assign MadeBy
playButton = (ImageButton)findViewById(R.id.playButton); //Assign playButton
optionsButton = (ImageButton)findViewById(R.id.optionsButton); //Assign OptionsButton
shareButton = (ImageButton)findViewById(R.id.shareButton); //Assign shareButton
Cloud1 = (Cloud)findViewById(R.id.Cloud1);
Cloud2 = (Cloud)findViewById(R.id.Cloud2);
Cloud3 = (Cloud)findViewById(R.id.Cloud3);
correctMenuSizes();
CorrectPositions();
playButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
playButtonClicked();
}
}); //Listen to playButton
optionsButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
optionsButtonClicked();
}
}); //Listen to optionsButton
shareButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
shareButtonClicked();
}
});
Cloud1.Move();
Cloud2.Move();
Cloud3.Move();
}
//Set image sizes
private void correctMenuSizes(){
GameName.setMaxHeight(height/12);
MenuBox.setMaxHeight(height/2);
MadeBy.setMaxWidth(width/3);
playButton.setMaxWidth(width/8);
optionsButton.setMaxWidth(width/8);
shareButton.setMaxWidth(width/8);
Cloud1.setWidth(width/3);
Cloud2.setWidth(width/4);
Cloud3.setWidth(width/3);
//Measurements
Cloud1.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
Cloud2.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
Cloud3.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED);
}
private void CorrectPositions(){
//Cloud startPositions and speed
Cloud1.Y = (height / 10);
Cloud1.X = 0;
Cloud1.speed = 3;
Cloud2.Y = (height / 2);
Cloud2.X = (width / 2);
Cloud2.speed = 2;
Cloud3.Y = (height - (height / 3));
Cloud3.X = (width - (width / 3));
Cloud3.speed = 3;
}
//When clicked on playButton
public void playButtonClicked(){
playButton.setImageResource(R.drawable.play_pressed);
new CountDownTimer(500, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
playButtonTimer();
}
}.start();
}
//Reset the button with a delay of 0,5 seconds
//Go to LevelMenu
public void playButtonTimer(){
playButton.setImageResource(R.drawable.play_normal);
Cloud1.stopThread();
Cloud2.stopThread();
Cloud3.stopThread();
Intent intent = new Intent(this, LevelMenu.class);
startActivity(intent);
}
//When clicked on optionsButton
public void optionsButtonClicked(){
optionsButton.setImageResource(R.drawable.options_pressed);
new CountDownTimer(500, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
optionsButtonTimer();
}
}.start();
}
//Reset the button with a delay of 0,5 seconds
public void optionsButtonTimer(){
optionsButton.setImageResource(R.drawable.options_normal);
//Intent intent = new Intent(this, LevelMenu.class);
//startActivity(intent);
}
//When clicked on shareButton
public void shareButtonClicked(){
shareButton.setImageResource(R.drawable.share_pressed);
new CountDownTimer(500, 1000) {
public void onTick(long millisUntilFinished) {
}
public void onFinish() {
shareButtonTimer();
}
}.start();
}
//Reset the button with a delay of 0,5 seconds
public void shareButtonTimer(){
shareButton.setImageResource(R.drawable.share_normal);
//Intent intent = new Intent(this, LevelMenu.class);
//startActivity(intent);
}
}
我已经尝试搜索类似的问题,但仍然没有结果。
【问题讨论】:
-
错误信息已经告诉你问题是什么
Only the original thread that created a view hierarchy can touch its views.。因此,您正试图从另一个线程更改视图,这在 android 的线程模型中是不允许的。 -
这不是这个问题的重复:stackoverflow.com/questions/5161951/…我已经尝试过这个问题,但没有积极的结果
标签: java android multithreading