避免在方向更改时重新启动线程

时间:2012-01-29 12:49:27

标签: android android-activity orientation

我的activity的oncreate()方法中有一些线程。当方向改变时,线程再次重新启动(每次方向更改时都会创建新的线程实例)。

我不想使用android:configChangesandroid:screenOrientation。因为活动取决于方向。

2 个答案:

答案 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()不会被调用,并且您的踏板不会重新启动,但您的布局将会旋转。

相关问题