From 9a634b47f4f5ac48e0571070b1be220ae0f05cd6 Mon Sep 17 00:00:00 2001 From: Xiaofei Date: Wed, 31 Aug 2016 16:14:56 +0800 Subject: [PATCH 1/4] Make a new ObjectCanary --- .idea/misc.xml | 2 +- .../library/hermeseventbus/ObjectCanary2.java | 135 ++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java diff --git a/.idea/misc.xml b/.idea/misc.xml index 8f8b72d..671fecf 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -44,7 +44,7 @@ - + diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java new file mode 100644 index 0000000..599d610 --- /dev/null +++ b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java @@ -0,0 +1,135 @@ +/** + * + * Copyright 2016 Xiaofei + * + * 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 xiaofei.library.hermeseventbus; + +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +import xiaofei.library.concurrentutils.util.Action; +import xiaofei.library.concurrentutils.util.Function; + +/** + * Created by Xiaofei on 16/8/31. + */ +public class ObjectCanary2 { + + private volatile T object; + + private volatile AtomicInteger pendingTaskNumber; + + private final Lock lock; + + private final Condition condition; + + private final ExecutorService executor; + + public ObjectCanary2() { + object = null; + pendingTaskNumber = new AtomicInteger(0); + lock = new ReentrantLock(); + condition = lock.newCondition(); + executor = Executors.newSingleThreadExecutor(); + } + + public void action(final Action action) { + if (object == null || pendingTaskNumber.get() > 0) { + pendingTaskNumber.incrementAndGet(); + executor.execute(new Runnable() { + @Override + public void run() { + if (object == null) { + try { + lock.lock(); + while (object == null) { + condition.await(); + } + action.call(object); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } else { + action.call(object); + } + pendingTaskNumber.decrementAndGet(); + } + }); + } else { + action.call(object); + } + } + + public R calculate(final Function function) { + if (object == null || pendingTaskNumber.get() > 0) { + pendingTaskNumber.incrementAndGet(); + Future future = executor.submit(new Callable() { + @Override + public R call() throws Exception { + R result = null; + if (object == null) { + try { + lock.lock(); + while (object == null) { + condition.await(); + } + result = function.call(object); + } catch (InterruptedException e) { + e.printStackTrace(); + } finally { + lock.unlock(); + } + } else { + result = function.call(object); + } + pendingTaskNumber.decrementAndGet(); + return result; + } + }); + try { + return future.get(); + } catch (InterruptedException e) { + e.printStackTrace(); + } catch (ExecutionException e) { + e.printStackTrace(); + } + return null; + } else { + return function.call(object); + } + } + + public void set(T object) { + if (object == null) { + throw new IllegalArgumentException("You cannot assign null to this object."); + } + lock.lock(); + this.object = object; + condition.signalAll(); + lock.unlock(); + } + +} From 094c3ff7dee5f8f04fd98857c414cf15b83d6ad3 Mon Sep 17 00:00:00 2001 From: Xiaofei Date: Wed, 31 Aug 2016 18:19:32 +0800 Subject: [PATCH 2/4] Finish --- .idea/misc.xml | 2 +- .../hermeseventbus/HermesEventBus.java | 36 +++++++------------ .../library/hermeseventbus/ObjectCanary2.java | 5 ++- 3 files changed, 18 insertions(+), 25 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index 671fecf..8f8b72d 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -44,7 +44,7 @@ - + diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java index ebab131..9bbd1a0 100644 --- a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java +++ b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java @@ -40,10 +40,6 @@ public class HermesEventBus { private static final String HERMES_SERVICE_DISCONNECTED = "Hermes service disconnected!"; - private static final String UNKNOWN_ERROR = "An unknown error occurred. Please report this to the author."; - - private static final int STATE_UNDEFINED = -1; - private static final int STATE_DISCONNECTED = 0; private static final int STATE_CONNECTING = 1; @@ -58,11 +54,11 @@ public class HermesEventBus { private volatile boolean mMainProcess; - private volatile ObjectCanary mRemoteApis; + private volatile ObjectCanary2 mRemoteApis; private volatile MainService mMainApis; - private volatile int mState = STATE_UNDEFINED; + private volatile int mState = STATE_DISCONNECTED; /** * TODO @@ -90,7 +86,7 @@ public class HermesEventBus { private HermesEventBus() { mEventBus = EventBus.getDefault(); - mRemoteApis = new ObjectCanary(); + mRemoteApis = new ObjectCanary2(); } public static HermesEventBus getDefault() { @@ -122,7 +118,7 @@ private static String getCurrentProcessName(Context context) { } public void init(Context context) { - mContext = context; + mContext = context.getApplicationContext(); mMainProcess = isMainProcess(context.getApplicationContext()); if (mMainProcess) { Hermes.init(context); @@ -137,7 +133,7 @@ public void init(Context context) { } public void connectApp(Context context, String packageName) { - mContext = context; + mContext = context.getApplicationContext(); mMainProcess = false; mState = STATE_CONNECTING; Hermes.setHermesListener(new HermesListener()); @@ -169,17 +165,13 @@ private void actionInternal(final Action action) { } else { if (mState == STATE_DISCONNECTED) { Log.w(TAG, HERMES_SERVICE_DISCONNECTED); - } else if (mState == STATE_CONNECTING) { - mRemoteApis.actionNonNullNonBlocking(new Action() { + } else { + mRemoteApis.action(new Action() { @Override public void call(IMainService o) { action.call(o); } }); - } else if (mState == STATE_CONNECTED) { - action.call(mRemoteApis.get()); - } else { - throw new IllegalStateException(UNKNOWN_ERROR); } } } @@ -191,17 +183,13 @@ private T calculateInternal(final Function functi if (mState == STATE_DISCONNECTED) { Log.w(TAG, HERMES_SERVICE_DISCONNECTED); return null; - } else if (mState == STATE_CONNECTING) { - return mRemoteApis.calculateNonNull(new Function() { + } else { + return mRemoteApis.calculate(new Function() { @Override public T call(IMainService o) { return function.call(o); } }); - } else if (mState == STATE_CONNECTED) { - return function.call(mRemoteApis.get()); - } else { - throw new IllegalStateException(UNKNOWN_ERROR); } } } @@ -311,14 +299,16 @@ public void call(IMainService o) { @Override public void onHermesDisconnected(Class service) { // Log.v(TAG, "Hermes disconnected in Process " + Process.myPid()); + mState = STATE_DISCONNECTED; mRemoteApis.action(new Action() { @Override public void call(IMainService o) { o.unregister(Process.myPid()); } }); - mRemoteApis.set(null); - mState = STATE_DISCONNECTED; + // I deleted the statement which assigns null to mRemoteApis. + // Then, if the service is disconnected, the pending events will still be posted + // but this process will not receive them any more. } } diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java index 599d610..754cac2 100644 --- a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java +++ b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java @@ -38,7 +38,7 @@ public class ObjectCanary2 { private volatile T object; - private volatile AtomicInteger pendingTaskNumber; + private final AtomicInteger pendingTaskNumber; private final Lock lock; @@ -56,6 +56,8 @@ public ObjectCanary2() { public void action(final Action action) { if (object == null || pendingTaskNumber.get() > 0) { + // The following statement must be executed before the runnable is put into the queue. + // TODO Will the following statements be reordered at the compile time? pendingTaskNumber.incrementAndGet(); executor.execute(new Runnable() { @Override @@ -75,6 +77,7 @@ public void run() { } else { action.call(object); } + // The following statement must be executed after the action is performed. pendingTaskNumber.decrementAndGet(); } }); From 27904067094b8256e231be3e3157e98dd49cafa7 Mon Sep 17 00:00:00 2001 From: Xiaofei Date: Wed, 31 Aug 2016 18:41:46 +0800 Subject: [PATCH 3/4] Remove two methods in ISubService --- .../xiaofei/library/hermeseventbus/ISubService.java | 6 ------ .../xiaofei/library/hermeseventbus/SubService.java | 12 ------------ 2 files changed, 18 deletions(-) diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ISubService.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ISubService.java index f73c302..3420c86 100644 --- a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ISubService.java +++ b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ISubService.java @@ -32,10 +32,4 @@ public interface ISubService { @MethodId("cancelEventDelivery") void cancelEventDelivery(Object event); - @MethodId("removeStickyEvent") - boolean removeStickyEvent(Object event); - - @MethodId("removeAllStickyEvents") - void removeAllStickyEvents(); - } diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/SubService.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/SubService.java index a149105..311475b 100644 --- a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/SubService.java +++ b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/SubService.java @@ -52,18 +52,6 @@ public void post(Object event) { mEventBus.post(event); } - @MethodId("removeStickyEvent") - @Override - public boolean removeStickyEvent(Object event) { - return mEventBus.removeStickyEvent(event); - } - - @MethodId("removeAllStickyEvents") - @Override - public void removeAllStickyEvents() { - mEventBus.removeAllStickyEvents(); - } - @MethodId("cancelEventDelivery") @Override public void cancelEventDelivery(Object event) { From 675152f061cc9d8d09d989015f61d4e89cf94941 Mon Sep 17 00:00:00 2001 From: Xiaofei Date: Wed, 31 Aug 2016 20:24:13 +0800 Subject: [PATCH 4/4] Version 0.2.0 --- README-zh-CN.md | 4 +- README.md | 4 +- hermes-eventbus/build.gradle | 8 +- .../hermeseventbus/HermesEventBus.java | 14 +- .../library/hermeseventbus/ObjectCanary2.java | 138 ------------------ 5 files changed, 12 insertions(+), 156 deletions(-) delete mode 100644 hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java diff --git a/README-zh-CN.md b/README-zh-CN.md index ed6b8ea..d24e4c4 100644 --- a/README-zh-CN.md +++ b/README-zh-CN.md @@ -51,7 +51,7 @@ public void showText(String text) { ``` dependencies { - compile 'xiaofei.library:hermes-eventbus:0.1.1' + compile 'xiaofei.library:hermes-eventbus:0.2.0' } ``` @@ -61,7 +61,7 @@ dependencies { xiaofei.library hermes-eventbus - 0.1.1 + 0.2.0 pom ``` diff --git a/README.md b/README.md index de6f26f..7f0242d 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ Add the following into your gradle file: ``` dependencies { - compile 'xiaofei.library:hermes-eventbus:0.1.6' + compile 'xiaofei.library:hermes-eventbus:0.2.0' } ``` @@ -74,7 +74,7 @@ For maven, please use the following: xiaofei.library hermes-eventbus - 0.1.6 + 0.2.0 pom ``` diff --git a/hermes-eventbus/build.gradle b/hermes-eventbus/build.gradle index b4320bc..d25474f 100644 --- a/hermes-eventbus/build.gradle +++ b/hermes-eventbus/build.gradle @@ -13,7 +13,7 @@ ext { siteUrl = 'https://github.com/Xiaofei-it/HermesEventBus-OriginalRepo' gitUrl = 'https://github.com/Xiaofei-it/HermesEventBus-OriginalRepo.git' - libraryVersion = '0.1.6' + libraryVersion = '0.2.0' developerId = 'Xiaofei-it' developerName = 'Eric Zhao' @@ -31,8 +31,8 @@ android { defaultConfig { minSdkVersion 8 targetSdkVersion 23 - versionCode 2 - versionName "0.1.6" + versionCode 3 + versionName "0.2.0" } buildTypes { release { @@ -48,7 +48,7 @@ dependencies { compile 'com.android.support:appcompat-v7:23.3.0' compile 'org.greenrobot:eventbus:3.0.0' compile 'xiaofei.library:hermes:0.6.1' - compile 'xiaofei.library:concurrent-utils:0.1.3' + compile 'xiaofei.library:concurrent-utils:0.1.4' } apply from: 'https://raw.githubusercontent.com/nuuneoi/JCenter/master/installv1.gradle' diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java index 9bbd1a0..2684e34 100644 --- a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java +++ b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/HermesEventBus.java @@ -25,7 +25,7 @@ import org.greenrobot.eventbus.EventBus; -import xiaofei.library.concurrentutils.ObjectCanary; +import xiaofei.library.concurrentutils.ObjectCanary2; import xiaofei.library.concurrentutils.util.Action; import xiaofei.library.concurrentutils.util.Function; import xiaofei.library.hermes.Hermes; @@ -61,27 +61,21 @@ public class HermesEventBus { private volatile int mState = STATE_DISCONNECTED; /** - * TODO * * 1. Consider more about the interleaving, especially when the service is being connected or disconnected. * - * 2. I should solve the following problems in the future: + * 2. Pay attention to the following cases: * * (1) Before the connection succeeds, e1, e2 and e3 are put into the queue. * Then when the connection succeeds, they are posted one by one. * However, after e1 is posted, we post another event e4. - * How can I guarantee that e4 is posted after e3? + * I should guarantee that e4 is posted after e3. * * (2) Before the connection succeeds, some sticky events (e1, e2 and e3) * are put into the queue. * Then when the connection succeeds, they are posted one by one. * However, after e1 is posted, we get a sticky event. - * How can I guarantee that we get e3 rather than e1? - * - * I have made some modifications in the concurrent library but has not imported it - * into HermesEventBus. - * Work remains to be done in the future. - * + * I should guarantee that we get e3 rather than e1. */ private HermesEventBus() { diff --git a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java b/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java deleted file mode 100644 index 754cac2..0000000 --- a/hermes-eventbus/src/main/java/xiaofei/library/hermeseventbus/ObjectCanary2.java +++ /dev/null @@ -1,138 +0,0 @@ -/** - * - * Copyright 2016 Xiaofei - * - * 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 xiaofei.library.hermeseventbus; - -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.concurrent.locks.Condition; -import java.util.concurrent.locks.Lock; -import java.util.concurrent.locks.ReentrantLock; - -import xiaofei.library.concurrentutils.util.Action; -import xiaofei.library.concurrentutils.util.Function; - -/** - * Created by Xiaofei on 16/8/31. - */ -public class ObjectCanary2 { - - private volatile T object; - - private final AtomicInteger pendingTaskNumber; - - private final Lock lock; - - private final Condition condition; - - private final ExecutorService executor; - - public ObjectCanary2() { - object = null; - pendingTaskNumber = new AtomicInteger(0); - lock = new ReentrantLock(); - condition = lock.newCondition(); - executor = Executors.newSingleThreadExecutor(); - } - - public void action(final Action action) { - if (object == null || pendingTaskNumber.get() > 0) { - // The following statement must be executed before the runnable is put into the queue. - // TODO Will the following statements be reordered at the compile time? - pendingTaskNumber.incrementAndGet(); - executor.execute(new Runnable() { - @Override - public void run() { - if (object == null) { - try { - lock.lock(); - while (object == null) { - condition.await(); - } - action.call(object); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - } else { - action.call(object); - } - // The following statement must be executed after the action is performed. - pendingTaskNumber.decrementAndGet(); - } - }); - } else { - action.call(object); - } - } - - public R calculate(final Function function) { - if (object == null || pendingTaskNumber.get() > 0) { - pendingTaskNumber.incrementAndGet(); - Future future = executor.submit(new Callable() { - @Override - public R call() throws Exception { - R result = null; - if (object == null) { - try { - lock.lock(); - while (object == null) { - condition.await(); - } - result = function.call(object); - } catch (InterruptedException e) { - e.printStackTrace(); - } finally { - lock.unlock(); - } - } else { - result = function.call(object); - } - pendingTaskNumber.decrementAndGet(); - return result; - } - }); - try { - return future.get(); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (ExecutionException e) { - e.printStackTrace(); - } - return null; - } else { - return function.call(object); - } - } - - public void set(T object) { - if (object == null) { - throw new IllegalArgumentException("You cannot assign null to this object."); - } - lock.lock(); - this.object = object; - condition.signalAll(); - lock.unlock(); - } - -}