我创建了一个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次以上,然而,实际的视觉变化将导致CalledFromWrongThreadException
被抛出。不熟悉Java& Android,我坚持为什么会发生这种情况。
我注意到,当电话和电话之间的时间间隔稍长时,会发生崩溃。如果对TextOutputWrapper(String)
的调用很快就会发生,那么它就可以了。例如,这个:
int i = 0;
while (i < 200) {
TextOutputWrapper(String.valueOf(i));
i++;
}
工作正常。
看过LogCat后,似乎垃圾收集器释放了一些资源,然后在下次TextOutputWrapper(String)
被调用时,它会崩溃(确切地说Output.SetText(String)
被调用时),尽管我我不确定为什么会导致这个错误。
答案 0 :(得分:0)
我在这里会改变一些事情:
如果要触发UI更新,Handler
非常有用,并且可以从非UI线程(又名“后台”线程)执行此操作)。
在你的情况下,它没有达到这个目的。您直接致电
textFromBGThread.handleMessage(msg);
这不是为你设计的。您应该使用Handler
的方式是在handleMessage(Message)
方法中实现您想要对UI执行的操作。你做到了但是,您不应直接致电handleMessage()
。如果你这样做,那么将从任何线程调用handleMessage()
调用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中,typical coding standards为类之类的东西保留大写名称,而方法以小写字母开头。因此,请将方法重命名为:
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