[英]Android SQLite Transaction with database is locked
I am very new to the world of android. 我对android的世界很新。 Here is what I am trying to accomplish. 这是我想要完成的。 So I want to make a simple calibration session for the accelerometer sensor, which simply collect the accelerometer data and insert them into the database in a period of 3 minutes. 所以我想为加速度计传感器做一个简单的校准会话,它只需收集加速度计数据并在3分钟内将它们插入数据库。 Here are my codes: 这是我的代码:
Calibration Activity 校准活动
package com.example.calibration;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.IBinder;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import com.example.calibration.AccelsService.LocalBinder;
public class CalibrationActivity extends Activity{
private final String DEBUG_TAG = CalibrationActivity.class.getSimpleName();
private TextView mCountdownTv;
private Button mStartButton;
private final int countdownPeriod = 10; //3 Minutes
private AccelsService mService;
private boolean mBound;
private Intent mIntent;
private class myCountdown extends CountDownTimer{
public myCountdown(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
public void onTick(long millisUntilFinished) {
int minutes = (int) millisUntilFinished / (60*1000);
int seconds = (int) (millisUntilFinished - minutes*60*1000)/1000;
if (seconds >= 10){
mCountdownTv.setText(minutes+":" + seconds);
}
else{
mCountdownTv.setText(minutes+":0" + seconds);
}
}
public void onFinish() {
mCountdownTv.setText("Done!");
mCountdown = null;
Log.d(DEBUG_TAG,"Done Calibrating! With mBound = "+mBound);
if (mBound){
mService.setTransactionStatus(true);
unbindService(mConnection);
mBound = false;
}
mStartButton.setEnabled(true);
}
}
private CountDownTimer mCountdown;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName className, IBinder iservice) {
LocalBinder binder = (LocalBinder) iservice;
mService = binder.getService();
mBound = true;
}
@Override
public void onServiceDisconnected(ComponentName className) {
mBound = false;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_calibration);
mCountdownTv = (TextView) findViewById(R.id.countdown_timer);
mStartButton = (Button) findViewById(R.id.start_button);
}
@Override
protected void onStart(){
super.onStart();
mStartButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mIntent = new Intent(CalibrationActivity.this, AccelsService.class);
bindService(mIntent,mConnection,Context.BIND_AUTO_CREATE);
//Start to countdown 3 minutes and stop the service
if (mCountdown==null){
mCountdown = new myCountdown(1000*countdownPeriod, 1000);
mCountdown.start();
}
//Disable the button after it's clicked
mStartButton.setEnabled(false);
}
});
}
@Override
protected void onStop() {
super.onStop();
// Unbind from the service
Log.d(DEBUG_TAG,"ONSTOP! mBound is "+mBound);
if (mBound) {
mService.setTransactionStatus(false);
unbindService(mConnection);
mBound = false;
}
}
@Override
protected void onRestart(){
super.onRestart();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_calibration, menu);
return true;
}
}
AccelsService: AccelsService:
package com.example.calibration;
import android.app.Service;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.AsyncTask;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
public class AccelsService extends Service implements SensorEventListener{
private final String DEBUG_TAG = AccelsService.class.getSimpleName();
private boolean mTransactionStatus = false;//Indicate if the service should commit the database changes
// Binder given to clients
private final IBinder mBinder = new LocalBinder();
public class LocalBinder extends Binder{
AccelsService getService() {
// Return this instance of AccelsService so clients can call public methods
return AccelsService.this;
}
};
private SensorManager mSensorManager;
private Sensor mSensor;
private AccelsDbHelper mDbHelper;
private SQLiteDatabase mDb;
@Override
public void onCreate(){
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(DEBUG_TAG, "onStartCommand!" );
return START_STICKY;
}
@Override
public IBinder onBind(Intent intent) {
startCalibration();
return mBinder;
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
}
@Override
public void onDestroy(){
super.onDestroy();
mSensorManager.unregisterListener(AccelsService.this);
Log.d(DEBUG_TAG, "AccelService got Destroyed!" );
mDbHelper.close();
}
@Override
public void onSensorChanged(SensorEvent event) {
Log.d(DEBUG_TAG, "onSensorChanged" );
new AccelTask().execute(event);
}
private class AccelTask extends AsyncTask<SensorEvent,Void,Void> {
protected Void doInBackground(SensorEvent... events){
mDb.execSQL("INSERT INTO "+ AccelsDbHelper.ACCELS_TABLE_NAME +" VALUES ( "+ events[0].values[0]
+", "+ events[0].values[1] + ", " + events[0].values[2] + ", " + System.currentTimeMillis() + " );");
return null;
}
}
private void startCalibration(){
/*Register the Sensor Listener */
mSensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
mSensor = (Sensor) mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
mSensorManager.registerListener(this,mSensor,SensorManager.SENSOR_DELAY_NORMAL);
Toast.makeText(this, "AccelService starting...", Toast.LENGTH_SHORT).show();
mDbHelper = new AccelsDbHelper(this);
mDb = mDbHelper.getWritableDatabase();
mDb.beginTransaction();
if (mTransactionStatus){
try{
mDb.setTransactionSuccessful();
}
finally{
mDb.endTransaction();
stopSelf();
}
}
}
public void setTransactionStatus(boolean isSuccessful){
mTransactionStatus = isSuccessful;
}
}
I have omitted the SQLiteOpenHelper class, because it's pretty much ordinary. 我省略了SQLiteOpenHelper类,因为它非常普通。 So after clicking on the button, the OnSensorChanged() event keeps getting called, and no error occur at this stage. 因此,在单击按钮后,OnSensorChanged()事件将继续被调用,并且此阶段不会发生错误。 Nonetheless, I don't think the data is getting written to the database at all, because I cannot see any data generated from the DDMS view on Eclipse. 尽管如此,我认为数据根本不会写入数据库,因为我无法在Eclipse上看到从DDMS视图生成的任何数据。 Then, after the code is done, I tried to click on the button again. 然后,在代码完成后,我尝试再次单击该按钮。 But now I am getting the error "(5) database is locked". 但现在我收到错误“(5)数据库被锁定”。 I am so confused. 我感到很困惑。 Any thoughts? 有什么想法吗?
Thank you! 谢谢!
This looks suspicious to me: 这看起来很可疑:
mDb.beginTransaction();
if (mTransactionStatus){
try{
mDb.setTransactionSuccessful()
}
finally{
mDb.endTransaction();
stopSelf();
}
}
It doesn't look like you close the transaction unless mTransactionStatus is true. 除非mTransactionStatus为true,否则它看起来不会关闭事务。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.