问题
public class UserRepository {
private final Webservice webservice;
private final UserDao userDao;
private final Executor executor;
@Inject
public UserRepository(Webservice webservice, UserDao userDao, Executor executor) {
this.webservice = webservice;
this.userDao = userDao;
this.executor = executor;
}
public LiveData<User> getUser(String userId) {
refreshUser(userId);
// Returns a LiveData object directly from the database.
return userDao.load(userId);
}
private void refreshUser(final String userId) {
// Runs in a background thread.
executor.execute(() -> {
// Check if user data was fetched recently.
boolean userExists = userDao.hasUser(FRESH_TIMEOUT);
if (!userExists) {
// Refreshes the data.
Response<User> response = webservice.getUser(userId).execute();
// Check for errors here.
// Updates the database. The LiveData object automatically
// refreshes, so we don't need to do anything else here.
userDao.save(response.body());
}
});
}
}
code above is a part from "Guide to app architecture" using architecture components. Inside refreshUser method they fetch data from network using retrofit if data doesn't exists in cache.
My question is: Why do they use an executor for this? Retrofit itself is already capable of running network request asynchronously.
Please clarify what exactly is an Executor and its need in this example for me.
回答1:
Out of the box room doesn't support database access on the main thread so the executor is there to ensure the work is done on a separate thread.
By using the executor they've also opted to use the synchronous retrofit call which will block the executing thread.
In the code you're referencing the executor is a SingleThreadExecutor, this essentially creates a single worker thread to execute its work, which in this case will execute the Room DB operations along with handling the synchronous retrofit call.
This is the link the to executor in the above example. https://github.com/PhilippeBoisney/GithubArchitectureComponents/blob/98e0a048791f18646c730323c242c670c3eaf453/app/src/main/java/com/boisneyphilippe/githubarchitecturecomponents/di/module/AppModule.java#L48
Along with the official docs for newSingleThreadExecutor: https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor()
回答2:
What exactly is an Executor?
An Executor is normally used instead of explicitly creating threads. For example, rather than invoking new Thread(new RunnableTask()).start()
for each of a set of tasks, you might use:
Executor executor = someExecutor();
executor.execute(new Runnable1());
executor.execute(new Runnable2());
Why do they use an executor for this? Retrofit itself is already capable of running network request asynchronously.
They have used it to switch to a background worker thread from the main thread, to perform a database operation, since by default, Room architecture component does not allow queries on the MainThread
.
Retrofit is capable of performing async network requests, but they are doing a synchronous network request here instead after which they are just performing a insert operation on local database using Room component.
For more information about Executor framework, you can follow this guide: https://developer.android.com/reference/java/util/concurrent/Executor
来源:https://stackoverflow.com/questions/52164957/usage-of-executor-in-android-architecture-components