Я использую этот подход:
У меня есть поле в деятельности, которая хранит поток. В onRetainNonConfigurationInstance () ответьте на это поле. Таким образом он сохраняется и становится доступным для нового экземпляра действия позже.
В onStart () я получаю поток из getLastNonConfigurationInstance (). Это либо значение NULL (поток не запущен), либо ссылка на поток, сохраненный функцией onRetainNonConfigurationInstance ().
Если вы показываете (и вам необходимо восстановить) диалоговое окно прогресса, у вас также должно быть состояние в потоке (например, STARTED, RUNNING, DONE и т. Д.) Для обработки восстановления отображения прогресса в onStart ().
Если вам нужно связаться с потоком, вы можете захотеть добавить обработчик (например, как параметр для конструктора потока).
Вот пример. Поток считывает данные GPS из базы данных для последующей постобработки. Я пытался показать только соответствующий код здесь, имена методов пропущенных методов должны говорить сами за себя,
Это все из класса занятий:
private ProgressDialog progressDialog = null;
private LoadGpsDataThread loadGpsLogThread = null;
Это обработчик, используемый для связи:
/**
* This handler updates the progress dialog when the logged GPS data is loaded.
*/
final Handler progressHandler = new Handler() {
@Override
public void handleMessage(final Message msg) {
Bundle b;
switch( msg.arg2 ) {
case UPDATE_LOADER:
// Update from GPS data loading thread
final int total = msg.arg1;
if( GpsPostprocessingActivity.this.progressDialog != null )
GpsPostprocessingActivity.this.progressDialog.setProgress(total);
if( GpsPostprocessingActivity.this.loadGpsLogThread != null && GpsPostprocessingActivity.this.loadGpsLogThread.state == STATE_DONE ) {
GpsPostprocessingActivity.this.dismissProgress();
GpsPostprocessingActivity.this.fillGraphView();
}
break;
case IGpsDataPostProccessor.STATUS_ANALYZER:
GpsPostprocessingActivity.this.statusView.setText(msg.arg1);
break;
case IGpsDataPostProccessor.UPDATE_ANALYZER:
int sample;
switch( msg.arg1 ) {
// ...
}
break;
case IGpsDataPostProccessor.GRAPH_UPDATE:
GpsPostprocessingActivity.this.fillGraphView();
break;
}
break;
}
}
};
Вот метод, запускающий поток, обратите внимание на обработчик как параметр конструктора:
/**
* Load the GPS data from the database.
* @param loading if <code>true</code> the load thread is already
* running. In this case only the progress dialog is opened.
*/
private void loadGpsData(final boolean loading) {
if( DEBUG )
Log.d( TAG, "loadGpsData: Loading GPS data, already loading = " + loading);
final int dataSize = this.gpsFlight.size();
final String title = this.globalState.getString(R.string.titel_load_gps_data);
final String msg = this.globalState.getFormattedTemplate(R.string.msg_tmpl_loading_gps_data, this.flightDesc);
this.showProgress(title, msg, dataSize);
if( ! loading ) {
this.loadGpsLogThread = new LoadGpsDataThread(this.progressHandler);
this.loadGpsLogThread.start();
}
}
@Override
public Object onRetainNonConfigurationInstance() {
// Dialog is removed in onSaveInstanceState(), see comment there
// Check that there is a worker thread that
// needs preserving
if (this.loadGpsLogThread != null) {
// remove reference to this activity (important to avoid memory leak)
this.loadGpsLogThread.handler = null;
// Return the instance to be retained
if( DEBUG )
Log.d( TAG, "onRetainNonConfigurationInstance: saved process");
return this.loadGpsLogThread;
}
return super.onRetainNonConfigurationInstance();
}
Вот логика запуска:
@Override
protected void onStart() {
if( DEBUG )
Log.d(TAG, "onStart");
super.onStart();
this.refreshData();
this.flightView.setText(this.flightDesc);
this.logView.setText(this.getGpsLogDescription());
this.statusView.setText(null);
this.initProfileSpinner();
// graphView is set asynchronously by the GPS data loading thread
// Get the last load thread and check whether it is still running
if (this.getLastNonConfigurationInstance() != null) {
this.loadGpsLogThread = (LoadGpsDataThread) this.getLastNonConfigurationInstance();
this.loadGpsLogThread.handler = this.progressHandler;
switch (this.loadGpsLogThread.state) {
case STATE_RUNNING:
// Show the progress dialog again
this.loadGpsData(true);
break;
case STATE_NOT_STARTED:
// Close the progress dialog in case it is open
this.dismissDialog(PROGRESS_DIALOG);
break;
case STATE_DONE:
this.loadGpsLogThread = null;
// Close the progress dialog in case it is open
this.dismissDialog(PROGRESS_DIALOG);
break;
default:
// Close the progress dialog in case it is open
// Get rid of the sending thread
if( DEBUG )
Log.d(TAG, "Unknown progress thread state");
this.dismissProgress();
}
}
else {
if( ! this.globalState.detectorState.isGpsDataCacheAvailable(this.gpsFlight) ) {
this.loadGpsData(false);
this.analysisResult = null;
}
else
// data already loaded
this.fillGraphView();
}
this.graphView.setShowLines(this.globalState.getBooleanPref(IPreferences.PREFS_GPS_GRAPH_LINES));
this.processSubActivityResult();
}
Это нить как внутренний класс:
/**
* This thread loads the GPS data from the database and
* updates the progress dialog via the handler.
*/
private class LoadGpsDataThread extends Thread {
Handler handler;
int state;
int stepsDone;
LoadGpsDataThread(final Handler h) {
this.handler = h;
this.state = STATE_NOT_STARTED;
}
@Override
public void run() {
this.state = STATE_RUNNING;
this.stepsDone = 0;
final Cursor c = GpsPostprocessingActivity.this.queryGpsData();
try {
while (c.moveToNext() && (this.state == STATE_RUNNING)) {
final TrackData row = GpsPostprocessingActivity.this.globalState.getDb().readGpsData(c);
GpsPostprocessingActivity.this.globalState.detectorState.gpsData[this.stepsDone] = row;
this.stepsDone += 1;
if( this.handler != null ) {
// can be null if the activity has been destroyed
final Message msg = this.handler.obtainMessage();
msg.arg1 = this.stepsDone;
msg.arg2 = UPDATE_LOADER;
this.handler.sendMessage(msg);
}
}
}
finally {
this.state = STATE_DONE;
c.close();
}
if( DEBUG )
Log.d(TAG, "Data load thread finished");
}
}