Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/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 从错误的线程异常Android调用_Java_Android_Multithreading - Fatal编程技术网

Java 从错误的线程异常Android调用

Java 从错误的线程异常Android调用,java,android,multithreading,Java,Android,Multithreading,我正在尝试创建一个应用程序,当你触摸屏幕时,屏幕顶部会出现一片雪花并慢慢落下。我正在将每个雪花添加到arraylist中,以便使每个雪花落下。这是我的密码: Runnable runable = new Runnable(){ @Override public void run(){ while(true){ letTheSnowFall(); } } }; public void letTheSnowFall()

我正在尝试创建一个应用程序,当你触摸屏幕时,屏幕顶部会出现一片雪花并慢慢落下。我正在将每个雪花添加到arraylist中,以便使每个雪花落下。这是我的密码:

Runnable runable = new Runnable(){
    @Override
    public void run(){
        while(true){
            letTheSnowFall();
        }
    }
};

public void letTheSnowFall(){
    for(int i = 0; i < snowArray.size(); i++){
        snowArray.get(i).setY(snowArray.get(i).getY() + 0.01f);
    }
}

首先,您不能从后台线程更新UI

其次,没有延迟的无限后台线程是非常糟糕的代码

第三,请不要在
onCreate()
中调用
setContentView()
两次。您不需要第二个(
setContentView(layout)

实现这一点的最轻量级方法是使用
postDelayed()
,可在任何
视图
(如
layout
)上找到,以安排在延迟后获得控制权。通过调用
removeCallbacks()
,传入与
postDelayed()
相同的
Runnable
,可以取消
postDelayed()
工作:

(源代码)


在您的情况下,
run()
会更新您的雪花,而不是显示一个
Toast

,如果我正确理解雪花是视图的话。因此,snowArray的类型为
ArrayList
。如果是,则抛出异常,因为您从主线程以外的线程调用
View.setY()
方法。几乎所有与Android GUI框架相关的方法都必须从主线程(执行回调的线程,如
Activity.onCreate()
)调用。

我猜您的
snowArray
包含一系列的实例(或其众多子类之一)?在这种情况下,您试图从非GUI线程修改GUI组件,这是不允许的,因此会抛出一个
调用FromErrorThreadException

“简单”的解决方案是在需要修改UI的任何地方调用。如果您已经在一个单独的线程上完成了一些处理,并且现在准备在GUI上显示结果,那么这将非常有用

但是,您需要进行大量的GUI更新。更糟糕的是,因为您在无限循环中进行更新:
while(true){letTheSnowFall();}
。这件事真的是无限的:它永远不会停止,你的雪将永远持续下降,Y坐标迅速增加,最终溢出。但您不会看到这种情况发生,因为一旦GUI更新,您就会立即再次更新它:没有延迟


不过,你想做的事情要简单得多:你只想让雪落下来。您希望设置雪花视图的动画,从其当前位置开始,向下结束一段距离。Android附带了一些。要更新视图,需要从主线程进行更新。显然,你做错了。您可以将信息抛出主线程并更新它。也许,您可以尝试使用Android构建的线程(AsyncTasks)更新视图,在doInBackGround()上计算结果,并在onPostExecute()方法上发布结果。

如何初始化
snowArray
?您确定可以从
myThread
中访问它吗?您正在调用线程上的绘图(?)代码,该线程不是UI线程,可能正在尝试将雪花添加到窗口,对吗?请尝试将您的
letTheSnowFall()
发布到
活动的
处理程序中,或者使用
runOnUiThread
方法。它们实际上是图像视图,但无论如何,您的方法都不是解决此问题的最佳方法。如果您只想使用Android库,那么我建议实现一个自定义视图(视图的子类),它将包含呈现代码。否则,您应该使用更高级的图形库。Android库太有限了。这样一个库的一个例子是LibGDX,它实际上是一个游戏引擎。那么,在我的情况下,root会是什么,它会是一样的吗?@Cj1m:它可能是一样的,或者任何其他
视图
,比如你的
布局
。我计划在雪离开屏幕时清除它,并增加一点延迟,使它“不那么无限”。不过,你应该看看动画。这会让你的生活更轻松,因为你可以依靠这个框架来管理时间和时间间隔。您还可以使用更高级的功能,如加速器或动画集。此外,安卓系统中的大多数动画都可以通过GPU来完成,从而带来更流畅的体验。这会导致我不得不重写很多应用程序吗?
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    layout = (RelativeLayout) findViewById(R.id.activity_main);

    setContentView(layout);
    layout.setOnClickListener(listener);

    Thread myThread = new Thread(runable);
    myThread.start();
}
/***
  Copyright (c) 2012 CommonsWare, LLC
  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  use this file except in compliance with the License. You may obtain a copy
  of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
  by applicable law or agreed to in writing, software distributed under the
  License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
  OF ANY KIND, either express or implied. See the License for the specific
  language governing permissions and limitations under the License.

  From _The Busy Coder's Guide to Android Development_
    http://commonsware.com/Android
 */

package com.commonsware.android.post;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class PostDelayedDemo extends Activity implements Runnable {
  private static final int PERIOD=5000;
  private View root=null;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    root=findViewById(android.R.id.content);
  }

  @Override
  public void onResume() {
    super.onResume();

    run();
  }

  @Override
  public void onPause() {
    root.removeCallbacks(this);

    super.onPause();
  }

  @Override
  public void run() {
    Toast.makeText(PostDelayedDemo.this, "Who-hoo!", Toast.LENGTH_SHORT)
         .show();
    root.postDelayed(this, PERIOD);
  }
}