Android SQLite事务与数据库被锁定

时间:2013-02-17 05:29:36

标签: android sqlite android-asynctask

我对android的世界很新。这是我想要完成的。所以我想为加速度计传感器做一个简单的校准会话,它只需收集加速度计数据并在3分钟内将它们插入数据库。 这是我的代码:

校准活动

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:

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;
    }

}

我省略了SQLiteOpenHelper类,因为它非常普通。因此,在单击按钮后,OnSensorChanged()事件将继续被调用,并且此阶段不会发生错误。尽管如此,我认为数据根本不会写入数据库,因为我无法在Eclipse上看到从DDMS视图生成的任何数据。然后,在代码完成后,我尝试再次单击该按钮。但现在我收到错误“(5)数据库被锁定”。我感到很困惑。有什么想法吗?

谢谢!

1 个答案:

答案 0 :(得分:2)

这看起来很可疑:

mDb.beginTransaction();
if (mTransactionStatus){
    try{
        mDb.setTransactionSuccessful()
    }
    finally{
        mDb.endTransaction();
        stopSelf();
    }
}

除非mTransactionStatus为true,否则看起来不会关闭事务。