EventBus概述和优点
1.Android事件发布、订阅框架
2.事件传递可用于Android四大组件间通讯
3.简洁,使用简单,并将事件的发布和订阅充分解耦
EventBus的使用
1.定义事件event
2.准备订阅者
3.订阅者同时需要在总线上注册和注销自己
4.发送事件
看下 EventBus.getDefault()方法
public static EventBus getDefault() {//单例模式
if (defaultInstance == null) {
synchronized (EventBus.class) {
if (defaultInstance == null) {
defaultInstance = new EventBus();
}
}
}
return defaultInstance;
}
看下EventBusBuilder的currentPostingThreadState成员变量
//ThreadLocal是线程内部,存储数据类,通过它我们可以再指定的线程内部,存储数据,存储完数据,只有在指定的线程中可以获取到数据,其它线程就无法获取到该线程的数据
private final ThreadLocal<PostingThreadState> currentPostingThreadState = new ThreadLocal<PostingThreadState>()
{
@Override
protected PostingThreadState initialValue() {
return new PostingThreadState();
}
};
看下subscriptionsByEventType成员变量
//subscriptionsByEventType是以Event为key,以Subscriber为value,所以说当发送Event的时候,通过subscriptionsByEventType可以找到对应的订阅者
private final Map<Class<?>, CopyOnWriteArrayList<Subscription>> subscriptionsByEventType
subscriptionsByEventType = new HashMap<>();
看下typesBySubscriber成员变量
//typesBySubscriber是以Subscriber为key,以Event为Value,当我们注册或者反注册事件的时候,都会操作到它
private final Map<Object, List<Class<?>>> typesBySubscriber;
typesBySubscriber = new HashMap<>();
看下stickyEvents成员变量
//它是维护粘性事件的,粘性事件就是当我们的Event发送数据之后,如果再注册粘性事件的话,这个粘性事件,它也能收到之前发送的数据的Event,ConcurrentHashMap是一个并发的HashMap
private final Map<Class<?>, Object> stickyEvents;
stickyEvents = new ConcurrentHashMap<>();
看下mainThreadPoster成员变量
//Poster是负责线程间调度的
private final Poster mainThreadPoster;
mainThreadPoster = mainThreadSupport != null ? mainThreadSupport.createPoster(this) : null;
看下createPoster(this)方法
@Override
public Poster createPoster(EventBus eventBus) {
return new HandlerPoster(eventBus, looper, 10);
}
看下HandlerPoster类
//继承了Handler
public class HandlerPoster extends Handler implements Poster {
//PendingPostQueue用来放我们即将执行的Post事件的队列
private final PendingPostQueue queue;
//表示我们Post的事件,最大的所能在我们的Handler当中的handleMessage方法,所存在的最大的时间值
private final int maxMillisInsideHandleMessage;
private final EventBus eventBus;
//标志的是Handler它是否运行起来了
private boolean handlerActive;
看下HandlerPoster 的handleMessage方法
@Override
public void handleMessage(Message msg) {
boolean rescheduled = false;
try {
long started = SystemClock.uptimeMillis();
while (true) {
//从队列中获取事件
//PendingPostw维护这一个可复用对象的对象池
PendingPost pendingPost = queue.poll();
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
handlerActive = false;
return;
}
}
}
//分发事件
eventBus.invokeSubscriber(pendingPost);
long timeInMethod = SystemClock.uptimeMillis() - started;
//对比事件,判断事件是否大于等于或者POST最大的在handleMessage里当中所存在的最大时间
if (timeInMethod >= maxMillisInsideHandleMessage) {
if (!sendMessage(obtainMessage())) {
throw new EventBusException("Could not send handler message");
}
rescheduled = true;
return;
}
}
} finally {
handlerActive = rescheduled;
}
}
看下PendingPost类
final class PendingPost {
//通过ArrayList来做的
private final static List<PendingPost> pendingPostPool = new ArrayList<PendingPost>();
Object event;
Subscription subscription;
PendingPost next;
//去获取PendingPost
static PendingPost obtainPendingPost(Subscription subscription, Object event) {
synchronized (pendingPostPool) {
int size = pendingPostPool.size();
if (size > 0) {
PendingPost pendingPost = pendingPostPool.remove(size - 1);
pendingPost.event = event;
pendingPost.subscription = subscription;
pendingPost.next = null;
return pendingPost;
}
}
return new PendingPost(event, subscription);
}
//回收PendingPost
static void releasePendingPost(PendingPost pendingPost) {
pendingPost.event = null;
pendingPost.subscription = null;
pendingPost.next = null;
synchronized (pendingPostPool) {
// Don't let the pool grow indefinitely
if (pendingPostPool.size() < 10000) {
pendingPostPool.add(pendingPost);
}
}
}
看下 backgroundPoster成员变量
//Poster是负责线程间调度的
//就是在后台做的一些操作
private final BackgroundPoster backgroundPoster;
看下BackgroundPoste类
//它实现了Runnable
final class BackgroundPoster implements Runnable, Poster {
@Override
public void run() {
try {
try {
while (true) {
//获取消息
PendingPost pendingPost = queue.poll(1000);
if (pendingPost == null) {
synchronized (this) {
// Check again, this time in synchronized
pendingPost = queue.poll();
if (pendingPost == null) {
executorRunning = false;
return;
}
}
}
//分发事件,直到取完为止
eventBus.invokeSubscriber(pendingPost);
}
} catch (InterruptedException e) {
eventBus.getLogger().log(Level.WARNING, Thread.currentThread().getName() + " was interruppted", e);
}
} finally {
executorRunning = false;
}
}
看下asyncPoster成员变量
//Poster是负责线程间调度的
//asyncPoster异步Poster
private final AsyncPoster asyncPoster;
看下AsyncPoster
class AsyncPoster implements Runnable, Poster {
@Override
public void run() {
//获取队列中的一个PendingPost
PendingPost pendingPost = queue.poll();
if(pendingPost == null) {
throw new IllegalStateException("No pending post available");
}
//分发事件
eventBus.invokeSubscriber(pendingPost);
}
EventBus其它变量
//indexCount 表示Event生成的索引
indexCount = builder.subscriberInfoIndexes != null ? builder.subscriberInfoIndexes.size() : 0;
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//对我们已经注解好的,给它设定好@Subscriber注解的方法的找寻器
subscriberMethodFinder = new SubscriberMethodFinder(builder.subscriberInfoIndexes,
builder.strictMethodVerification, builder.ignoreGeneratedIndex);
//当我们用事件处理函数时,发生异常,这时候是否需要进行异常信息的打印
logSubscriberExceptions = builder.logSubscriberExceptions;
//当没有订阅者订阅该事件的时候,是否要打印日志
logNoSubscriberMessages = builder.logNoSubscriberMessages;
//当我们调用事件处理函数时异常,是否需要发送sendSubscriberEvent事件
sendSubscriberExceptionEvent =
builder.sendSubscriberExceptionEvent;
//当没有事件处理函数时,对事件处理是否需要发送NoSubscriberEvent标志位
sendNoSubscriberEvent = builder.sendNoSubscriberEvent;
//是否需要抛出SubscriberException
throwSubscriberException = builder.throwSubscriberException;
//与Event有关系的,是否都需要继承发送
eventInheritance = builder.eventInheritance;
//线程池
executorService = builder.executorService;
}
看下@Subscribe注解
@Documented //Java Doc文档
@Retention(RetentionPolicy.RUNTIME)//运行时有效,也就是运行时会保留这个注解
@Target({ElementType.METHOD})//用来描述方法的
public @interface Subscribe {
//线程模式(POSTING, MAIN, MAIN,BACKGROUND,ASYNC)
ThreadMode threadMode() default ThreadMode.POSTING;
//判断是否是粘性事件(Sticky Brocast粘性广播也是粘性事件,利用的是保存的原理,AndroidEventBus会存储所有的Sticky事件,如果不需要,进行手动的的移除)
boolean sticky() default false;
//设定方法的优先级
int priority() default 0;
}
看下ThreadMode枚举类
public enum ThreadMode {
//默认的线程模式,执行POST事件操作的时候,线程调用订阅者的事件方法,不论该线程是否在主线程,在主线程当中,不能做耗时操作
POSTING,
//在主线程执行这个方法,当我们的发布线程就是在主线程,直接调用订阅者的事件方法来处理,否则需要通过HandlerPost来进行发送,handleMesage来处(对应mainThreadPoster)
MAIN,
MAIN_ORDERED,
//在后台线程中,去执行相应的方法,表示发布线程不是在主线程中,直接调用订阅者的事件处理函数,肯定是不行的,一定要启动唯一的后台线程去进行处理,当事件发送的Poster超过一个的时候,会依次处理(对应BackgroundPoste)
BACKGROUND,
//表示发布线程无论是否是在主线程,都会使用一个空线程来进行处理,它和BACKGROUND不同的是,ASYNC所有的线程都相互独立的,不会出现线程卡顿,AsyncPoster每次只会取一个,BackgroundPoste会取出所有线程进行处理
ASYNC
}
看下EventBus.getDefault().register(this)方法
public void register(Object subscriber) {
//反射获取订阅者Class对象
Class<?> subscriberClass = subscriber.getClass();
//通过找寻器的findSubscriberMethods(subscriberClass)返回订阅方法的集合
List<SubscriberMethod> subscriberMethods = subscriberMethodFinder.findSubscriberMethods(subscriberClass);
synchronized (this) {
for (SubscriberMethod subscriberMethod : subscriberMethods) {
//单个方法的订阅操作
subscribe(subscriber, subscriberMethod);
}
}
}
看下subscriberMethodFinder.findSubscriberMethods(subscriberClass)方法
List<SubscriberMethod> findSubscriberMethods(Class<?> subscriberClass) {
//方法的缓存池中查找是否有订阅方法,如果有的话,就返回订阅者方法集合
List<SubscriberMethod> subscriberMethods = METHOD_CACHE.get(subscriberClass);
if (subscriberMethods != null) {
return subscriberMethods;
}
//索引的判断,默认情况下是false
if (ignoreGeneratedIndex) {
subscriberMethods = findUsingReflection(subscriberClass);
} else {
//获取订阅方法的集合
subscriberMethods = findUsingInfo(subscriberClass);
}
if (subscriberMethods.isEmpty()) {
throw new EventBusException("Subscriber " + subscriberClass
+ " and its super classes have no public methods with the @Subscribe annotation");
} else {
//将subscriberMethods存储到METHOD_CACHE当中
METHOD_CACHE.put(subscriberClass, subscriberMethods);
return subscriberMethods;
}
}
看下SubscriberMethod类
public class SubscriberMethod {
//方法
final Method method;
//线程模式
final ThreadMode threadMode;
//事件类型
final Class<?> eventType;
//方法的优先级
final int priority;
//是否为粘性事件
final boolean sticky;
//方法名
String methodString;
.
.
.
}
看下 findUsingInfo(subscriberClass)方法
private List<SubscriberMethod> findUsingInfo(Class<?> subscriberClass) {
//找到注解过的方法的状态
FindState findState = prepareFindState();
//用来做赋值操作
findState.initForSubscriber(subscriberClass);
while (findState.clazz != null) {
//获取到FindState中订阅者的相关信息
findState.subscriberInfo = getSubscriberInfo(findState);
if (findState.subscriberInfo != null) {
//获取到FindState中订阅方法的集合
SubscriberMethod[] array = findState.subscriberInfo.getSubscriberMethods();
for (SubscriberMethod subscriberMethod : array) {
//判断获取到的方法,是否可以添加到订阅方法集合中
if (findState.checkAdd(subscriberMethod.method, subscriberMethod.eventType)) {
//将订阅方法添加到FindStated当中 findState.subscriberMethods.add(subscriberMethod);
}
}
} else {
findUsingReflectionInSingleClass(findState);
}
//依次找寻FindState的父类
findState.moveToSuperclass();
}
return getMethodsAndRelease(findState);
}
看下FindState 类
static class FindState {
//保存所有订阅方法的List
final List<SubscriberMethod> subscriberMethods = new ArrayList<>();
//保存的类型是事件类型为Key,订阅方法为Value
final Map<Class, Object> anyMethodByEventType = new HashMap<>();
//订阅方法为Key,Valuse是订阅者的Class对象
final Map<String, Class> subscriberClassByMethodKey = new HashMap<>();
.
.
.
}
看下prepareFindState()方法
private FindState prepareFindState() {
//从FindState对象池中去查找
synchronized (FIND_STATE_POOL) {
for (int i = 0; i < POOL_SIZE; i++) {
FindState state = FIND_STATE_POOL[i];
if (state != null) {
//找到了可用的state ,将该位置清空,清空就是为了以后再去复用它
FIND_STATE_POOL[i] = null;
return state;
}
}
}
//FindState对象池中没有找到,就自己去创建一个
return new FindState();
}
看下initForSubscriber(subscriberClass)方法
void initForSubscriber(Class<?> subscriberClass) {
//将传进来的subscriberClass赋值给它的成员变量
this.subscriberClass = clazz = subscriberClass;
skipSuperClasses = false;
subscriberInfo = null;
}
看下findUsingReflectionInSingleClass(findState)方法
private void findUsingReflectionInSingleClass(FindState findState) {
Method[] methods;
try {
?//通过反射来获取到订阅者的所有的方法
methods = findState.clazz.getDeclaredMethods();
} catch (Throwable th) {
methods = findState.clazz.getMethods();
findState.skipSuperClasses = true;
}
for (Method method : methods) {
//获取到方法的修饰符
int modifiers = method.getModifiers();
if ((modifiers & Modifier.PUBLIC) != 0 && (modifiers & MODIFIERS_IGNORE) == 0) {
//获取到方法的参数,为什么要获取方法的参数,因为下面要进行方法参数的判断,为什么要进行方法参数的判断,因为EventBus中只允许我们订阅方法后面的订阅事件是一个,通过方法参数长度的判断,来过滤出参数只有一个的方法
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length == 1) {
//过滤出只被@Subscribe修饰过的方法
Subscribe subscribeAnnotation = method.getAnnotation(Subscribe.class);
if (subscribeAnnotation != null) {
Class<?> eventType = parameterTypes[0];
if (findState.checkAdd(method, eventType)) { //获取到被@Subscribe修饰的方法的线程模式
ThreadMode threadMode = subscribeAnnotation.threadMode();
//添加到FindState里
findState.subscriberMethods.add(new SubscriberMethod(method, eventType, threadMode,
subscribeAnnotation.priority(), subscribeAnnotation.sticky()));
}
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException("@Subscribe method " + methodName +
"must have exactly 1 parameter but has " + parameterTypes.length);
}
} else if (strictMethodVerification && method.isAnnotationPresent(Subscribe.class)) {
String methodName = method.getDeclaringClass().getName() + "." + method.getName();
throw new EventBusException(methodName +
" is a illegal @Subscribe method: must be public, non-static, and non-abstract");
}
}
}
看下findState.checkAdd(subscriberMethod.method,
subscriberMethod.eventType)方法
boolean checkAdd(Method method, Class<?> eventType) {
Object existing = anyMethodByEventType.put(eventType, method);
if (existing == null) {
return true;
} else {
if (existing instanceof Method) {
if (!checkAddWithMethodSignature((Method) existing, eventType)) {
throw new IllegalStateException();
}
anyMethodByEventType.put(eventType, this);
}
//EventBus中一个订阅者,包括这个订阅者所有的父类和子类,它不会有多个方法,相同的全部去接收同一个事件,但是它可能它可能会出现这样一种情况,子类会订阅该事件,同时父类也会同时订阅该事件,如何判断,用checkAddWithMethodSignature(method, eventType)
return checkAddWithMethodSignature(method, eventType);
}
}
看下checkAddWithMethodSignature(method, eventType)方法
//根据方法的签名来进行检查
private boolean checkAddWithMethodSignature(Method method, Class<?> eventType) {
methodKeyBuilder.setLength(0);
methodKeyBuilder.append(method.getName());
methodKeyBuilder.append('>').append(eventType.getName());
String methodKey = methodKeyBuilder.toString();
Class<?> methodClass = method.getDeclaringClass();
//返回之前订阅的Class对象
Class<?> methodClassOld = subscriberClassByMethodKey.put(methodKey, methodClass);
//如果Class对象不存在,或者这个值是我们Method类的父类
if (methodClassOld == null || methodClassOld.isAssignableFrom(methodClass)) {
} else {
//调用put方法之后,它不是存进了缓存,因为放进去的是methodClassOld,意义就是,我们不要出现一个订阅者,有多个相同方法订阅同一个事件,如果有的话,就把以前的methodClassOld放到HashMap当中去覆盖
subscriberClassByMethodKey.put(methodKey, methodClassOld);
return false;
}
}
看下getMethodsAndRelease(findState)方法
private List<SubscriberMethod> getMethodsAndRelease(FindState findState) {
List<SubscriberMethod> subscriberMethods = new ArrayList<>(findState.subscriberMethods);
//资源回收
findState.recycle();
.
.
.
}
看下findState.recycle()方法
void recycle() {
subscriberMethods.clear();
anyMethodByEventType.clear();
subscriberClassByMethodKey.clear();
methodKeyBuilder.setLength(0);
subscriberClass = null;
clazz = null;
skipSuperClasses = false;
subscriberInfo = null;
}
看下subscribe(subscriber, subscriberMethod)方法
private void subscribe(Object subscriber, SubscriberMethod subscriberMethod) {
Class<?> eventType = subscriberMethod.eventType;
//Subscription封封装了订阅者subscriber和subscriberMethod
Subscription newSubscription = new Subscription(subscriber, subscriberMethod);
//CopyOnWriteArrayList可并发读写ArrayList
CopyOnWriteArrayList<Subscription> subscriptions = subscriptionsByEventType.get(eventType);
//这个事件还没有被注册过
if (subscriptions == null) {
subscriptions = new CopyOnWriteArrayList<>();
subscriptionsByEventType.put(eventType, subscriptions);
} else {//已经被订阅骨过
if (subscriptions.contains(newSubscription)) {
throw new EventBusException("Subscriber " + subscriber.getClass() + " already registered to event "
+ eventType);
}
}
int size = subscriptions.size();
for (int i = 0; i <= size; i++) {
if (i == size || subscriberMethod.priority > subscriptions.get(i).subscriberMethod.priority) {
//根据优先级添加
subscriptions.add(i, newSubscription);
break;
}
}
List<Class<?>> subscribedEvents = typesBySubscriber.get(subscriber);
if (subscribedEvents == null) {
subscribedEvents = new ArrayList<>();
typesBySubscriber.put(subscriber, subscribedEvents);
}
subscribedEvents.add(eventType);
//判断方法是否是粘性事件
if (subscriberMethod.sticky) {
//判断是否可继承
if (eventInheritance) {
Set<Map.Entry<Class<?>, Object>> entries = stickyEvents.entrySet();
for (Map.Entry<Class<?>, Object> entry : entries) {
Class<?> candidateEventType = entry.getKey();
if (eventType.isAssignableFrom(candidateEventType)) {//事件是否有继承关系
Object stickyEvent = entry.getValue();
//分发事件的方法 checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
} else {
Object stickyEvent = stickyEvents.get(eventType);
checkPostStickyEventToSubscription(newSubscription, stickyEvent);
}
}
}
``
subscribe方法总结
1.首先判断是否有注册过该事件
2.然后在按照优先级加入到subscriptionsByEventType的value的List中
3.然后再添加到typesBySubscriber的value的List中
4.分发事件:checkPostStickyEventToSubscription
看下checkPostStickyEventToSubscription(newSubscription, stickyEvent)方法
```java
private void checkPostStickyEventToSubscription(Subscription newSubscription, Object stickyEvent) {
if (stickyEvent != null) {
//实际分发
postToSubscription(newSubscription, stickyEvent, isMainThread());
}
}
看下isMainThread()
private boolean isMainThread() {
return mainThreadSupport != null ? mainThreadSupport.isMainThread() : true;
}
看下isMainThread方法
//通过主线程Looper和当前线程的Looper进行判断是否在主线程当中
public boolean isMainThread() {
return looper == Looper.myLooper();
}
看下 postToSubscription(newSubscription, stickyEvent, isMainThread())方法
private void postToSubscription(Subscription subscription, Object event, boolean isMainThread) {
switch (subscription.subscriberMethod.threadMode) {
case POSTING:
//线程调用
invokeSubscriber(subscription, event);
break;
case MAIN:
if (isMainThread) {//在主线程,直接调用 invokeSubscriber(subscription, event)方法是通过反射来完成的
invokeSubscriber(subscription, event);
} else {
//mainThreadPoste是new HandlerPoster(eventBus, looper, 10) ,HandlerPoster内部继承了Handler,需要入队
mainThreadPoster.enqueue(subscription, event);
}
break;
case MAIN_ORDERED:
if (mainThreadPoster != null) {
mainThreadPoster.enqueue(subscription, event);
} else {
// temporary: technically not correct as poster not decoupled from subscriber
invokeSubscriber(subscription, event);
}
break;
case BACKGROUND:
if (isMainThread) {//如果在主线程,需要入队
backgroundPoster.enqueue(subscription, event);
} else {//不在UI线程,直接调用
invokeSubscriber(subscription, event);
}
break;
case ASYNC:
//不管是否在主线程,都需要入队列
asyncPoster.enqueue(subscription, event);
break;
default:
throw new IllegalStateException("Unknown thread mode: " + subscription.subscriberMethod.threadMode);
}
}
看下EventBus.getDefault().post()方法
public void post(Object event) {
//PostingThreadState 是发送事件的封装类
//currentPostingThreadState是线程独享的,不会和其它线程共享数据
PostingThreadState postingState = currentPostingThreadState.get();
List<Object> eventQueue = postingState.eventQueue;
eventQueue.add(event);
if (!postingState.isPosting) {
//是否是主线程
postingState.isMainThread = isMainThread();
//当前事件正在分发,其它事件先堵塞在这里
postingState.isPosting = true;
if (postingState.canceled) {
throw new EventBusException("Internal error. Abort state was not reset");
}
try {
while (!eventQueue.isEmpty()) {
postSingleEvent(eventQueue.remove(0), postingState);
}
} finally {
postingState.isPosting = false;
postingState.isMainThread = false;
}
}
}
看下PostingThreadState 类
final static class PostingThreadState {
//事件队列集合
final List<Object> eventQueue = new ArrayList<>();
//是否正在发送
boolean isPosting;
//是否是主线程
boolean isMainThread;
//将订阅者和订阅方法封装起来的封装类
Subscription subscription;
//事件
Object event;
//取消的标志位
boolean canceled;
}
看下 postSingleEvent(eventQueue.remove(0), postingState)方法
private void postSingleEvent(Object event, PostingThreadState postingState) throws Error {
Class<?> eventClass = event.getClass();
boolean subscriptionFound = false;
//是否查看事件有关的继承关系
if (eventInheritance) {
//查找到所有继承关系的事件类型,也就是查找该类的父类
List<Class<?>> eventTypes = lookupAllEventTypes(eventClass);
int countTypes = eventTypes.size();
for (int h = 0; h < countTypes; h++) {
Class<?> clazz = eventTypes.get(h);
subscriptionFound |= postSingleEventForEventType(event, postingState, clazz);
}
} else {
subscriptionFound = postSingleEventForEventType(event, postingState, eventClass);
}
if (!subscriptionFound) {//如果没有任何的事件
if (logNoSubscriberMessages) {
logger.log(Level.FINE, "No subscribers registered for event " + eventClass);
}
if (sendNoSubscriberEvent && eventClass != NoSubscriberEvent.class &&
eventClass != SubscriberExceptionEvent.class) { //发送没有订阅者订阅该事件
post(new NoSubscriberEvent(this, event));
}
}
}
看下postSingleEventForEventType(event, postingState, eventClass)方法
private boolean postSingleEventForEventType(Object event, PostingThreadState postingState, Class<?> eventClass) {
CopyOnWriteArrayList<Subscription> subscriptions;
synchronized (this) {
//获取到订阅事件的集合
subscriptions = subscriptionsByEventType.get(eventClass);
}
if (subscriptions != null && !subscriptions.isEmpty()) {
for (Subscription subscription : subscriptions) {
postingState.event = event;
postingState.subscription = subscription;
boolean aborted = false;
try {
//前面讲过
postToSubscription(subscription, event, postingState.isMainThread);
aborted = postingState.canceled;
} finally {
postingState.event = null;
postingState.subscription = null;
postingState.canceled = false;
}
if (aborted) {
break;
}
}
return true;
}
return false;
}