2

我创建了一个Handler可以从活动中的任何地方访问的,还编写了一个方法来更容易调用处理程序:

private Handler textFromBGThread = new Handler() {
    @Override
    public void handleMessage (Message msg) {
        // Get the string from the msg
        String outputString = msg.getData().getString("Output");
        // Find the TextView
        TextView Output = (TextView)findViewById(R.id.ConsoleOutputView);
        // Display the output
        Log.i("TextOutput","About to display message: " + outputString);
        Output.setText(Output.getText() + outputString);
        Log.i("TextOutput","Message displayed");
    }
};

private void TextOutputWrapper (String outputText) {
    Message msg = new Message();
    Bundle bndle = new Bundle();
    bndle.putString("Output", "\n" + outputText);
    msg.setData(bndle);
    textFromBGThread.handleMessage(msg);
}

那么这可以从后台线程简单地调用:

TextOutputWrapper("Attemping to connect...");

这将工作 1 次以上,但是,实际的视觉变化会导致 aCalledFromWrongThreadException被抛出。作为 Java 和 Android 的新手,我不知道为什么会发生这种情况。

我注意到,当呼叫之间的时间稍长时,崩溃往往会发生,如果呼叫TextOutputWrapper(String)一个接一个地发生得非常快,那么它就会起作用。例如,这个:

int i = 0;
while (i < 200) {
    TextOutputWrapper(String.valueOf(i));
    i++;
}

工作正常。

查看 LogCat 后,似乎垃圾收集器释放了一些资源,然后在下一次TextOutputWrapper(String)被调用时,它崩溃了(Output.SetText(String)准确地说是在调用时),尽管我不确定为什么会导致这个错误。

4

1 回答 1

0

有几件事我会在这里改变:

使用处理程序

如果您想触发 UI 更新,并且从非 UI 线程也称为“后台”线程)执行此操作, AHandler很有用。

在你的情况下,它没有达到这个目的。你直接打电话

textFromBGThread.handleMessage(msg);

它不是为您设计的。您应该使用的方式Handler是在方法中实现您想要对 UI 执行的操作handleMessage(Message)。你做到了。但是,您不应该直接调用handleMessage(). 如果你这样做, thenhandleMessage()将从任何线程调用TextOutputWrapper()如果那是后台线程,那就错了。

您要做的是调用处理程序的sendMessage(Message)方法(或其他可用变体之一)。 sendMessage()会将您的消息放入线程安全队列中,然后在主线程上进行处理。然后主线程将调用您的处理程序handleMessage(),将排队的消息传回,并允许它安全地更改 UI。所以,TextOutputWrapper()改用这个:

private void TextOutputWrapper (String outputText) {
    Message msg = new Message();
    Bundle bndle = new Bundle();
    bndle.putString("Output", "\n" + outputText);
    msg.setData(bndle);
    textFromBGThread.sendMessage(msg);
}

Java 约定

对于有经验的 Java 开发人员来说,这段代码有点难以阅读。在 Java 中,典型的编码标准为类等事物保留大写名称,而方法以小写字母开头。因此,请将方法重命名为:

private void textOutputWrapper (String outputText);

或者,更好的是,因为这实际上是一种方法,而不是包装器,本身,重命名为类似

private void outputText(String text);

安全线程替代方案

最后,我可能会建议,如果您只是想要一种允许您从任何线程安全地修改 UI 的方法,请使用另一种技术。对于初学者来说,我发现它并不Handler容易使用。

private void outputText(final String outputString) {
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // Find the TextView
            TextView output = (TextView)findViewById(R.id.ConsoleOutputView);
            // Display the output
            Log.i("TextOutput","About to display message: " + outputString);
            output.setText(Output.getText() + outputString);
            Log.i("TextOutput","Message displayed");
        }
    });
}

runOnUiThread()是每个Activity.

我还将向您指出一些有关理解 Android 中的线程的一般文档:

http://www.vogella.com/articles/AndroidBackgroundProcessing/article.html

http://android-developers.blogspot.com/2009/05/painless-threading.html

于 2013-05-13T09:37:40.503 回答