我的activity的oncreate()方法中有一些线程。当方向改变时,线程再次重新启动(每次方向更改时都会创建新的线程实例)。
我不想使用android:configChanges
或android:screenOrientation
。因为活动取决于方向。
答案 0 :(得分:2)
我正在使用这种方法: 我在活动中有一个存储线程的字段。在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");
}
}
答案 1 :(得分:2)
使用android:configChanges
,但在覆盖onConfigurationChanged()
方法时,只调用super.onConfigurationCanged()
方法(或者通常不要覆盖它)。
在旋转时,onCreate()不会被调用,并且您的踏板不会重新启动,但您的布局将会旋转。