Threads and UI in Android

  • Thread starter Dirk Bruere at NeoPax
  • Start date
D

Dirk Bruere at NeoPax

Part of the problem I have been having with adding data to a listview
stems from the threads I have running. Specifically, I have a thread
that constantly checks for messages coming over the Wifi/LAN. When it
finds one it loads the datagram, then calls a static method from a class
BlinkAPI which calls other BlinkAPI methods which loads the data into
arrays.

So far so good - no problems.
However, if the Android ListView in the UI is to be updated with this
data there is a problem. I cannot go in and do stuff to the ListView
from BlinkAPI or I get a message about "called from wrong thread".

Given that loading up Listviews, adapters etc should be done from the
same UI thread, how best to put a "break" between my LAN thread and the
UI thread?
 
D

Dirk Bruere at NeoPax

Part of the problem I have been having with adding data to a listview
stems from the threads I have running. Specifically, I have a thread
that constantly checks for messages coming over the Wifi/LAN. When it
finds one it loads the datagram, then calls a static method from a class
BlinkAPI which calls other BlinkAPI methods which loads the data into
arrays.

So far so good - no problems.
However, if the Android ListView in the UI is to be updated with this
data there is a problem. I cannot go in and do stuff to the ListView
from BlinkAPI or I get a message about "called from wrong thread".

Given that loading up Listviews, adapters etc should be done from the
same UI thread, how best to put a "break" between my LAN thread and the
UI thread?

It would seem the answer is in here somewhere
http://developer.android.com/resources/articles/painless-threading.html
 
M

markspace

This seems analogus to Java Swing & EDT. Use the Activity.runOnUiThread
method to send processing to the UI thread, so you won't get this message.

Given:

some other thread
|
|
V
public void someMethod( Params.... ) {
// do set up

// do this on UI thread

// do clean up
}

Transform this to:

some other thread
|
|
V
public void someMethod( Params.... ) {
// do set up

Activity.runOnUiThread( new Runnable() {
public void run() {
// do this on UI thread
}
} );

// do clean up
}

To run the center bit of code on the UI thread. Note that you are
executing code asynchronously and the "clean up" will likely happen
before the UI thread bit. Something to be aware of.
 
M

markspace

Seems like AsyncTask is the way to go: it automatically divides up execution
between a background thread and the UI thread, and takes care of all the
synchronization between the two for you.

How much more painless can you get? :)



Given that the OP want's to "constantly [check] for messages" I think
the way he's doing it now is fine. runOnUiThread() does the
synchronization that he needs, and it seems cleaner than trying to wrap
his deamon in an AsyncTask object and constantly call publishProgress()
whenever he gets a packet.

Modern threading is getting sophisticated, and one sophisticated thing
to do is to limit the number of threads so as to not overwhelm the OS.
Limited thread pools are used for this purpose. I don't know how
AsynchTask is implemented, but if it uses a thread pool, you could
easily starve your own app of threads for AsynchTask by permanently
capturing too many AsynchTask threads, which is what the OP's task would do.

"Long running" tasks relative to the UI response time go in AsynchTask.
"Really long running" tasks, or permanent tasks like the OP's little
network daemon, go in their own private thread. Seems safest that way.
 
J

John B. Matthews

Seems like AsyncTask is the way to go: it automatically divides up execution
between a background thread and the UI thread, and takes care of all the
synchronization between the two for you.

How much more painless can you get? :)

Given that the OP want's to "constantly [check] for messages" I think
the way he's doing it now is fine. runOnUiThread() does the
synchronization that he needs, and it seems cleaner than trying to
wrap his deamon in an AsyncTask object and constantly call
publishProgress() whenever he gets a packet.

Modern threading is getting sophisticated, and one sophisticated
thing to do is to limit the number of threads so as to not overwhelm
the OS. Limited thread pools are used for this purpose. I don't know
how AsynchTask is implemented, but if it uses a thread pool, you
could easily starve your own app of threads for AsynchTask by
permanently capturing too many AsynchTask threads, which is what the
OP's task would do.

"Long running" tasks relative to the UI response time go in
AsynchTask. "Really long running" tasks, or permanent tasks like the
OP's little network daemon, go in their own private thread. Seems
safest that way.

