I am trying to update my app to handle configuration changes (especially screen turning) manually.
I have some questions about what happens when changes happen during a Thread execution.
I have created an abstract class I call ThreadTask which uses Threads and Handlers to the main thread's looper to send updates to the main thread. This is my implementation of AsyncTask but with threads, I prefer this to using AsyncTask because I have more control over it.
It also has two methods to register an observer to the above events, it uses this interface:
public interface TaskObserver {
void pre_execute();
void on_progress(ProgressData progress);
void finished(Object result);
void cancelled(Object result);
}
The abstract members that the subclass must implement are :
abstract Object do_in_background();
and some concrete members are:
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
So when I implement a concrete class it would go something like this:
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);
}
}
}
and I updated the activity that calls this like so:
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);
}
}
this makes sure that I always have a reference to the correct thread
When I wish to start the task I do it like so:
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
})
and when the thread finishes it calls void finished(Object result) which I handle like so:
void finished(Object result) {
try {
//get result;
} finally {
_data.task.remove(this);
_data.task = null;
}
}
here are my questions:
a) is declaring my observer methods as synchronized necessary? I did it just to make sure , but when the activity is destroyed and then recreated, does it happen on the same thread? is there a chance for example that a progress_update may happen while an observer is being removed during onDestroy?
b) what will happen if a thread finishes and calls post_execute(which is important) during a configuration change? will the update be lost?
c) If indeed the update is lost because it currently has no observers, is there a way, either in my implementation or a different one, to handle the above?
Thanks in advance for any help you can provide