java - Handler changing UI causes CalledFromWrongThreadException -
i've created handler
can accessed anywhere within activity , written method make easier call handler:
private handler textfrombgthread = new handler() { @override public void handlemessage (message msg) { // string msg string outputstring = msg.getdata().getstring("output"); // find textview textview output = (textview)findviewbyid(r.id.consoleoutputview); // display output log.i("textoutput","about 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); }
so can called background thread with:
textoutputwrapper("attemping connect...");
this work 1+ times, however, actual visual change cause calledfromwrongthreadexception
thrown. being new java & android, i'm stuck on why happening.
i have noticed crash tends happen when there's longer time period between calls & if calls textoutputwrapper(string)
happening after 1 another, works. example, this:
int = 0; while (i < 200) { textoutputwrapper(string.valueof(i)); i++; }
works fine.
having looked @ logcat, seems garbage collector frees resources , next time textoutputwrapper(string)
called, crashes (when output.settext(string)
called, precise), although i'm not sure why cause error.
there's few things i'd change here:
using handler
a handler
useful if want trigger ui update, , non-ui thread (aka "background" thread).
in case, it's not serving purpose. directly calling
textfrombgthread.handlemessage(msg);
it's not designed that. way supposed use handler
implement want done ui in handlemessage(message)
method. did that. but, shouldn't directly call handlemessage()
. if that, handlemessage()
called whatever thread invokes textoutputwrapper()
. if that's background thread, that's wrong.
what want call handler's sendmessage(message) method (or 1 of other available variants). sendmessage()
put message in thread-safe queue, processed on main thread. main thread invoke handler's handlemessage()
, passing queued message, , allowing safely change ui. so, change textoutputwrapper()
use this:
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 conventions
this code bit hard read, experienced java developer. in java, typical coding standards reserve upper case names things classes, while methods start lower case letters. so, please rename method to:
private void textoutputwrapper (string outputtext);
or, better yet, since in fact method, , not wrapper, per se, rename
private void outputtext(string text);
safe threading alternatives
finally, might recommend if want method allows safely modify ui thread, use technique. don't find handler
easy use beginners.
private void outputtext(final string outputstring) { runonuithread(new runnable() { @override public void run() { // find textview textview output = (textview)findviewbyid(r.id.consoleoutputview); // display output log.i("textoutput","about display message: " + outputstring); output.settext(output.gettext() + outputstring); log.i("textoutput","message displayed"); } }); }
runonuithread()
method available in every activity
.
i'll point general docs on understanding threading in android:
http://www.vogella.com/articles/androidbackgroundprocessing/article.html
http://android-developers.blogspot.com/2009/05/painless-threading.html
Comments
Post a Comment