我正在尝试更新我的应用以手动处理配置更改(尤其是屏幕转换)。
我对在线程执行期间发生更改时会发生什么有一些疑问。
我创建了一个抽象类,我调用ThreadTask,它使用Threads和Handlers到主线程的looper来向主线程发送更新。这是我对AsyncTask的实现,但是对于线程,我更喜欢使用AsyncTask,因为我可以更好地控制它。
它还有两种将观察者注册到上述事件的方法,它使用这个接口:
public interface TaskObserver {
void pre_execute();
void on_progress(ProgressData progress);
void finished(Object result);
void cancelled(Object result);
}
子类必须实现的抽象成员是:
abstract Object do_in_background();
并且一些具体成员是:
synchronized void add_observer(TaskObserver observer){
_observers.add(observer);
}
synchronized void remove_observer(TaskObserver observer){
_observers.remove(observer);
}
synchronized void post_execute(Object result) {
int observers = _observers.size();
for (int idx = 0; idx < observers; idx++) {
_observers.get(idx).finished(result);
}
}
///plus all the other methods of the interface
所以当我实现一个具体的类时,它会像这样:
public class MyThreadTask extends ThreadTask{
@Override
Object do_in_background() {
progress.primary_max = 5;
for (int cur = 0 ; cur < 5 ; cur++) {
progress.primary = cur;
publish();
Thread.Sleep(3000);
}
}
}
我更新了调用它的活动:
static final string TAG ="my_main_activity";
MyDataFragment _data; //this is a datafragment, a fragment with retaininstancestate , and a public `MyThreadTask task` variable
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (_data == null) {
_data = (MyDataFragment)getFragmentManager().findFragmentByTag(TAG + "_data");
if (_data == null) {
_data = new MyDataFragment();
getFragmentManager().beginTransaction().add(_data, TAG + "_data").commit();
}
}
if (_data.task != null) {
_data.task.register(this);
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (_data.task != null) {
_data.task.remove(this);
}
}
这确保我总是引用正确的线程
当我希望开始这项任务时,我会这样做:
button.setOnClickListener((v) -> {
if (_data.task != null) return; //to make sure only one thread starts at a time
_data.task = new MyThreadTask();
_data.task.register(this);
_data.task.start(); //this is not thread's start, it is mine, it does other things too
})
当线程完成时,调用void finished(Object result),我这样处理:
void finished(Object result) {
try {
//get result;
} finally {
_data.task.remove(this);
_data.task = null;
}
}
这是我的问题:
a)声明我的观察者方法是否同步必要?我这样做是为了确保,但是当活动被销毁然后重新创建时,是否会在同一个线程上发生?例如,在onDestroy期间移除观察者时可能会发生progress_update吗?
b)如果线程在配置更改期间完成并调用post_execute(这很重要)会发生什么?更新会丢失吗?
c)如果确实由于当前没有观察者而导致更新丢失,是否有办法在我的实现或不同的实现中处理上述内容?
提前感谢您提供的任何帮助
答案 0 :(得分:0)
通过配置更改使后台任务保持活动状态的首选方法是将其托管在retained fragment中。片段的相同实例将通过配置更改持续存在。当片段暂停时,检查活动的isChangingConfigurations并仅在任务为假时取消该任务。
我不知道这是否记录在任何地方,但似乎整个配置更改都发布到主线程,以便在暂停旧活动和恢复新活动之间不会运行任何其他操作。如果您在保留的片段中使用onPostExecute
,则可以确保在配置更改期间其JSONObject
无法运行。通过您的方法,当没有观察者时,任务可以轻松完成。
答案 1 :(得分:0)
Asynctask不能很好地处理配置更改。我认为,你应该使用A synctaskLoader代替Asynctask,它可以轻松处理配置更改,并且它在活动/片段的生命周期内表现。
当您运行AsyncTask并且如果Android系统杀死您的活动/片段(在配置更改或内存保护期间),那么您的 doInBackground()方法仍然在后台继续运行,这可能会导致不良后果。
因此,您可以使用 AsynctaskLoader 代替使用AsyncTask,或者如果您从SQLite填充数据,则可以使用 CursorLoader 。
参考文献: