Android RemoteCallbackList类

来源:互联网 发布:淘宝手机端连接 编辑:程序博客网 时间:2024/05/22 04:55

在网上很少看到有解释 RemoteCallbackList类的,没办法要搞懂只能去看源码,大致理解:一个容器,容纳的对象是一些接口,用于执行列表中对象的回调函数,主要用于服务调用activity函数,或者解释为服务端和客户端通信。

/* * Copyright (C) 2008 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package android.os;import java.util.HashMap;/** * Takes care of the grunt work of maintaining a list of remote interfaces, * typically for the use of performing callbacks from a * {@link android.app.Service} to its clients.  In particular, this: * * <ul> * <li> Keeps track of a set of registered {@link IInterface} callbacks, * taking care to identify them through their underlying unique {@link IBinder} * (by calling {@link IInterface#asBinder IInterface.asBinder()}. * <li> Attaches a {@link IBinder.DeathRecipient IBinder.DeathRecipient} to * each registered interface, so that it can be cleaned out of the list if its * process goes away. * <li> Performs locking of the underlying list of interfaces to deal with * multithreaded incoming calls, and a thread-safe way to iterate over a * snapshot of the list without holding its lock. * </ul> * * <p>To use this class, simply create a single instance along with your * service, and call its {@link #register} and {@link #unregister} methods * as client register and unregister with your service.  To call back on to * the registered clients, use {@link #beginBroadcast}, * {@link #getBroadcastItem}, and {@link #finishBroadcast}. * * <p>If a registered callback's process goes away, this class will take * care of automatically removing it from the list.  If you want to do * additional work in this situation, you can create a subclass that * implements the {@link #onCallbackDied} method. */public class RemoteCallbackList<E extends IInterface> {    /*package*/ HashMap<IBinder, Callback> mCallbacks            = new HashMap<IBinder, Callback>();    private Object[] mActiveBroadcast;    private int mBroadcastCount = -1;    private boolean mKilled = false;    private final class Callback implements IBinder.DeathRecipient {        final E mCallback;        final Object mCookie;        Callback(E callback, Object cookie) {            mCallback = callback;            mCookie = cookie;        }        public void binderDied() {            synchronized (mCallbacks) {                mCallbacks.remove(mCallback.asBinder());            }            onCallbackDied(mCallback, mCookie);        }    }    /**     * Simple version of {@link RemoteCallbackList#register(E, Object)}     * that does not take a cookie object.     */    public boolean register(E callback) {        return register(callback, null);    }    /**     * Add a new callback to the list.  This callback will remain in the list     * until a corresponding call to {@link #unregister} or its hosting process     * goes away.  If the callback was already registered (determined by     * checking to see if the {@link IInterface#asBinder callback.asBinder()}     * object is already in the list), then it will be left as-is.     * Registrations are not counted; a single call to {@link #unregister}     * will remove a callback after any number calls to register it.     *     * @param callback The callback interface to be added to the list.  Must     * not be null -- passing null here will cause a NullPointerException.     * Most services will want to check for null before calling this with     * an object given from a client, so that clients can't crash the     * service with bad data.     *     * @param cookie Optional additional data to be associated with this     * callback.     *      * @return Returns true if the callback was successfully added to the list.     * Returns false if it was not added, either because {@link #kill} had     * previously been called or the callback's process has gone away.     *     * @see #unregister     * @see #kill     * @see #onCallbackDied     */    public boolean register(E callback, Object cookie) {        synchronized (mCallbacks) {            if (mKilled) {                return false;            }            IBinder binder = callback.asBinder();            try {                Callback cb = new Callback(callback, cookie);                binder.linkToDeath(cb, 0);                mCallbacks.put(binder, cb);                return true;            } catch (RemoteException e) {                return false;            }        }    }    /**     * Remove from the list a callback that was previously added with     * {@link #register}.  This uses the     * {@link IInterface#asBinder callback.asBinder()} object to correctly     * find the previous registration.     * Registrations are not counted; a single unregister call will remove     * a callback after any number calls to {@link #register} for it.     *     * @param callback The callback to be removed from the list.  Passing     * null here will cause a NullPointerException, so you will generally want     * to check for null before calling.     *     * @return Returns true if the callback was found and unregistered.  Returns     * false if the given callback was not found on the list.     *     * @see #register     */    public boolean unregister(E callback) {        synchronized (mCallbacks) {            Callback cb = mCallbacks.remove(callback.asBinder());            if (cb != null) {                cb.mCallback.asBinder().unlinkToDeath(cb, 0);                return true;            }            return false;        }    }    /**     * Disable this callback list.  All registered callbacks are unregistered,     * and the list is disabled so that future calls to {@link #register} will     * fail.  This should be used when a Service is stopping, to prevent clients     * from registering callbacks after it is stopped.     *     * @see #register     */    public void kill() {        synchronized (mCallbacks) {            for (Callback cb : mCallbacks.values()) {                cb.mCallback.asBinder().unlinkToDeath(cb, 0);            }            mCallbacks.clear();            mKilled = true;        }    }    /**     * Old version of {@link #onCallbackDied(E, Object)} that     * does not provide a cookie.     */    public void onCallbackDied(E callback) {    }    /**     * Called when the process hosting a callback in the list has gone away.     * The default implementation calls {@link #onCallbackDied(E)}     * for backwards compatibility.     *      * @param callback The callback whose process has died.  Note that, since     * its process has died, you can not make any calls on to this interface.     * You can, however, retrieve its IBinder and compare it with another     * IBinder to see if it is the same object.     * @param cookie The cookie object original provided to     * {@link #register(E, Object)}.     *      * @see #register     */    public void onCallbackDied(E callback, Object cookie) {        onCallbackDied(callback);    }    /**     * Prepare to start making calls to the currently registered callbacks.     * This creates a copy of the callback list, which you can retrieve items     * from using {@link #getBroadcastItem}.  Note that only one broadcast can     * be active at a time, so you must be sure to always call this from the     * same thread (usually by scheduling with {@link Handler}) or     * do your own synchronization.  You must call {@link #finishBroadcast}     * when done.     *     * <p>A typical loop delivering a broadcast looks like this:     *     * <pre>     * int i = callbacks.beginBroadcast();     * while (i &gt; 0) {     *     i--;     *     try {     *         callbacks.getBroadcastItem(i).somethingHappened();     *     } catch (RemoteException e) {     *         // The RemoteCallbackList will take care of removing     *         // the dead object for us.     *     }     * }     * callbacks.finishBroadcast();</pre>     *     * @return Returns the number of callbacks in the broadcast, to be used     * with {@link #getBroadcastItem} to determine the range of indices you     * can supply.     *     * @see #getBroadcastItem     * @see #finishBroadcast     */    public int beginBroadcast() {        synchronized (mCallbacks) {            if (mBroadcastCount > 0) {                throw new IllegalStateException(                        "beginBroadcast() called while already in a broadcast");            }            final int N = mBroadcastCount = mCallbacks.size();            if (N <= 0) {                return 0;            }            Object[] active = mActiveBroadcast;            if (active == null || active.length < N) {                mActiveBroadcast = active = new Object[N];            }            int i=0;            for (Callback cb : mCallbacks.values()) {                active[i++] = cb;            }            return i;        }    }    /**     * Retrieve an item in the active broadcast that was previously started     * with {@link #beginBroadcast}.  This can <em>only</em> be called after     * the broadcast is started, and its data is no longer valid after     * calling {@link #finishBroadcast}.     *     * <p>Note that it is possible for the process of one of the returned     * callbacks to go away before you call it, so you will need to catch     * {@link RemoteException} when calling on to the returned object.     * The callback list itself, however, will take care of unregistering     * these objects once it detects that it is no longer valid, so you can     * handle such an exception by simply ignoring it.     *     * @param index Which of the registered callbacks you would like to     * retrieve.  Ranges from 0 to 1-{@link #beginBroadcast}.     *     * @return Returns the callback interface that you can call.  This will     * always be non-null.     *     * @see #beginBroadcast     */    public E getBroadcastItem(int index) {        return ((Callback)mActiveBroadcast[index]).mCallback;    }    /**     * Retrieve the cookie associated with the item     * returned by {@link #getBroadcastItem(int)}.     *      * @see #getBroadcastItem     */    public Object getBroadcastCookie(int index) {        return ((Callback)mActiveBroadcast[index]).mCookie;    }    /**     * Clean up the state of a broadcast previously initiated by calling     * {@link #beginBroadcast}.  This must always be called when you are done     * with a broadcast.     *     * @see #beginBroadcast     */    public void finishBroadcast() {        if (mBroadcastCount < 0) {            throw new IllegalStateException(                    "finishBroadcast() called outside of a broadcast");        }        Object[] active = mActiveBroadcast;        if (active != null) {            final int N = mBroadcastCount;            for (int i=0; i<N; i++) {                active[i] = null;            }        }        mBroadcastCount = -1;    }    /**     * Returns the number of registered callbacks. Note that the number of registered     * callbacks may differ from the value returned by {@link #beginBroadcast()} since     * the former returns the number of callbacks registered at the time of the call     * and the second the number of callback to which the broadcast will be delivered.     * <p>     * This function is useful to decide whether to schedule a broadcast if this     * requires doing some work which otherwise would not be performed.     * </p>     *     * @return The size.     */    public int getRegisteredCallbackCount() {        synchronized (mCallbacks) {            if (mKilled) {                return 0;            }            return mCallbacks.size();        }    }}
  • 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
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 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
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329

