我的Runnable中的Sqlite交互导致ANR

时间:2012-09-24 16:44:36

标签: android multithreading android-sqlite

我有一个类Recorder,它捕获传感器数据并将其写入数据库。所有数据库处理都在Recorder中进行。在这里,我在一个新线程中运行它。 mContext来自getApplicationContext()。

        Runnable startRunnable = new Runnable(){
            public void run() {
                Recorder recorder = new Recorder((SensorManager) getSystemService(SENSOR_SERVICE), mContext);
                recorder.start();
            }
        };
        recorderThread = new Thread(startRunnable);
        recorderThread.start();

以下是Recorder的相关位:

public Recorder(SensorManager sensorManager, Context context){
    mSensorManager = sensorManager;
    mContext = context;
}

void start(){               
    List <Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
    for(Sensor sensor : sensorList){
        mSensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
    }
}

public void onSensorChanged(SensorEvent event) {
    SensorDatabase dbHelper = new SensorDatabase(mContext);
    mDb = dbHelper.getWritableDatabase();

    if(mDb != null && mDb.isOpen()){
        ContentValues values = new ContentValues();
        values.put(DataColumns.ACCURACY, event.accuracy);
        // more values stuff ... 

        mDb.insert(SensorDatabase.TABLE_NAME, null, values);
        mDb.close();
    }
}

应用程序记录数据,但收到ANR错误。如果我这样做,以便数据库不在记录器中初始化,则没有ANR错误。

这个Runnable怎么能在这里阻止UI线程?没有回调,UI线程永远不会尝试打开数据库连接,至少我不打算这样做。

我查看了ANR的traces.txt,它说线程“main”正在执行:

 android.database.sqlite.SQLiteStatement.native_executeSql(Native Method) 

任何指针?我很困惑。

2 个答案:

答案 0 :(得分:0)

  

这个Runnable怎么能在这里阻止UI线程?

Runnable未阻止主应用程序线程(a.k.a。,“UI线程”)。 onSensorChanged()阻塞了主应用程序线程,因为在主应用程序线程上调用onSensorChanged(),因此您在主应用程序线程上执行磁盘I / O.

答案 1 :(得分:0)

我(错误地,愚蠢地)假设从非ui线程注册事件监听器会将监听器放在所述非ui线程上。为了完成所需的操作,我做了以下操作,并明确地为registerListener方法提供了一个新的Handler:

    mThread = new HandlerThread("RecorderThread");
    mThread.start();

    List <Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ALL);
    for(Sensor sensor : sensorList){
        mSensorManager.registerListener(
                Recorder.this, 
                sensor, 
                SensorManager.SENSOR_DELAY_FASTEST, 
                new Handler(mThread.getLooper())
        );
    } 

这似乎运作良好。