-
Notifications
You must be signed in to change notification settings - Fork 730
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Async improvements #509
Merged
Merged
Async improvements #509
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
41 changes: 41 additions & 0 deletions
41
epoxy-adapter/src/main/java/com/airbnb/epoxy/AsyncEpoxyController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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. | ||
* <p> | ||
* 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; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
103 changes: 103 additions & 0 deletions
103
epoxy-adapter/src/main/java/com/airbnb/epoxy/EpoxyAsyncUtil.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<Handler> handlerConstructor = asyncHandlerConstructor(); | ||
if (handlerConstructor != null) { | ||
try { | ||
return handlerConstructor.newInstance(looper, null, true); | ||
} catch (Throwable e) { | ||
// Fallback | ||
} | ||
} | ||
} | ||
|
||
return new Handler(looper); | ||
} | ||
|
||
/** | ||
* Create a new looper that runs on a new background thread. | ||
*/ | ||
public static Looper buildBackgroundLooper(String threadName) { | ||
HandlerThread handlerThread = new HandlerThread(threadName); | ||
handlerThread.start(); | ||
return handlerThread.getLooper(); | ||
} | ||
|
||
@Nullable | ||
private static Constructor<Handler> asyncHandlerConstructor() { | ||
try { | ||
//noinspection JavaReflectionMemberAccess | ||
return Handler.class.getConstructor( | ||
Looper.class, | ||
Handler.Callback.class, | ||
Boolean.class | ||
); | ||
} catch (Throwable e) { | ||
return null; | ||
} | ||
} | ||
} |
12 changes: 8 additions & 4 deletions
12
epoxy-adapter/src/main/java/com/airbnb/epoxy/MainThreadExecutor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,12 +1,16 @@ | ||
package com.airbnb.epoxy; | ||
|
||
import android.os.Handler; | ||
import android.os.Looper; | ||
|
||
import static com.airbnb.epoxy.EpoxyAsyncUtil.createHandler; | ||
|
||
class MainThreadExecutor extends HandlerExecutor { | ||
static final MainThreadExecutor INSTANCE = new MainThreadExecutor(); | ||
static final MainThreadExecutor INSTANCE = new MainThreadExecutor(false); | ||
static final MainThreadExecutor ASYNC_INSTANCE = new MainThreadExecutor(true); | ||
|
||
MainThreadExecutor() { | ||
super(new Handler(Looper.getMainLooper())); | ||
MainThreadExecutor(boolean async) { | ||
super(createHandler(Looper.getMainLooper(), async)); | ||
} | ||
} | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enableAsync
is unused.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@baoti whoops! thanks a lot for catching that