diff --git a/.travis.yml b/.travis.yml index 32ebe05c07..9ac2659eac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ android: - tools - platform-tools - build-tools-27.0.3 - - android-27 + - android-28 - extra-google-google_play_services - extra-android-m2repository - extra-android-support diff --git a/blessedDeps.gradle b/blessedDeps.gradle index 6a7f2db8d5..da02d21a5c 100644 --- a/blessedDeps.gradle +++ b/blessedDeps.gradle @@ -10,8 +10,8 @@ rootProject.ext.JAVA_SOURCE_VERSION = JavaVersion.VERSION_1_7 rootProject.ext.JAVA_TARGET_VERSION = JavaVersion.VERSION_1_7 -rootProject.ext.TARGET_SDK_VERSION = 27 -rootProject.ext.COMPILE_SDK_VERSION = 27 +rootProject.ext.TARGET_SDK_VERSION = 28 +rootProject.ext.COMPILE_SDK_VERSION = 28 rootProject.ext.MIN_SDK_VERSION = 14 rootProject.ext.MIN_SDK_VERSION_LITHO = 15 diff --git a/build.gradle b/build.gradle index e4c111cb88..c879b98aab 100755 --- a/build.gradle +++ b/build.gradle @@ -2,7 +2,7 @@ buildscript { ext.KOTLIN_VERSION = "1.2.60" - ext.ANDROID_PLUGIN_VERSION = "3.1.3" + ext.ANDROID_PLUGIN_VERSION = "3.1.4" repositories { google() diff --git a/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyController.java b/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyController.java new file mode 100644 index 0000000000..b720b12747 --- /dev/null +++ b/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyController.java @@ -0,0 +1,41 @@ +package com.airbnb.epoxy; + +import android.os.Handler; + +import static com.airbnb.epoxy.EpoxyAsyncUtil.MAIN_THREAD_HANDLER; +import static com.airbnb.epoxy.EpoxyAsyncUtil.getAsyncBackgroundHandler; + +/** + * A subclass of {@link EpoxyController} that makes it easy to do model building and diffing in + * the background. + *
+ * See https://github.com/airbnb/epoxy/wiki/Epoxy-Controller#asynchronous-support
+ */
+public abstract class AsyncEpoxyController extends EpoxyController {
+
+ /**
+ * A new instance that does model building and diffing asynchronously.
+ */
+ public AsyncEpoxyController() {
+ this(true);
+ }
+
+ /**
+ * @param enableAsync True to do model building and diffing asynchronously, false to do them
+ * both on the main thread.
+ */
+ public AsyncEpoxyController(boolean enableAsync) {
+ this(true, true);
+ }
+
+ /**
+ * Individually control whether model building and diffing are done async or on the main thread.
+ */
+ public AsyncEpoxyController(boolean enableAsyncModelBuilding, boolean enableAsyncDiffing) {
+ super(getHandler(enableAsyncModelBuilding), getHandler(enableAsyncDiffing));
+ }
+
+ private static Handler getHandler(boolean enableAsync) {
+ return enableAsync ? getAsyncBackgroundHandler() : MAIN_THREAD_HANDLER;
+ }
+}
diff --git a/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyDiffer.java b/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyDiffer.java
index 98190a8a32..24f1e9674d 100644
--- a/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyDiffer.java
+++ b/epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyDiffer.java
@@ -162,7 +162,9 @@ private void onRunCompleted(
@Nullable final DiffResult result
) {
- MainThreadExecutor.INSTANCE.execute(new Runnable() {
+ // We use an asynchronous handler so that the Runnable can be posted directly back to the main
+ // thread without waiting on view invalidation synchronization.
+ MainThreadExecutor.ASYNC_INSTANCE.execute(new Runnable() {
@Override
public void run() {
final boolean dispatchResult = tryLatchList(newList, runGeneration);
diff --git a/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAsyncUtil.java b/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAsyncUtil.java
new file mode 100644
index 0000000000..2bf449b421
--- /dev/null
+++ b/epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAsyncUtil.java
@@ -0,0 +1,103 @@
+package com.airbnb.epoxy;
+
+import android.os.Build;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.support.annotation.MainThread;
+import android.support.annotation.Nullable;
+
+import java.lang.reflect.Constructor;
+
+/**
+ * Various helpers for running Epoxy operations off the main thread.
+ */
+public final class EpoxyAsyncUtil {
+ private EpoxyAsyncUtil() {
+ }
+
+ /**
+ * A Handler class that uses the main thread's Looper.
+ */
+ public static final Handler MAIN_THREAD_HANDLER =
+ createHandler(Looper.getMainLooper(), false);
+
+ /**
+ * A Handler class that uses the main thread's Looper. Additionally, this handler calls
+ * {@link Message#setAsynchronous(boolean)} for
+ * each {@link Message} that is sent to it or {@link Runnable} that is posted to it
+ */
+ public static final Handler AYSNC_MAIN_THREAD_HANDLER =
+ createHandler(Looper.getMainLooper(), true);
+
+ private static Handler asyncBackgroundHandler;
+
+ /**
+ * A Handler class that uses a separate background thread dedicated to Epoxy. Additionally,
+ * this handler calls {@link Message#setAsynchronous(boolean)} for
+ * each {@link Message} that is sent to it or {@link Runnable} that is posted to it
+ */
+ @MainThread
+ public static Handler getAsyncBackgroundHandler() {
+ // This is initialized lazily so we don't create the thread unless it will be used.
+ // It isn't synchronized so it should only be accessed on the main thread.
+ if (asyncBackgroundHandler == null) {
+ asyncBackgroundHandler = createHandler(buildBackgroundLooper("epoxy"), true);
+ }
+
+ return asyncBackgroundHandler;
+ }
+
+ /**
+ * Create a Handler with the given Looper
+ *
+ * @param async If true the Handler will calls {@link Message#setAsynchronous(boolean)} for
+ * each {@link Message} that is sent to it or {@link Runnable} that is posted to it.
+ */
+ public static Handler createHandler(Looper looper, boolean async) {
+ if (!async) {
+ return new Handler(looper);
+ }
+
+ if (Build.VERSION.SDK_INT >= 28) {
+ return Handler.createAsync(looper);
+ }
+
+ if (Build.VERSION.SDK_INT >= 17) {
+ Constructor> {
public interface AdapterCallbacks {
void onAddCarouselClicked();
@@ -31,18 +30,10 @@ public interface AdapterCallbacks {
private final AdapterCallbacks callbacks;
- private static final Handler BACKGROUND_HANDLER;
-
- static {
- HandlerThread handlerThread = new HandlerThread("epoxy");
- handlerThread.start();
- BACKGROUND_HANDLER = new Handler(handlerThread.getLooper());
- }
-
SampleController(AdapterCallbacks callbacks) {
// Demonstrating how model building and diffing can be done in the background.
// You can control them separately by passing in separate handler, as shown below.
- super(BACKGROUND_HANDLER, BACKGROUND_HANDLER);
+ super(getAsyncBackgroundHandler(), getAsyncBackgroundHandler());
// super(new Handler(), BACKGROUND_HANDLER);
// super(BACKGROUND_HANDLER, new Handler());