Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/382.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/google-sheets/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何从SurfaceView正确更新Android UI_Java_Android_Multithreading - Fatal编程技术网

Java 如何从SurfaceView正确更新Android UI

Java 如何从SurfaceView正确更新Android UI,java,android,multithreading,Java,Android,Multithreading,因此,我有一个带有文本视图的活动来保存分数,如下所示: public class PlayGameActivity extends Activity { private GameThread mGameThread; private GameView mGameView; private Handler mHandler = new Handler(); @Override public void onCreate(Bundle savedInstan

因此,我有一个带有文本视图的活动来保存分数,如下所示:

public class PlayGameActivity extends Activity {
    private GameThread mGameThread;
    private GameView mGameView;

    private Handler mHandler = new Handler();

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_play_game);

        final TextView scoreView = (TextView) findViewById(R.id.textView2);

        mGameView = (GameView) findViewById(R.id.gameView1);
        mGameThread = mGameView.getThread();

        mHandler.post(new Runnable() {
            @Override
            public void run() {
                if (mGameView != null) {
                    scoreView.setText(mGameThread.getScore());
                }
            }
        });
    }
}
然后在我的GameView中,我将函数声明为:

class GameView extends SurfaceView implements SurfaceHolder.Callback {
    class GameThread extends Thread {
        int score = 0;

        public String getScore(){
            return Integer.toString(score);
        }

        @Override
        public void run() {
            synchronized (mSurfaceHolder) {
                if (something){
                    score++
                }
            }
        }
    }
}
问题是mGameThread.getScore()总是返回0,就好像分数没有更新一样

如果有人有任何煽动,我们将不胜感激。此外,我还从上面的代码片段中剥离了许多不必要的代码。如果您想查看全文,可以在此处查看:


您的处理程序只运行一次
getScore()
,因此您将始终只获取初始值。您应该尝试使用
postDelayed()

正如Thomas提到的,Handler不应以这种方式使用,这里引用了:

处理程序有两个主要用途:(1)将消息和可运行文件安排为将来某个时间点执行;和(2)将要在不同线程上执行的操作排队


它完全符合(1)

您的处理程序只运行一次
getScore()
,因此您将始终只获取初始值。您应该尝试使用
postDelayed()

正如Thomas提到的,Handler不应以这种方式使用,这里引用了:

处理程序有两个主要用途:(1)将消息和可运行文件安排为将来某个时间点执行;和(2)将要在不同线程上执行的操作排队


它完全符合(1)

您还可以从哪里调用
mHandler.post(Runnable)
?您发布的代码将一条消息(来自onCreate)添加到主线程的消息队列中,这没有多大意义。此消息已处理,将打印0,然后就是它。因此,如果您不定期从某个地方调用它,它将不会打印首字母0之后的任何内容

如果您也从其他地方调用了
Handler.post(Runnable)
,那么请确保从正确的位置调用它。每次要更新UI时,必须从
GameThread
调用它。因此,您需要在GameThread中引用
mHandler
。例如,
gameshread
的构造函数是一个很好的地方(我不会将
gameshread
实现为一个内部类,而是实现给每个人自己的类)。一旦
GameThread
引用了
mHandler
,您就可以使用
mHandler.post(Runnable)
来更新您的UI。例如:

    @Override
    public void run() {
        synchronized (mSurfaceHolder) {
            if (something){
                // IMPORTANT: see "important note" at the end of this Answer                          

                mHandler.post(mRunnable); // mRunnable is preinstantiated somewhere
                score++
            }
        }
    }
重要提示:您的
游戏线程
可能使用了一种测量实时性的方法(即,它不会在没有线程的情况下调用无限循环中的所有内容。睡眠(…)。因此,不会过度向
处理程序
发送“更新分数”消息。如果您的游戏是基于回合的(而不是实时的),那么这个问题根本就没有出现


注2::我检查了你的完整代码,你的游戏似乎没有任何FPS规则,即你不使用Thread.sleep(33)或任何类似的东西。因此,如果你的海盗发生冲突,我上面写的解决方案将向你的用户界面发送很多消息(你的分数会在很短的时间内达到一个很高的值--我怀疑这就是你想要的)。事实上,除非冲突很快结束,否则您的
分数
值可能很快就会溢出。因此,我建议您向代码中添加FPS平衡,就像所有游戏一样。

从其他地方调用
mHandler.post(Runnable)
?您发布的代码添加了一条消息(来自onCreate)到主线程的消息队列,这没有多大意义。此消息已处理,将打印0,然后就是它。因此,如果您不定期从某处调用此消息,它将不会打印初始0之后的任何内容

如果您正在调用
Handler.post(Runnable)
也可以从其他地方调用,然后确保从正确的位置调用它。每次要更新UI时,必须从
GameThread
调用它。因此,您需要在GameThread中引用
mHandler
。例如,
GameThread
的构造函数就是一个很好的地方(我不会将
GameThread
实现为一个内部类,而是实现为每个类)。一旦
GameThread
引用了
mHandler
,您就可以使用
mHandler.post(Runnable)
来更新您的UI。例如:

    @Override
    public void run() {
        synchronized (mSurfaceHolder) {
            if (something){
                // IMPORTANT: see "important note" at the end of this Answer                          

                mHandler.post(mRunnable); // mRunnable is preinstantiated somewhere
                score++
            }
        }
    }
重要提示:您的
游戏线程
可能使用了一种测量实时性的方法(即,它不会在没有线程的情况下调用无限循环中的所有内容。睡眠(…)。因此,不会过度向
处理程序
发送“更新分数”消息。如果您的游戏是基于回合的(而不是实时的),那么这个问题根本就没有出现


注2::我检查了你的完整代码,你的游戏似乎没有任何FPS规则,即你不使用Thread.sleep(33)
或任何类似的东西。因此,如果你的海盗发生冲突,我上面写的解决方案将向你的用户界面发送很多消息(你的分数会在很短的时间内达到一个很高的值--我怀疑这就是你想要的)。事实上,除非冲突很快结束,否则您的
分数
值可能很快就会溢出。因此,我建议您在代码中添加FPS平衡,就像所有游戏一样。

有更好的方法更新UI数据,使用事件/侦听器机制

坐在循环线程中不是OOP风格的编程。如果你的应用程序中发生了分数变化,你肯定有一个句柄来检测变化。一旦检测到,用一个简单的setText调用你的textview来更新UI

不要像调用post(..)那样(可能是无意中)过度拥挤UI事件队列堆栈,这会使UI对实际用户交互的响应性降低,尤其是在一段时间内这样做时
     activity.runOnUiThread(Runnable);