1

On Android basically, I am trying to upload/download data from a web service and have a progress bar that should be rendered showing the progress percentage.

Following is the approach that I implemented along with the reason for considering them:

  1. Chose IntentService to run in background: As per the link I could not use bound service as it will destroy when the binded Activity/Fragment is destroyed. Hence the selection of IntentService over Service. Move over it would be one time and intent service works on a worker thread so it is much better.
  2. Broadcast to receive updates: Implementation of LocalBroadcastManager to update the progress bar UI by registering it to listen to the broadcast received from the IntentService described above.

However with this approach, the following issue needs to be addressed:

Sequence of broadcasts is not maintained. The broadcast carries the percentage of progress of the upload/download. But since the sequence is not maintained, there are chances that I receive stale updates (eg: I may receive 30% after 40%). I also tried using sendBroadcastSync method of the LocalBroadcastManager but it doesn't work consistently (I am not very sure on this). Hence I tried to implement Messenger via Handler however I got to know that the approach will not be able to reconnect to the on going upload/download once the UI is re-created (Activitiy/Fragment is destroyed and created). Basically the reference to the Handler is lost along with the previous activity/fragment and hence the messages are not delivered to the UI for update.

I have been trying to get my way about since a while but I am not able to get it done. Your words of wisdom will be very helpful.

Tejas Sherdiwala
  • 750
  • 8
  • 15

3 Answers3

2

How about using an interface. UI: get instance and setCallback() when activity/fragment created, Service: get instance and call update(use a handler if not called from the main thread, handler.post(runnable {... update ...})).

If you want to notify multiple UI instances, keep an ArrayList in the updater class, and modify the 'setCallback' method to 'addCallback', and update every list item in 'update'.

public class ProgressUpdater {
    private static ProgressUpdater sUpdater;
    private UpdateCallback mCallback;

    public interface UpdateCallback {
        public void update(long progress);
    }

    public void setCallback(UpdateCallback callback) {
        mCallback = callback;
    }

    public void update(long progress) {
        if (mCallback != null) {
            mCallback.update(progress);
        }
    }

    public static ProgressUpdater getInstance() {
        if (null == sUpdater) {
            sUpdater = new ProgressUpdater();
        }
        return sUpdater;
    }

    private ProgressUpdater() {

    }
}
wrkwrk
  • 2,261
  • 15
  • 21
  • This is a Singleton pattern and it should update without either the `Messenger` or `Broadcast`. I will need to check this out. However there is a point of concern. Once the UI (Activity/Fragment) is destroyed, the `mCallback` will be going to `null`. Isn't there a chance that there will be a null pointer exception in that case? – Tejas Sherdiwala Jun 03 '15 at 04:38
  • I set a callback in the activity that shows a toast, and call update in the service every 5 seconds. the result is, even if the activity had been destoryed, the toast still shows up. Use a weakreference for the callback if you are worried about leaking the activity context. @Tejas – wrkwrk Jun 03 '15 at 06:06
1

If you want to constantly update your ui then we can start a local broadcast manager from a service and register your broadcast receiver in your activity.

Srishti Roy
  • 576
  • 5
  • 17
  • The issue with the broadcast manager is that the order is not guaranteed by the system. Kindly find the explanation here: http://stackoverflow.com/a/28513424/1161911 – Tejas Sherdiwala Jun 03 '15 at 05:53
1

I would go about the problem a bit differently, as ordering of messages may be a problem with a variety of message solutions.

The fact that you get the 40% event after the 30% event is not really a problem. What is a problem is if you update the UI to reflect 30%.

Have each event (each Intent when using LocalBroadcastManager as your event bus) contain a timestamp along with the percentage-complete. Track in your UI the last-seen event timestamp. If you get an event that is older than your last-seen event timestamp, ignore that event.

If you are sure that your percentage is monotonically increasing — in other words, that there is no legitimate scenario in which you might drop from 40% to 30% complete — you could skip the timestamp and just only apply new percentages that are higher than your currently-showing percentage.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491