使用 @Background 注释时,我们启动一个新线程。如果我们在这个线程执行旋转屏幕的时候,我们会丢失来自那个线程的回调吗?或者如何处理?使用 Loaders,这在屏幕后面进行了整理,因此我们不必担心使用异步任务时经常发生的问题。
但是@Background 注释是如何处理这个问题的呢?
使用 @Background 注释时,我们启动一个新线程。如果我们在这个线程执行旋转屏幕的时候,我们会丢失来自那个线程的回调吗?或者如何处理?使用 Loaders,这在屏幕后面进行了整理,因此我们不必担心使用异步任务时经常发生的问题。
但是@Background 注释是如何处理这个问题的呢?
首先,当你使用@Background注解时,代码是在单独的线程上执行的,但这并不一定意味着会启动一个新的线程,因为我们使用了一个普通的线程池(可以替换)所有@Background 方法。
与 AsyncTask 一样,@Background 不会处理您的活动的任何生命周期更改。因此,如果您调用@Background 方法然后旋转屏幕,那么无论如何都会在调用它的实例上执行@Background 代码。如果将@Background 放置在属于该活动的方法上,并依次调用@UiThread 方法,则如果发生配置更改,则可能会在错误的活动实例上调用@UiThread 方法。
在 Android 中,在加载器之前,通常的处理方法是使用 AsyncTask,在 onRetainNonConfigurationInstance() 中保留对这些任务的引用,并在配置更改后将它们重新绑定到新活动。
在最新版本中,AndroidAnnotations 提供了@NonConfiguration 实例注解,可以与@EBean / @Bean 和@Background 组合使用,达到同样的效果。
这是一个示例代码(未经测试,由 gmail 编写):
@EActivity
public class MyActivity extends Activity {
// Using @NonConfigurationInstance on a @Bean will automatically update the context ref on configuration changes (if the bean is not a singleton)
@NonConfigurationInstance
@Bean
MyBackgroundTask task;
@Click
void myButtonClicked() {
task.doSomethingInBackground();
}
void showResult(MyResult result) {
// do something with result
}
}
@EBean
public void MyBackgroundTask {
@RootContext
MyActivity activity;
@Background
void doSomethingInBackground() {
// do something
MyResult result = XXX;
updateUI(result);
}
// Notice that we manipulate the activity ref only from the UI thread
@UiThread
void updateUI(MyResult result) {
activity.showResult(result);
}
}
我认为我们可以提供更好的解决方案,但是有很多不同的用例,我们需要全部考虑。所以现在,@Background 有一个非常简单的行为,我不想改变它。但是,我们可以引入具有高级“线程 + 生命周期”行为的新注释。
感谢“Pierre-Yves Ricau”通过 googlegroup 为 androidannotations 提供此答案。希望这将帮助其他可能遇到类似问题的人。