aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/utils/CancellableHandler.java
blob: 7b7aa6f60e4b4bba6d3b4ceedd2f94ecb5d1a481 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
package cgeo.geocaching.utils;

import cgeo.geocaching.CgeoApplication;

import rx.Subscription;
import rx.subscriptions.CompositeSubscription;

import android.os.Handler;
import android.os.Message;

/**
 * Handler with a cancel policy. Once cancelled, the handler will not handle
 * any more cancel or regular message.
 */
public abstract class CancellableHandler extends Handler {

    public static final int DONE = -1000;
    protected static final int UPDATE_LOAD_PROGRESS_DETAIL = 42186;
    private volatile boolean cancelled = false;
    private final CompositeSubscription subscriptions = new CompositeSubscription();

    private static class CancelHolder {
        final Object payload;

        CancelHolder(final Object payload) {
            this.payload = payload;
        }
    }

    @Override
    final public void handleMessage(final Message message) {
        if (cancelled) {
            return;
        }

        if (message.obj instanceof CancelHolder) {
            cancelled = true;
            subscriptions.unsubscribe();
            handleCancel(((CancelHolder) message.obj).payload);
        } else {
            handleRegularMessage(message);
        }
    }

    /**
     * Add a subscription to the list of subscriptions to be subscribed at cancellation time.
     */
    final public void unsubscribeIfCancelled(final Subscription subscription) {
        subscriptions.add(subscription);
        if (cancelled) {
            // Protect against race conditions
            subscriptions.unsubscribe();
        }
    }

    /**
     * Handle a non-cancel message.<br>
     * Subclasses must implement this to handle messages.
     *
     * @param message
     *            the message to handle
     */
    abstract protected void handleRegularMessage(final Message message);

    /**
     * Handle a cancel message.
     *
     * @param extra
     *            the additional payload given by the canceller
     */
    protected void handleCancel(final Object extra) {
    }

    /**
     * Get a cancel message that can later be sent to this handler to cancel it.
     *
     * @return a cancel message
     */
    public Message cancelMessage() {
        return cancelMessage(null);
    }

    /**
     * Get a cancel message with an additional parameter that can later be sent to
     * this handler to cancel it.
     *
     * @param extra
     *            the extra parameter to give to the cancel handler
     * @return a cancel message
     */
    public Message cancelMessage(final Object extra) {
        return this.obtainMessage(0, new CancelHolder(extra));
    }

    /**
     * Cancel the current handler. This can be called from any thread.
     */
    public void cancel() {
        cancel(null);
    }

    /**
     * Cancel the current handler. This can be called from any thread.
     *
     * @param extra
     *            the extra parameter to give to the cancel handler
     */
    public void cancel(final Object extra) {
        cancelMessage(extra).sendToTarget();
    }

    /**
     * Check if the current handler has been cancelled.
     *
     * @return true if the handler has been cancelled
     */
    public boolean isCancelled() {
        return cancelled;
    }

    /**
     * Check if a handler has been cancelled.
     *
     * @param handler
     *            a handler, or null
     * @return true if the handler is not null and has been cancelled
     */
    public static boolean isCancelled(final CancellableHandler handler) {
        return handler != null && handler.isCancelled();
    }

    public static void sendLoadProgressDetail(final Handler handler, final int resourceId) {
        if (null != handler) {
            handler.obtainMessage(UPDATE_LOAD_PROGRESS_DETAIL, CgeoApplication.getInstance().getString(resourceId)).sendToTarget();
        }
    }
}