通过查看上面的源码,我们可以知道主要是维护 mCallbacks ,mCallbacks中包含我们的客户端接口

    /*package*/ HashMap<IBinder, Callback> mCallbacks            = new HashMap<IBinder, Callback>();
  • 1
  • 2
  • 1
  • 2

其中常用的几个函数 register

    public boolean register(E callback) {        return register(callback, null);    }    public boolean register(E callback, Object cookie) {        synchronized (mCallbacks) {            if (mKilled) {                return false;            }            IBinder binder = callback.asBinder();            try {                Callback cb = new Callback(callback, cookie);                binder.linkToDeath(cb, 0);                mCallbacks.put(binder, cb);                return true;            } catch (RemoteException e) {                return false;            }        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

向 mCallbacks中添加接口对象,主要使用 mCallbacks.put(binder, cb);方法,

unregister()方法

    public boolean unregister(E callback) {        synchronized (mCallbacks) {            Callback cb = mCallbacks.remove(callback.asBinder());            if (cb != null) {                cb.mCallback.asBinder().unlinkToDeath(cb, 0);                return true;            }            return false;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

通过 mCallbacks.remove(callback.asBinder()); 从HashMap中删除

kill()方法

    public void kill() {        synchronized (mCallbacks) {            for (Callback cb : mCallbacks.values()) {                cb.mCallback.asBinder().unlinkToDeath(cb, 0);            }            mCallbacks.clear();            mKilled = true;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

通过 mCallbacks.clear(); 清空集合。

beginBroadcast() ;

    public int beginBroadcast() {        synchronized (mCallbacks) {            if (mBroadcastCount > 0) {                throw new IllegalStateException(                        "beginBroadcast() called while already in a broadcast");            }            final int N = mBroadcastCount = mCallbacks.size();            if (N <= 0) {                return 0;            }            Object[] active = mActiveBroadcast;            if (active == null || active.length < N) {                mActiveBroadcast = active = new Object[N];            }            int i=0;            for (Callback cb : mCallbacks.values()) {                active[i++] = cb;            }            return i;        }    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

从注释的解释来说大致是:准备开始调用当前注册的回调。这将创建一个回调列表的副本,你可以从使用getBroadcastItem检索条目,注意:一次只能激活一个广播,所以你必须确保总是从同一个线程调用这个或者是自己做同步。完成后必须调用finishBroadcast。
返回值:callbacks的大小;

如果 mBroadcastCount > 0 说明之前调用过beginBroadcast(),则会抛出异常;

getBroadcastItem()方法 从副本中获取我们之前存入的接口对象

    public E getBroadcastItem(int index) {        return ((Callback)mActiveBroadcast[index]).mCallback;    }
  • 1
  • 2
  • 3
  • 1
  • 2
  • 3

finishBroadcast(),清理我们之前建立的active[] 副本

    public void finishBroadcast() {        if (mBroadcastCount < 0) {            throw new IllegalStateException(                    "finishBroadcast() called outside of a broadcast");        }        Object[] active = mActiveBroadcast;        if (active != null) {            final int N = mBroadcastCount;            for (int i=0; i<N; i++) {                active[i] = null;            }        }        mBroadcastCount = -1;    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

如果 mBroadcastCount <0 说明之前掉用过finishBroadcast() 则会抛出异常。

常用的函数大概就是这个样子,如果我理解有误欢迎大家留言指正,也欢迎大家补充,一起学习

阅读全文
0 0