2013-02-17 2 views
0

Я очень новичок в мире Android. Вот что я пытаюсь выполнить. Поэтому я хочу сделать простой сеанс калибровки для датчика акселерометра, который просто собирает данные акселерометра и вставляет их в базу данных в течение 3 минут. Вот мои коды:Android SQLite Транзакция с базой данных заблокирована

Калибровка Активность

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() продолжает вызываться, и на данном этапе ошибки не возникает. Тем не менее, я не думаю, что данные записываются в базу данных вообще, потому что я не вижу никаких данных, генерируемых в представлении DDMS на Eclipse. Затем, после завершения кода, я попытался снова нажать кнопку. Но теперь я получаю сообщение об ошибке "(5) база данных заблокирована". Я так растерялся. Есть предположения?

Спасибо!

+0

Поскольку в вашем приложении есть async-задача, он попытается получить доступ к db, пока идет один процесс с db. Таким образом, это может привести к ошибке, например, блокировка db, поскольку она занята каким-то процессом. –

ответ

2

Это выглядит подозрительно ко мне:

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

Это не выглядит, как вы закрыть сделку, если mTransactionStatus не верно.

Смежные вопросы