I have no practical experience on android, but I was struck by the
similarity between AsyncTask and SwingWorker:

<http://developer.android.com/reference/android/os/AsyncTask.html>
<http://download.oracle.com/javase/6/docs/api/javax/swing/SwingWorker.htm
l>

It appears to be of more recent vintage, and it supports either a
SERIAL_EXECUTOR or THREAD_POOL_EXECUTOR, with certain caveats for the
latter.
 
D

Dirk Bruere at NeoPax

Seems like AsyncTask is the way to go: it automatically divides up
execution
between a background thread and the UI thread, and takes care of all the
synchronization between the two for you.

How much more painless can you get? :)



Given that the OP want's to "constantly [check] for messages" I think
the way he's doing it now is fine. runOnUiThread() does the
synchronization that he needs, and it seems cleaner than trying to wrap
his deamon in an AsyncTask object and constantly call publishProgress()
whenever he gets a packet.

Modern threading is getting sophisticated, and one sophisticated thing
to do is to limit the number of threads so as to not overwhelm the OS.
Limited thread pools are used for this purpose. I don't know how
AsynchTask is implemented, but if it uses a thread pool, you could
easily starve your own app of threads for AsynchTask by permanently
capturing too many AsynchTask threads, which is what the OP's task would
do.

"Long running" tasks relative to the UI response time go in AsynchTask.
"Really long running" tasks, or permanent tasks like the OP's little
network daemon, go in their own private thread. Seems safest that way.

Currently I have this:

public class BlinkDataThread extends Thread
{
int length = Constants.PACKET_LENGTH;
byte[] receiveBuffer = new byte[length];
DatagramSocket socket;
DatagramPacket packet;

public void run()
{
try
{
DatagramSocket ds = new DatagramSocket(Constants.LOCAL_PORT);
DatagramPacket incoming = new DatagramPacket(receiveBuffer,
receiveBuffer.length);
incoming.setLength(length);
String packetStr=new String(receiveBuffer, "UTF-8");

while(true) //Run this as an endless loop
{
ds.setReceiveBufferSize(receiveBuffer.length);
ds.receive(incoming);
packetStr = new String(receiveBuffer, 0,
incoming.getLength(), "UTF-8");
if (packetStr != null) BlinkAPI.updateIncomingData(packetStr);
}
} catch (IOException e1) {}
}

}

Where linkAPI.updateIncomingData(packetStr); is the offending bit since
it triggers updates on the UI thread.

That would be where I use runOnUiThread()?
 
L

Lawrence D'Oliveiro

Where linkAPI.updateIncomingData(packetStr); is the offending bit since
it triggers updates on the UI thread.

That would be where I use runOnUiThread()?

OK, if it’s running in an endless loop, I guess that’s not suitable for an
AsyncTask.

I believe the recommended mechanism for posting actions back to the UI
thread is via a Handler
<http://developer.android.com/reference/android/os/Handler.html>: create
this from the UI thread, pass it to the background thread, and the latter
can use the post method to send back a Runnable to be executed.

By the way, note that faceless background threads can be killed at any time.
 
D

Dirk Bruere at NeoPax

In message<[email protected]>, Dirk Bruere at NeoPax
wrote:

It would seem the answer is in here somewhere
http://developer.android.com/resources/articles/painless-threading.html

Seems like AsyncTask is the way to go: it automatically divides up
execution
between a background thread and the UI thread, and takes care of all the
synchronization between the two for you.

How much more painless can you get? :)



Given that the OP want's to "constantly [check] for messages" I think
the way he's doing it now is fine. runOnUiThread() does the
synchronization that he needs, and it seems cleaner than trying to wrap
his deamon in an AsyncTask object and constantly call publishProgress()
whenever he gets a packet.

Modern threading is getting sophisticated, and one sophisticated thing
to do is to limit the number of threads so as to not overwhelm the OS.
Limited thread pools are used for this purpose. I don't know how
AsynchTask is implemented, but if it uses a thread pool, you could
easily starve your own app of threads for AsynchTask by permanently
capturing too many AsynchTask threads, which is what the OP's task would
do.

"Long running" tasks relative to the UI response time go in AsynchTask.
"Really long running" tasks, or permanent tasks like the OP's little
network daemon, go in their own private thread. Seems safest that way.

