Android架构组件中Executor的用法

5
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());
        }
    });
}
}

上面的代码是来自于Android文档中"应用架构指南"的一部分,使用了架构组件。在refreshUser方法中,如果缓存中不存在数据,则使用retrofit从网络获取数据。
我的问题是:为什么他们要使用执行器?Retrofit本身已经可以异步运行网络请求了。
请为我澄清什么是Executor以及在这个例子中它的作用。
2个回答

8
开箱即用的Room不支持在主线程上访问数据库,因此执行器确保在单独的线程上完成工作。通过使用执行器,他们还选择使用同步的Retrofit调用,这将阻塞执行线程。在你所引用的代码中,执行器是SingleThreadExecutor,这实际上创建了一个单个工作线程来执行其工作,在本例中将执行Room DB操作以及处理同步的Retrofit调用。这是上面示例中执行器的链接。https://github.com/PhilippeBoisney/GithubArchitectureComponents/blob/98e0a048791f18646c730323c242c670c3eaf453/app/src/main/java/com/boisneyphilippe/githubarchitecturecomponents/di/module/AppModule.java#L48。还有关于newSingleThreadExecutor的官方文档:https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Executors.html#newSingleThreadExecutor()

你好 Chris,能否请你查看一下我的新问题:https://dev59.com/Oa7la4cB1Zd3GeqPYSgf。谢谢! - user10314481
从技术上讲,Room 确实支持在主线程上通过调用allowMainThreadQueries()来访问数据库。然而,良好的实践是只在后台线程上访问数据库。 - tronman

7

Executor是什么?

Executor通常用于代替显式创建线程。例如,你可以使用以下方式来执行一组任务,而不是为每个任务调用new Thread(new RunnableTask()).start()

Executor executor = someExecutor();  // any class implementing `Executor` interface
executor.execute(new Runnable1());
executor.execute(new Runnable2());

为什么要使用执行器?Retrofit本身已经能够异步运行网络请求。
他们使用它来从主线程切换到后台工作线程,执行数据库操作,因为默认情况下,Room架构组件不允许在MainThread上进行查询。
Retrofit能够执行异步网络请求,但是在这里他们正在执行同步网络请求,之后只是使用Room组件对本地数据库执行插入操作。
有关Executor框架的更多信息,请参阅此指南:https://developer.android.com/reference/java/util/concurrent/Executor

2
这里的someExecutor()是什么意思? - blackjack
1
@blackjack 现在已经太晚了,但是 someExecutor 是一个实现了 Executor 接口的类。 - starriet

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接