在run()中,我如何调用方法而不使我的应用程序崩溃(Java/Android)?

在run()中,我如何调用方法而不使我的应用程序崩溃(Java/Android)?,java,android,Java,Android,我想做一个简单的小程序,每秒递增一个数字。在本例中,我实现了一个线程,它应该每秒循环一次,每次循环时向“土豆”添加1。在返回到display方法potatoDisp()之前,它工作正常。由于某种原因,这会导致我的应用程序崩溃。从run()中删除potatoDisp()可以解决此问题,但显示不会随着“土豆”的增加而更新 public int potato = 0; @Override protected void onCreate(Bundle savedInstanceState) {

我想做一个简单的小程序,每秒递增一个数字。在本例中,我实现了一个线程,它应该每秒循环一次,每次循环时向“土豆”添加1。在返回到display方法potatoDisp()之前,它工作正常。由于某种原因,这会导致我的应用程序崩溃。从run()中删除potatoDisp()可以解决此问题,但显示不会随着“土豆”的增加而更新

public int potato = 0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    potatoDisp();
    start();
}

public void potatoDisp() {
    TextView text = (TextView) findViewById(R.id.textView1);
    text.setText("You currently have " + potato + " potatoes");
}

public void start() {
    Thread thread = new Thread(this);
    thread.start();
}

@Override
public void run() {
    while (true) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            return;
        }
        potato++;
        potatoDisp();
    }
}

如果有帮助的话,我是为Android应用程序做这件事的。我尝试过寻找答案,但对于如何正确处理线程,我感到非常困惑。

在后台更新
UI
可能会遇到异常。因为,
potatoDisp()
是从后台
线程调用的
,但该函数会更新
UI
,它会给您带来问题。您需要使用
runOnUiThread()
调用它


类似的东西应该可以使用。

您需要这样一个可运行/处理程序:

private Runnable potatoRun = new Runnable() {
    @Override
    public void run () {
        potatoDisp();
    }
};
然后改变

potatoDisp();
致:


当您不在UI线程上时,无法更新视图。

问题是您试图在主UI线程以外的线程上更新UI(调用
text.setText(…)

虽然我建议使用
TimerTask
而不是调用
Thread.sleep(…)
,但有两种主要方法可以编辑当前代码,使其按预期工作

--使用
处理程序

定义一个
处理程序
类,该类将接受消息并根据需要更新UI。例如:

private final String POTATO_COUNT = "num_potatoes";

Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        int numPotatoes = msg.getData.getInt(POTATO_COUNT);
        mText.setText("You currently have " + numPotatoes + " potatoes");
    }
}
然后,无论您是否在主UI线程上,在要调用处理程序以更新文本视图的代码中,执行以下操作:

Bundle bundle = new Bundle();
bundle.putInt(POTATO_COUNT, potato);

Message msg = new Message();
msg.setData(bundle);
handler.sendMessage(msg);
--调用runOnUiThread(…)


我认为您应该使用异步任务从一个线程更新UI:

哦,那些土豆!发布崩溃日志。为什么要在主活动中重写run方法?你试过在一个单独的线程中运行你的计数器吗?现在不要使用logcat,但将来你应该发布它。这通常会帮助我们更容易地帮助你。看看我的答案,谢谢!这正是我要找的。不客气,很高兴我能帮上忙。很好的资源,@Eric这应该是一个评论。虽然这里可以使用
AsyncTask
,但OP的操作方式应该可以,他们只需要合并
runOnUiThread()
。另外,
AsyncTask
对于计算和更新单个
TextView
来说可能有些过分。但是为什么不使用内置的功能来运行一个线程,该线程将更新用户界面,该界面也会为您处理线程池,并且(希望)不会导致任何应用程序延迟呢?注意:虽然您不太可能遇到更新之间暂停1秒的问题,但此处的runOnUiThread示例(以及在其他解决方案中)包含更新UI的主线程和更新计数器的另一个线程之间的争用条件。
Handler
方法(或者让
potatoDisp
接受马铃薯计数的int值)可以解决这个问题。
private final String POTATO_COUNT = "num_potatoes";

Handler handler = new Handler() {
    public void handleMessage(Message msg) {
        int numPotatoes = msg.getData.getInt(POTATO_COUNT);
        mText.setText("You currently have " + numPotatoes + " potatoes");
    }
}
Bundle bundle = new Bundle();
bundle.putInt(POTATO_COUNT, potato);

Message msg = new Message();
msg.setData(bundle);
handler.sendMessage(msg);
@Override
public void run() {
    while (true) {
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            return;
        }
        potato++;
        runOnUiThread(new Runnable() 
        {
            public void run() 
            {
                potatoDisp();
            }
        }
    }
}