Currently I have this:

public class BlinkDataThread extends Thread
{
int length = Constants.PACKET_LENGTH;
byte[] receiveBuffer = new byte[length];
DatagramSocket socket;
DatagramPacket packet;

public void run()
{
try
{
DatagramSocket ds = new DatagramSocket(Constants.LOCAL_PORT);
DatagramPacket incoming = new DatagramPacket(receiveBuffer,
receiveBuffer.length);
incoming.setLength(length);
String packetStr=new String(receiveBuffer, "UTF-8");

while(true) //Run this as an endless loop
{
ds.setReceiveBufferSize(receiveBuffer.length);
ds.receive(incoming);
packetStr = new String(receiveBuffer, 0, incoming.getLength(), "UTF-8");
if (packetStr != null) BlinkAPI.updateIncomingData(packetStr);
}
} catch (IOException e1) {}
}

}

Where linkAPI.updateIncomingData(packetStr); is the offending bit since
it triggers updates on the UI thread.

That would be where I use runOnUiThread()?

Or not.
That BlinkAPI.updateIncomingData(packetStr) eventually gets to call this
from the Data class

public static void setRadioTitleAdapterListView()
{
radioLV.setAdapter(radioTitleAdapter);
radioTitleAdapter.notifyDataSetChanged();
radioLV.setVisibility(VISIBLE);
}
It is really this I need to execute in the UI thread.
Is there some way of wrapping that method (amongst several of the same
type) as a message to the UI thread telling it to execute
Data.setRadioTitleAdapterListView() from there?

[I can send the packet received in the BlinkDataThread but that rather
defeats the idea since all the heavy duty processing occurs after it is
picked up.]
 
M

markspace

Or not.
That BlinkAPI.updateIncomingData(packetStr) eventually gets to call this
from the Data class

public static void setRadioTitleAdapterListView()
{


I don't like the idea that you're suggesting here. Hard baking this
method so it always runs on the UI thread sounds bad. You want to keep
methods flexible so they can be used in a variety of contexts. Too much
specialized behavior results in classes that require too many support
classes or a specialized environment to function at all.

Better to do it where you had it at first. You're already processing
the packet and making a string. It seems fine to allow your Blink
routine to process the resulting string on the UI thread. You don't
have to be manic about removing every last cycle from the UI thread,
just keep long tasks (like IO, or sorting or searching) away from it.

Also, in the code you posted, you set up packetStr once outside of the
loop, then never use that value, so I'm moving packetStr inside the loop
and removing the unused assignment.

And I think you mean !packetStr.equals( "" ), not packetStr != null. It
isn't possible to get null from a constructor.


public void run()
{
try
{
DatagramSocket ds = new DatagramSocket(Constants.LOCAL_PORT);
DatagramPacket incoming = new DatagramPacket(
receiveBuffer, receiveBuffer.length);
incoming.setLength(length);
// not used String packetStr=new String(receiveBuffer, "UTF-8");

while(true) //Run this as an endless loop
{
ds.setReceiveBufferSize(receiveBuffer.length);
ds.receive(incoming);
final String packetStr = new String(receiveBuffer, 0,
incoming.getLength(), "UTF-8");
if( !packetStr.equals( "" ) ) {
Activity.runOnUiThread( new Runnable() {
public void run() {
BlinkAPI.updateIncomingData(packetStr);
}
} );
}
} catch (IOException e1) {
// you really must log errors if you find them
// honestly, you'll be happy you did.
}
}
}

At least we're doing things now that look like actual Java programming.
 
D

Dirk Bruere at NeoPax

I don't like the idea that you're suggesting here. Hard baking this
method so it always runs on the UI thread sounds bad. You want to keep
methods flexible so they can be used in a variety of contexts. Too much
specialized behavior results in classes that require too many support
classes or a specialized environment to function at all.

Better to do it where you had it at first. You're already processing the
packet and making a string. It seems fine to allow your Blink routine to
process the resulting string on the UI thread. You don't have to be
manic about removing every last cycle from the UI thread, just keep long
tasks (like IO, or sorting or searching) away from it.

Also, in the code you posted, you set up packetStr once outside of the
loop, then never use that value, so I'm moving packetStr inside the loop
and removing the unused assignment.

And I think you mean !packetStr.equals( "" ), not packetStr != null. It
isn't possible to get null from a constructor.


public void run()
{
try
{
DatagramSocket ds = new DatagramSocket(Constants.LOCAL_PORT);
DatagramPacket incoming = new DatagramPacket(
receiveBuffer, receiveBuffer.length);
incoming.setLength(length);
// not used String packetStr=new String(receiveBuffer, "UTF-8");

while(true) //Run this as an endless loop
{
ds.setReceiveBufferSize(receiveBuffer.length);
ds.receive(incoming);
final String packetStr = new String(receiveBuffer, 0,
incoming.getLength(), "UTF-8");
if( !packetStr.equals( "" ) ) {
Activity.runOnUiThread( new Runnable() {
public void run() {
BlinkAPI.updateIncomingData(packetStr);
}
} );
}
} catch (IOException e1) {
// you really must log errors if you find them
// honestly, you'll be happy you did.
}
}
}

At least we're doing things now that look like actual Java programming.

:)

