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 > 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() 则会抛出异常。
常用的函数大概就是这个样子,如果我理解有误欢迎大家留言指正,也欢迎大家补充,一起学习
- Android RemoteCallbackList类
- Android RemoteCallbackList类
- android aidl通信 RemoteCallbackList客户端注册回调
- aidl ( 七) RemoteCallbackList
- RemoteCallbackList的使用
- RemoteCallbackList 机制分析
- 探究---RemoteCallbackList---activity与service之间的联系
- AIDL使用学习(二):跨进程回调以及RemoteCallbackList
- aidl 中通过RemoteCallbackList 运用到的回调机制: service回调activity的方法
- aidl 中通过RemoteCallbackList 运用到的回调机制: service回调activity的方法 .
- aidl 中通过RemoteCallbackList 运用到的回调机制: service回调activity的方法
- aidl 中通过RemoteCallbackList 运用到的回调机制: service回调activity的方法
- aidl 中通过RemoteCallbackList 运用到的回调机制: service回调activity的方法
- android类
- [Android工具类]Android File工具类
- Android中的android.app.Application类
- [android] android源码中的 PduParser 类详解。
- [android] android framework中的 PhoneNumberUtils 类详解
- 【C语言】C语言运算符优先级列表
- hdu3555 Bomb(数位dp)
- 移植ucosii遇到的问题 B OSStartHang
- 基于哈希表的索引堆变形(Hackerrank: QHEAP1)
- opencv3.3.0安装cmake-cui的配置参考
- Android RemoteCallbackList类
- 读书笔记_C#入门经典(第5版)第六章_函数
- onSaveInstanceState、onRestoreInstanceState、onNewIntent调用时机
- JAVA学习笔记_断言的使用
- 【POJ1113】【计算几何】Wall 题解
- HDU6154CaoHaha's staff(递推+网格)
- bzoj2440(二分+莫比乌斯函数)
- angular.js框架简单实现加载无限加载商品
- 如何把UCos-ii_在STM32上的移植