我有一個應用程序設計爲每10ms記錄傳感器數據並存儲到手機上的SQLite數據庫。我正在做數據庫插入作爲異步任務,因爲他們發生得太快了,而且他們中有很多人會顯着減慢導航速度。但是,在嘗試停止錄製時,偶爾會遇到問題。Android:正確地停止異步任務
在我的一個片段中有一個開始停止按鈕。按下它來記錄。再按一次停止錄製。該onClick
看起來是這樣的:
@Override
public void onClick(View v) {
if (!recordingStarted){
recordingStarted = true;
mainActivity.startService(new Intent(mainActivity, SensorService.class));
startButton.setText(getResources().getString(R.string.start_button_label_stop));
Snackbar.make(coordinatorLayout, "Recording...", Snackbar.LENGTH_SHORT).show();
} else {
mainActivity.stopService(new Intent(mainActivity, SensorService.class));
startButton.setEnabled(false);
Snackbar.make(coordinatorLayout, "Recording stopped.", Snackbar.LENGTH_SHORT).show();
}
}
錄音開始時,該SensorService
類的叫了起來。這只是註冊聽衆,啓動服務,以便我可以在屏幕關閉時收集數據,計算一些傳感器等。這是我異步任務所在。該類的唯一有趣的部分是:
public class SensorService extends Service implements SensorEventListener {
public BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive("+intent+")");
if (!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
Log.i(TAG, "Runnable executing...");
unregisterListener();
registerListener();
}
};
new Handler().postDelayed(runnable, SCREEN_OFF_RECEIVER_DELAY);
}
};
public void onSensorChanged(SensorEvent event) {
sensor = event.sensor;
int i = sensor.getType();
if (i == MainActivity.TYPE_ACCELEROMETER) {
accelerometerMatrix = event.values;
} else if (i == MainActivity.TYPE_GYROSCOPE) {
gyroscopeMatrix = event.values;
} else if (i == MainActivity.TYPE_GRAVITY) {
gravityMatrix = event.values;
} else if (i == MainActivity.TYPE_MAGNETIC) {
magneticMatrix = event.values;
}
long curTime = System.currentTimeMillis();
long diffTime = (curTime - lastUpdate);
// only allow one update every POLL_FREQUENCY.
if(diffTime > POLL_FREQUENCY) {
lastUpdate = curTime;
//cut a bunch of stuff here to save space
//insert into database
new InsertSensorDataTask().execute();
}
}
@Override
public void onCreate() {
super.onCreate();
dbHelper = new DBHelper(getApplicationContext());
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(MainActivity.TYPE_ACCELEROMETER);
gyroscope = sensorManager.getDefaultSensor(MainActivity.TYPE_GYROSCOPE);
gravity = sensorManager.getDefaultSensor(MainActivity.TYPE_GRAVITY);
magnetic = sensorManager.getDefaultSensor(MainActivity.TYPE_MAGNETIC);
PowerManager manager =
(PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
@Override
public void onDestroy() {
unregisterReceiver(receiver);
unregisterListener();
wakeLock.release();
dbHelper.close();
stopForeground(true);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
startForeground(Process.myPid(), new Notification());
registerListener();
wakeLock.acquire();
return START_STICKY;
}
private class InsertSensorDataTask extends AsyncTask<String, String, Boolean> {
@Override
protected Boolean doInBackground(String... params) {
try {
dbHelper.insertData(Short.parseShort(MainActivity.subInfo.get("subNum")), System.currentTimeMillis(),
accelerometerMatrix[0], accelerometerMatrix[1], accelerometerMatrix[2],
accelerometerWorldMatrix[0], accelerometerWorldMatrix[1], accelerometerWorldMatrix[2],
gyroscopeMatrix[0], gyroscopeMatrix[1], gyroscopeMatrix[2]);
return true;
} catch (SQLException e) {
Log.e(TAG, "insertData: " + e.getMessage(), e);
return false;
}
}
}
}
當我按下停止按鈕,會立即撥打在onClick
stopService
,我相信會打電話給在SensorService
onDestroy
。然而,我遇到了停止按下的情況,監聽器未註冊,數據庫關閉,但仍有異步任務在後臺運行。我的猜測是他們在實際停止之前仍然完成了最終的任務。這讓我進入異常領域,因爲異步代碼試圖將數據插入到現在已關閉的數據庫中。我可以抓住這些並忽略它們,但我想找出正確的方法來處理這種情況
我應該如何重構我的代碼以允許異步任務完成?因爲這不是一個大工作,而是成千上萬的小型數據庫插入工作,我會想象他們可以很快停下來,所以我很驚訝,我一直遇到這些封閉的數據庫異常問題
有沒有辦法告訴所有異步任務何時完成?也許我可以用它作爲onDestroy
中的一個條件,然後關閉任何東西?
還是值得從異步任務完全撤離?我主要是想避免在主UI線程中運行這些分貝插入
在OnDestroy的AsynTask烤麪包!你會知道它是否停止 – Jois