BTW, do you any kind of feel for how long it would take to load a
ListView (and adapter/array) with (say) 1000 items comprising about
100kB of data?
 
M

markspace

BTW, do you any kind of feel for how long it would take to load a
ListView (and adapter/array) with (say) 1000 items comprising about
100kB of data?


Here's a different sort of question: do you know of any users who are
actually going to use a list view with 1000 items in it?

Most UIs implement some sort of pagination and load when the user is
ready for the next batch. 10-50 at a time is normal.
 
D

Dirk Bruere at NeoPax

Here's a different sort of question: do you know of any users who are
actually going to use a list view with 1000 items in it?
Yes

Most UIs implement some sort of pagination and load when the user is
ready for the next batch. 10-50 at a time is normal.

Well, there will be a couple of buttons to jump by 10% and 1% through
the list
 
M

markspace



Seriously? That's crazy.

I'd just load the 1000, then check the response. (You know, measure
performance?) If it's too long, split the load into groups of 50 or 100
or so, or whatever gives better updates and responsiveness for the UI.
 
D

Dirk Bruere at NeoPax

Seriously? That's crazy.

List of 1000 videos, in alphabetical order
I'd just load the 1000, then check the response. (You know, measure
performance?) If it's too long, split the load into groups of 50 or 100
or so, or whatever gives better updates and responsiveness for the UI.

I will do, but I don't have the real database to hand.
I've tested it with 85 and it seems to take about 0.2 seconds, which is
just a guess.
 
M

markspace

OK, if it’s running in an endless loop, I guess that’s not suitable for an
AsyncTask.

I believe the recommended mechanism for posting actions back to the UI
thread is via a Handler
<http://developer.android.com/reference/android/os/Handler.html>: create
this from the UI thread, pass it to the background thread, and the latter
can use the post method to send back a Runnable to be executed.


I don't like this idea. I'd bet that the UI thread already has a
handler; it seems the intelligent thing to do. And I'd bet too that the
handler for the UI is publicly available, in some publicly documented
API. And I'll further suppose that they called the public method to
access the UI handler "runOnUiThread".

So don't do this, because you're just reinventing a perfectly good wheel.
 
D

Dirk Bruere at NeoPax

Listing them all, instead of allowing some sort of pagination, is a
horrible idea.
Well, its a scrolling list.
You can jump through it by tens or hundreds.
1000 is also the expected practical max we will encounter. Most systems
will have in the low hundreds
 
D

Dirk Bruere at NeoPax

I should clarify my previous statement. It'll work if you're not using
the stock Android list control. I use K-9 Mail on my Android phone, and
it connects to my IMAP server which has dozens of folders (probably at
least 100) - and the list is manageable with 100-200 items. I would not
want to scroll through 1000+ items, it'd take forever.

The min spec is a Tablet, Tegra 2, 512MB RAM, 1024x600, 10"
Well, that's different. "low hundreds" should be manageable.

Anyone with more than a 1000 or so CDs, DVDs, video clips etc will have
to wait for 2.0
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,579
Members
45,053
Latest member
BrodieSola

Latest Threads

Top