简体   繁体   English

Android SQLite事务与数据库被锁定

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM