I want to keep my background threads and my views completely seperated, therefore I use threads and a bus system (actually I use a job manager, the one from here: https://github.com/path/android-priority-jobqueue). For a better user experience, I cache already calculated or loaded data in a LruCache
. I've written a wrapper for making it thread safe. Every work that has to be done in the background is identified by a tag.
I keep track of working threads in an own singleton class.
My threads work like following:
- put the tag of the work into a list in a singleton class => meaning, work will be done
- do work
- save result in cache
- post an event to the bus
- remove tag from the list of the singleton class => meaning, work has been done
I use this system like following, when a fragment is resumed:
- register on bus
- check cache for an existing result
- use cached data or check if a thread is calculating the desired data by checking the tag in the singleton class's list
- if a thread is working on the desired data, wait for it, otherwise, start a new thread
I think, this is prone to one race conditions:
- Thread finishes and posts it result to the bus
- => fragment is not registered yet because it's not resumed
- => Event will not be delivered but cached only
- => fragment get's resumed
- => fragment asks Status of work and sees that a thread is working on the desired data and does not start a new thread
- => thread clears the working state for the desired data
=> fragment will not receive it's data
How can I solve that problem? If I consider two independent threads, this race condition is possible. On andoroid, the thread will post on the main thread ALWAYS, does this effect my problem? I'm not sure about that actually...
Here's my main thread otto bus for completeness:
// defined in my application
private static final MainThreadBus BUS = new MainThreadBus(new Bus(ThreadEnforcer.ANY));
// the bus class
public class MainThreadBus extends Bus
{
private final Bus mBus;
private final Handler mHandler = new Handler(Looper.getMainLooper());
public MainThreadBus(final Bus bus)
{
if (bus == null)
throw new NullPointerException("ERROR: bus == null");
mBus = bus;
}
@Override
public void register(Object obj)
{
mBus.register(obj);
}
@Override
public void unregister(Object obj)
{
mBus.unregister(obj);
}
@Override
public void post(final Object event)
{
if (Looper.myLooper() == Looper.getMainLooper())
{
mBus.post(event);
}
else
{
mHandler.post(new Runnable()
{
@Override
public void run()
{
mBus.post(event);
}
});
}
}
}
0 comments:
Post a Comment