Android:有关在线程运行时手动处理配置更改的问题

时间:2017-09-14 10:56:20

标签: android java-threads

我正在尝试更新我的应用以手动处理配置更改(尤其是屏幕转换)。

我对在线程执行期间发生更改时会发生什么有一些疑问。

我创建了一个抽象类,我调用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)如果确实由于当前没有观察者而导致更新丢失,是否有办法在我的实现或不同的实现中处理上述内容?

提前感谢您提供的任何帮助

2 个答案:

答案 0 :(得分:0)

通过配置更改使后台任务保持活动状态的首选方法是将其托管在retained fragment中。片段的相同实例将通过配置更改持续存在。当片段暂停时,检查活动的isChangingConfigurations并仅在任务为假时取消该任务。

我不知道这是否记录在任何地方,但似乎整个配置更改都发布到主线程,以便在暂停旧活动和恢复新活动之间不会运行任何其他操作。如果您在保留的片段中使用onPostExecute,则可以确保在配置更改期间其JSONObject无法运行。通过您的方法,当没有观察者时,任务可以轻松完成。

答案 1 :(得分:0)

Asynctask不能很好地处理配置更改。我认为,你应该使用A synctaskLoader代替Asynctask,它可以轻松处理配置更改,并且它在活动/片段的生命周期内表现。

当您运行AsyncTask并且如果Android系统杀死您的活动/片段(在配置更改或内存保护期间),那么您的 doInBackground()方法仍然在后台继续运行,这可能会导致不良后果。

因此,您可以使用 AsynctaskLoader 代替使用AsyncTask,或者如果您从SQLite填充数据,则可以使用 CursorLoader

参考文献:

  1. Guideline to choose among AsyncTaskLoader and AsyncTask to be used in Fragment

  2. https://developer.android.com/reference/android/content/AsyncTaskLoader.html