I'm re writing an IOS app in android. It's a task I've set to try and learn android.
In android I've being learning about different async messaging options. What I have found so far are:
Callbacks
Broadcasts
Message Handlers
I'm trying to decide which approach is best to suit my purposes. In my IOS application I have 10 screen objects and 1 coordinator object. This is my n-1.
The way my ios currently works is my screen object calls a work method in my coordinator passing itself as a delegate. The coordinator performs some async work and calls various methods on the delegate when the job is done : completed / failed with reason etc.
Multiple screen objects can request work to be done at the same time.
So far my feeling that the callback / message handler approaches in android is more like a 1-1 relationship.
I'm leaning towards using the local broadcast manager. This does seem more like NSNotification than delegate methods but seems made for n-1 relationships.
Is the broadcast manager the best way to achieve n - 1 async work ?
Also are my assumption about the 1-1 relationship of callbacks and handlers correct?
You can indeed use the broadcasts like NSNotification, but I would generally use broadcasts to message between different parts of my App, for example to communicate between a Service and an Activity, rather than within a specific part.
I don't see why you can't do exactly what you do in iOS on android as well. You would have a protocol in iOS defining what functions to call, and you can do the same in Java/Android by using interfaces.
In iOS you would have something like:
doStuffWithObject:(NSObject<SpecialStuff> *)object {}
while in Java you would have:
doStuffWithObject(SpecialStuff object) {}
with SpecialStuff being your protocol or interface.
Because you don't have performSelectorOnBackground in android its a bit more work. Either use Timers, perhaps a separate Thread in combination with Handlers or use ASyncTask depending on what serves you best and how big the asynchronous task is.
ASyncTask is definitely worth looking into.
You could of course also make use of Observer and Observable.
A simple example with an handler and a timer that notifies its listeners of a new time every second (note that the handler is created on the main thread in this case, such that you can send messages back similar to using performSelectorOnMainThread in iOS):
class SomeExample {
private final ArrayList<TimeListener> timeListeners;
private final Handler handler = new Handler();
private final TimeUpdateRunnable timeUpdateRunnable = new TimeUpdateRunnable();
public SomeExampleView {
timeListeners = new ArrayList<TimeListener>();
updateTimer = new Timer("General Update Timer");
TimeUpdateTask timeUpdateTask = new TimeUpdateTask();
updateTimer.scheduleAtFixedRate(timeUpdateTask, (60 * 1000) - (System.currentTimeMillis() % (60 * 1000)), 60 * 1000);
}
public void addTimeListener(TimeListener timeListener) {
timeListeners.add(timeListener);
}
public boolean removeTimeListener(TimeListener timeListener) {
return timeListeners.remove(timeListener);
}
class TimeUpdateTask extends TimerTask {
public void run() {
handler.post(timeUpdateRunnable);
}
}
private class TimeUpdateRunnable implements Runnable {
public void run() {
for (TimeListener timeListener : timeListeners) {
timeListener.onTimeUpdate(System.currentTimeMillis());
}
}
}
}
And my listener interface which is similar to Observer
public interface TimeListener {
void onTimeUpdate(long time);
}
Related
Hey here's an interesting question. I am using in my Android project, lots of sql operations with sqlite. For this matter, I am using thread pool in order of reusing the existing resources. The thread pool look's like this:
final int NUMBER_OF_CORES = Runtime.getRuntime().availableProcessors();
ThreadPoolExecutor threadPoolExecutor= new ThreadPoolExecutor(NUMBER_OF_CORES*2,NUMBER_OF_CORES*2,1L, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(12,true),new PriorityThreadFactory(Process.THREAD_PRIORITY_BACKGROUND),new RejectedThread(context));
public class PriorityThreadFactory implements ThreadFactory {
private final int mThreadPriority;
public PriorityThreadFactory(int threadPriority) {
mThreadPriority = threadPriority;
}
#Override
public Thread newThread(final Runnable runnable) {
Runnable wrapperRunnable = new Runnable() {
#Override
public void run() {
try {
android.os.Process.setThreadPriority(mThreadPriority);
} catch (Throwable t) {
}
runnable.run();
}
};
return new Thread(wrapperRunnable);
}
}
public class RejectedThread implements RejectedExecutionHandler {
MyLogger myLogger;
public RejectedThread(Context context) {
this.myLogger=new MyLogger(RejectedThread.class.getSimpleName(), context);
}
#Override
public void rejectedExecution(Runnable worker, ThreadPoolExecutor executor) {
this.myLogger.info("Execution rejected for: "+worker.toString());
}
}
And also I am creating a new Runnable for every CRUD (Create-Read-Update-Delete) operation that I make in the database (being executed by the thread pool above). Here is the questions, beside the threadpool for sql operations, I would need one more thread pool for executing logger operations, to log system behavior for the rest of my functions that I make. Is there a way to prevent any crush/(insufficient resources) because I am using two or more thread pool executors (allocated separated, using in different purposes and never executing a thread pool executor on another thread pool executor) ?
I think that in general your idea is very good, but your implementation is a bit inefficient.
Try to answer these questions to yourself:
Why do you need two thread pools?
Do you REALLY need two thread pools?
Why do you set CORE size to NUMBER_OF_CORES*2?
Why do you set MAX size to NUMBER_OF_CORES*2?
Do you REALLY need to overwrite threads priorities?
In my experience, none of the above complications are really necessary.
For example, in all my apps I use a single instance of BackgroundThreadPoster class in order to offload work to background threads. The class is very simple:
/**
* A single instance of this class should be used whenever we need to post anything to a (random) background thread.
*/
public class BackgroundThreadPoster {
ExecutorService mExecutorService = Executors.newCachedThreadPool();
public void post(Runnable runnable) {
mExecutorService.execute(runnable);
}
}
Default pre-configured implementation returned by Executors.newCachedThreadPool() works like magic and I've never encountered any need to customize its parameters.
A full tutorial application that uses this approach can be found here: https://github.com/techyourchance/android_mvc_tutorial
Maybe this can work for you too?
My app has activities for the user interaction and a background service which is the only place where the data model is being modified. The background service listens to actions that where made by the user as well as incoming messages from the network. Therefore concurrency issues can arise which I try to prevent by using a handler.
For the event layer I use greenrobots Eventbus.
This is all working well but I wonder if there is a smarter/faster/less code extensive (and therefore less error prone) way to handle this use case?
To be more specific:
Is there a way to ensure serial execution of the onEvent methods
without a handler?
Is there an alternative to having onEvent methods
for each possible event?
Is there a better pattern for what I am
doing here?
This is my approach:
In the oncreate method I do register the service (in case of an activity I do this in onstart)
#Override
public void onCreate() {
super.onCreate();
...
EventBus.getDefault().register(this);
}
And in the onDestroy I do unregister again:
#Override
public void onDestroy() {
super.onDestroy();
....
EventBus.getDefault().unregister(this);
}
Whenever I react to an incoming event I want to ensure serial execution as there can be concurreny issues because there are incoming events from user interactions as well as from other users via networking. So I decided to work with a handler:
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
Object receivedEvent = msg.obj;
if(receivedEvent instanceof EditUser)
{
processEditUserBroadcast((EditUser)receivedEvent);
}
else if(receivedEvent instanceof JoinParty)
{
processJoinPartyBroadcast((JoinParty)receivedEvent);
}
else if(receivedEvent instanceof LeaveParty)
{
processLeavePartyBroadcast();
}
else if(receivedEvent instanceof SendMessage)
{
processSendMessageBroadcast((SendMessage)receivedEvent);
}
else if(receivedEvent instanceof ReceivedMessage)
{
processReceivedMessageBroadcast((ReceivedMessage)receivedEvent);
}
else if(receivedEvent instanceof Reset)
{
processResetBroadcast();
}
else if(receivedEvent instanceof ImageDownloadFinished)
{
processImageDownloadFinishedBroadcast((ImageDownloadFinished)receivedEvent);
}
}
};
return handler;
}
For each event of interest I do have an onEvent method which is doing nothing but passing the event to the handler to ensure serial execution via a small "passToHandler" helper function
public void passToHandler(Handler handler, Object object)
{
Message message = handler.obtainMessage();
message.obj = object;
handler.sendMessage(message);
}
public void onEvent(EditUser editUser)
{
passToHandler(handler,editUser);
}
public void onEvent(JoinParty joinParty)
{
passToHandler(handler,joinParty);
}
public void onEvent(LeaveParty leaveParty)
{
passToHandler(handler,leaveParty);
}
public void onEvent(SendMessage sendMessage)
{
passToHandler(handler,sendMessage);
}
public void onEvent(ReceivedMessage receivedMessage)
{
passToHandler(handler,receivedMessage);
}
public void onEvent(Reset reset)
{
passToHandler(handler,reset);
}
public void onEvent(ImageDownloadFinished imageDownloadFinished)
{
passToHandler(handler,imageDownloadFinished);
}
The "process.." methods are where the "data magic" happens and shouldn´t be relevant for my question.
And of course for each possible event I did create a class which is usually quite slim like this:
public class JoinParty {
private String partyCode;
public JoinParty(String partyCode) {
super();
this.partyCode = partyCode;
}
public String getPartyCode() {
return partyCode;
}
}
Thank you for posting this Matthias! I think you bring up a very important point about thread safety with GreenRobot EventBus that can easily be missed by users of it.
I think you are quite possibly heading down the right path, though I'm new to GreenRobot EventBus and Android (but not Java). If I read the GreenRobot EventBus source code correctly, one other possible benefit to this approach is that post of the SendMessage event to your onEvent() method immediately returns (after calling sendMessage on the Handler) allowing the EventBus to continue posting it to any other subscribers without delay of the actual processing by your class. This may or may not be what you desire though.
With the approach that you have given, the other thing you need to ensure is that if you take an approach like this that there are no other public methods to your class that has all of your onEvent() methods and the methods such as processEditUserBroadcast(). Otherwise, while you have ensured that all of the processing of the events received from the EventBus are actually handled on a single thread (in a serial manner), some other class might call a public method of this class on a different thread and then cause you thread safety issues again.
If you know that you do need to support other public methods on this class, doing what you have done here at least gets all of the onEvent() methods handling onto a single thread (that of the Looper for the thread that creates the Looper from what I read in the doc for the Looper class) and that simplifies things at least some. You may also then need to apply some synchronization to the public methods and all of the other methods such as processEditUserBroadcast() so as to guarantee safe access to the data members of the class from multiple threads if you are going to have other public methods on this class. Alternatively, depending on what those data members are and what your needs are, you might be able to get by with simply making some of them volatile, atomic, or using the concurrent collections, etc. It all depends on what the read and write access needs are and also the needed granularity of those accesses.
Does this help at all? For those that are well versed with Android, Loopers, Handlers, GreenRobot EventBus, etc. have I misspoken at all?
while it is very convenient to use, from my understanding, AsyncTask has two important limitations:
doInBackground of any instances will share the same worker
thread, i.e. one long running AsyncTasks can block all others.
execute, onPostExecute and other "synchronizing" methods must/will always be executed on the UI-thread, i.e. not on the Thread, which wants to start the task.
I ran into trouble, when I tried to reuse some existing AsyncTasks in a background IntentService that are responsible for the client-server communication of my app. The tasks of the service would fight over time in the worker thread with those of the UI activities. Also they would force the service to fall back onto the UI-thread, although that service should perform its work quietly in the background.
How would I go about removing/circumventing these limitations? I basically want to achieve:
A framework that closely resembles AsyncTask (because I need to migrate a lot of critical code there).
Each instance of such a task should run its doInBackground on its own thread instead of a single worker thread for all instances.
Edit: Thx to VinceFR for pointing out this can be achieved by simply calling executeOnExecutor instead of execute.
The callbacks like onPostExecute should be called on the same thread that started the task by calling execute, which should not need to be the UI-thread.
I figure, I'm not the first person to require something like this. Therefore I wonder: Is there already some third-party library that can be recommended to accomplish this? If not, what would be a way to implement this?
Thanks in advance!
The solution looks like this:
All classes that spawn AsyncTasks that might interfere with each other get their own Executor like this one (make that elaborate as you like using thread pools etc.):
private Executor serviceExecutor = new Executor() {
public void execute(Runnable command) {
new Thread(command).start();
}
};
As pointed out by VinceFR you can run an AsyncTask on a given Executor by calling it like this (where payload are the parameters that you would regularly pass to a task):
task.executeOnExecutor(serviceExecutor, payload);
However, this breaks backwards-compatibility to Gingerbread and earlier. Also, if you want to support Honeycomb, you need to make sure, this call happens on the UI thread. Jelly Bean will take care of this automatically.
Now the trickier part: Keeping the service running on its own thread. As many things in Android this seems harder than it needs to be (or maybe I'm lacking some information here). You can't use an IntentService, because that will shut down automatically the first time an AsyncTask takes over and let's the onHandleIntent callback complete.
You need to setup your own thread and event loop on the service:
public class AsyncService extends Service {
private static final String TAG = AsyncService.class.getSimpleName();
private class LooperThread extends Thread {
public Handler threadHandler = null;
public void run() {
Looper.prepare();
this.threadHandler = new Handler();
Looper.loop();
}
}
private LooperThread serviceThread = null;
private Handler serviceThreadHandler = null;
#Override
// This happens on the UI thread
public void onCreate() {
super.onCreate();
}
#Override
// This happens on the UI thread
public int onStartCommand(Intent intent, int flags, int startId) {
this.serviceThread = new LooperThread();
this.serviceThread.start();
while(this.serviceThread.threadHandler == null) {
Log.d(TAG, "Waiting for service thread to start...");
}
this.serviceThreadHandler = this.serviceThread.threadHandler;
this.serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheFirstThingOnTheServiceThread();
}
});
return Service.START_STICKY;
}
// doTheFirstThingOnTheServiceThread
}
No you need to make sure that each time an AsyncTask returns to the UI thread, you end up in your service thread instead:
// This happens on the serviceThread
private void doTheFirstThingOnTheServiceThread() {
// do some stuff
// here we can reuse a class that performs some work on an AsyncTask
ExistingClassWithAsyncOperation someUsefullObject = new ExistingClassWithAsyncOperation();
// the existing class performs some work on an AsyncTask and reports back via an observer interface
someUsefullObject.setOnOperationCompleteListener(new OnOperationCompleteListener() {
#Override
// This happens on the UI thread (due to an ``AsyncTask`` in someUsefullObject ending)
public void onOperationComplete() {
serviceThreadHandler.post(new Runnable() {
#Override
public void run() {
doTheSecondThingOnTheServiceThread();
}
});
}
}
someUsefulObject.performOperation();
}
// This happens on the serviceThread
private void doTheSecondThingOnTheServiceThread() {
// continue working on the serviceThread
}
So, this works for me. I'd be delighted to see a simpler solution for this. Note that the solution requires the service to know that is will be called back by the ExistingClassWithAsyncOperation on the UI thread. I don't particularly like this dependency, but don't know how to do better right now. However, I don't have to rewrite a lot of existing classes that perform asynchronous operations using AsyncTask.
is the order of a broadcast intent guaranteed? that is, if i do,
sendBroadcast(intent1);
sendBroadcast(intent2);
are the receivers guaranteed to get intent1 before intent2? i suspect the answer to this is no, but in that case, i'm not quite sure how to solve my problem.
i'm trying to create a "busy" indicator for my app that shows busy when the device is talking on the network, and then goes away when the network communication is done. all network communication happens in an intent service.
my attempt at this was to send a BUSY_START intent when i begin network communication in the service, and a BUSY_STOP when network communication ends. this seems to mostly work, but i'm finding occasionally that i get the stop and start messages out of order.
is there a better way to solve this problem?
i'm thinking of adding an ID to each busy intent, so they can be paired. that way if i receive a start for which i've already received a stop, i can ignore it. or, perhaps more simply, add an integer sequence number into each broadcast. if i ever receive a broadcast for which the sequence of the current intent is less than the sequence of the last received intent, ignore it.
Have you considered using a Handler object to communicate from the background thread in the IntentService? The advantage of a Handler over the BroadcastReciver approach is that the Handler uses a message queue to sequence the Message objects.
(I'm assuming your Service is in the same process as the app's main thread).
At least one viable alternative to intents is to execute messaging through the application class, i.e.,
create a listener interface
Manager a collection of listener objects in the application / provide methods to add / remove listener
Interested entities call the application methods to add / remove themselves as listeners
Add "notify" methods in the application, that call the appropriate listener interface method on each of the registered listeners
Services call the application's notification methods to
For example,
public class MyApplication extends Application {
public interface MyListener {
void onEvent();
}
private Set<MyListener> listeners = new HashSet<Listener>();
public void addListener(MyListener l) {
listeners.add(l);
}
public void removeListener(MyListener l) {
listeners.remove(l);
}
public void sendEvent() {
for (MyListener l: listeners) { l.onEvent(); }
}
}
Now, from your activity (or fragment),
public class MyActivity extends Activity implements MyListener {
...
...
...
#Override
public void onEvent() {
// do something
}
#Override
protected void onResume() {
super.onResume();
((MyApplication)getApplication()).addListener(this);
}
#Override
protected void onPause() {
super.onPause();
((MyApplication)getApplication()).removeListener(this);
}
}
And in your service,
((MyApplication)getApplication()).sendEvent();
This provides synchronous messaging without using intents or static variables.
I have a minor problem in one of my apps. It uses a BroadCastReceiver to detect when a call finishes and then performs some minor housekeeping tasks. These have to be delayed for a few seconds, to allow the user to see some data and to ensure that the call log has been updated. I'm currently using handler.postDelayed() for this purpose:
public class CallEndReceiver extends BroadcastReceiver {
#Override
public void onReceive(final Context context, final Intent intent) {
if (DebugFlags.LOG_OUTGOING)
Log.v("CallState changed "
+ intent.getStringExtra(TelephonyManager.EXTRA_STATE));
if (intent.getStringExtra(TelephonyManager.EXTRA_STATE)
.equalsIgnoreCase(TelephonyManager.EXTRA_STATE_IDLE)) {
SharedPreferences prefs = Utils.getPreferences(context);
if (prefs.getBoolean("auto_cancel_notification", true)) {
if (DebugFlags.LOG_OUTGOING)
Log.v("Posting Handler to remove Notification ");
final Handler mHandler = new Handler();
final Runnable mCancelNotification = new Runnable() {
public void run() {
NotificationManager notificationMgr = (NotificationManager) context
.getSystemService(Service.NOTIFICATION_SERVICE);
notificationMgr.cancel(12443);
if (DebugFlags.LOG_OUTGOING)
Log.v("Removing Notification ");
}
};
mHandler.postDelayed(mCancelNotification, 4000);
}
final Handler updateHandler = new Handler();
final Runnable mUpdate = new Runnable() {
public void run() {
if (DebugFlags.LOG_OUTGOING)
Log.v("Starting updateService");
Intent newBackgroundService = new Intent(context,
CallLogUpdateService.class);
context.startService(newBackgroundService);
}
};
updateHandler.postDelayed(mUpdate, 5000);
if (DebugFlags.TRACE_OUTGOING)
Debug.stopMethodTracing();
try
{
// Stopping old Service
Intent backgroundService = new Intent(context,
NetworkCheckService.class);
context.stopService(backgroundService);
context.unregisterReceiver(this);
}
catch(Exception e)
{
Log.e("Fehler beim Entfernen des Receivers", e);
}
}
}
}
Now I have the problem, that this setup works about 90% of the time. In about 10% of cases, the notification isn't removed. I suspect, that the thread dies before the message queue processes the message/runnable.
I'm now thinking about alternatives to postDelayed() and one of my choices is obviously the AlarmManager. However, I'm not sure about the performance impact (or the resources it uses).
Maybe there is a better way to ensure that all messages have been processed before a thread dies or another way to delay the execution of those two bits of code.
Thank you
I'm currently using handler.postDelayed() for this purpose:
That's not a good idea, assuming the BroadcastReceiver is being triggered by a filter in the manifest.
Now I have the problem, that this setup works about 90% of the time. In about 10% of cases, the notification isn't removed. I suspect, that the thread dies before the message queue processes the message/runnable.
More accurately, the process is terminated, taking everything with it.
I'm now thinking about alternatives to postDelayed() and one of my choices is obviously the AlarmManager. However, I'm not sure about the performance impact (or the resources it uses).
It's not that bad. Another possibility is to do your delayed work in an IntentService -- triggered via a call to startService() -- and have it sleep on its background thread for a couple of seconds.
Let's try a new way of doing this. Using RxJava. It's much simpler to prototype and easier to manage lots of threads if you want to ever run hundreds of such delayed tasks concurrently, sequentially, coupled with async tasks, chained with synchronous chained async calls etc.
Firstly, set up the Subscriber. Remember new on Subscriber should be done only once to avoid memory leaks.
// Set up a subscriber once
private Subscuber<Long> delaySubscriber = new Subscuber<Long> () {
#Override
public void onCompleted() {
//Wrap up things as onCompleted is called once onNext() is over
}
#Override
public void onError(Throwable e) {
//Keep an eye open for this. If onCompleted is not called, it means onError has been called. Make sure to override this method
}
#Override
public void onNext(Long aLong) {
// aLong will be from 0 to 1000
// Yuor code logic goes here
// If you want to run this code just once, just add a counter and call onComplete when the counter runs the first time
}
}
The snippet below will just emit the 1 in the onNext() of the subscriber.
Note that this is done on the Computation Threadpool created and managed by the RxJava library.
//Now when you want to start running your piece of cade, define an Observable interval that'll emit every second
private Observable<Long> runThisAfterDelay = Observable.just(1).delay(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
// Subscribe to begin the emissions.
runThisAfterDelay.subscribe(delaySubscriber);
If you want to run a code after every one second, say, then you can do this:
private Observable<Long> runThisOnInterval = Observable.interval(1000, TimeUnit.MILLISECONDS, Schedulers.computation());
In addition to the first answer, you might want to consider what the API documentation says for the onReceive method:
[...] The function is normally called within the main thread of its process, so you should never perform long-running operations in it [...]
So it looks like generally it is not a good idea to start something that waits a couple of time within onReceive (even though, in your case it's less than the 10s limit).
I had a similar timinig problem with the BroadcastReceiver. I couldn't get my results processed even though I onReceive had been called with exactly what I was exepcting. It seemed that the thread the BroadastReceiver was running in, got killed before my result processing could finish. My solutuion was to kick off a new thread to perform all processing.
AlarmManager seems not to work very well for short periods of time like 10 seconds and according to user reports the behaviour heavily depends on the firmware.
At the end I decided to use Handler and Runnable in my service.
When creating the Handler, be sure to create it inside the Service class, not inside the BroadcastReceiver since in the last case you'll get Can't create Handler inside thread that has not called Looper.prepare()
public class NLService extends NotificationListenerService {
private NLServiceReceiver nlservicereciver;
Handler delayUpdateHandler = new Handler();
private Runnable runBroadcastUpdate;
public void triggerViewUpdate() {
/* Accumulate view updates for faster, resource saving operation.
Delay the update by some milliseconds.
And if there was pending update, remove it and plan new update.
*/
if (runBroadcastUpdate != null) {
delayUpdateHandler.removeCallbacks(runBroadcastUpdate);
}
runBroadcastUpdate = new Runnable() {
public void run() {
// Do the work here; execution is delayed
}
};
delayUpdateHandler.postDelayed(runBroadcastUpdate, 300);
}
class NLServiceReceiver extends BroadcastReceiver{
#Override
public void onReceive(Context context, Intent intent) {
triggerViewUpdate();
}
}
}