简体   繁体   English

在同一数据库上运行的不同线程中的多个游标

[英]multiple cursors in different threads running on same database

I initialize a database instance in an asynctask class doInBackground(). 我在asynctask类doInBackground()中初始化数据库实例。 The database instance and its methods are in a separate class (the one I will show) From the asynctask I start another thread in a class for my Azure client, which eventually queries the database class to populate my azure db client. 数据库实例及其方法位于单独的类中(我将显示该类)。从asynctask中,我为Azure客户端的类中启动另一个线程,该线程最终查询数据库类以填充我的Azure数据库客户端。 Going back to my asynctask, I then access the db again (simultaneously as the first query) to query the db for separate information. 回到我的异步任务,然后我再次访问数据库(同时作为第一个查询)以查询数据库中的单独信息。 It seems having the two cursors going simultaneously from separate threads querying is causing me problems. 似乎有两个游标同时从单独的线程查询中移出,这给我带来了问题。

Below are the methods in the db class which use the first cursor to send stuff to Azure. 下面是db类中的方法,该方法使用第一个光标将内容发送到Azure。 These methods are called from the separate thread run in an Azure class. 从Azure类中运行的单独线程中调用这些方法。 The Azure class is called in the asynctask class. 在asynctask类中调用Azure类。 As you will see in the logcat, this works fine. 正如您将在logcat中看到的那样,它可以正常工作。

    public ArrayList<WeatherEvent> GetUnsychedWeatherEvent() {
    String query = COLUMN_SYNCHED + " = 0 ";
    Cursor cursor = db.query(TABLE_WEATHER, null, query, null, null, null, null);

    ArrayList<WeatherEvent> unsychedWeather = new ArrayList<>();
    while (cursor.moveToNext()) {
        unsychedWeather.add( GetWeatherEvent(cursor) );
    }
    cursor.close();

    return unsychedWeather;

}

//get weather event from db for azure
//TODO: finish populating this
public WeatherEvent GetWeatherEvent(Cursor cursor) {
    WeatherEvent wEvent = new WeatherEvent();
    wEvent.Latitude = cursor.getDouble(cursor.getColumnIndex(COLUMN_LATITUDE));
    wEvent.Longitude = cursor.getDouble(cursor.getColumnIndex(COLUMN_LONGITUDE));
    wEvent.CurrTemp = cursor.getString(cursor.getColumnIndex(COLUMN_CURRENT_TEMPERATURES));
    wEvent.CurrDesc = cursor.getString(cursor.getColumnIndex(COLUMN_CURRENT_WEATHER_DESCRIPTION));
    System.out.println("From DB, current temp: " + wEvent.CurrTemp);
    try {
        wEvent.Time = timeStampFormat.parseDateTime(cursor.getString(cursor.getColumnIndex(COLUMN_TIME_STAMP)));
    } catch (Exception e) {
        Log.d("GetEvent()", "Error parsing date " + e.toString());
    }

    return wEvent;
}

These next methods comes from the same db class. 这些下一个方法来自相同的db类。 The 'dailycursor' here is what is causing me trouble. 这就是给我造成麻烦的“日常光标”。 These methods are called in the asynctask class. 这些方法在asynctask类中调用。

  public ArrayList<WeatherEvent> DailyWeatherEvents(ArrayList<WeatherEvent> dailyWeatherEvents) {
        Log.d("DB Access", "got to dailyweatherevents");

    //todo: more specific time query
    Cursor dailycursor = db.rawQuery("SELECT avg(" + COLUMN_CURRENT_TEMPERATURES + "), " + COLUMN_TIME_STAMP + ", " +
            "CASE WHEN  strftime('%M', " + COLUMN_TIME_STAMP + ") < '30' " +
            "THEN strftime('%H', " + COLUMN_TIME_STAMP + ") " +
            "ELSE strftime('%H', " + COLUMN_TIME_STAMP + ", '+1 hours') END " +
            "FROM " + TABLE_WEATHER +  " "+
            "GROUP BY strftime('%H', " + COLUMN_TIME_STAMP + ", '+30 minutes')", null);

    //ArrayList<WeatherEvent> dailyWeatherEvents = new ArrayList<>();
    try {
        if (dailycursor.moveToFirst()) {
            while (dailycursor.moveToNext()) {
                dailyWeatherEvents.add(GetDailyWeatherEvent(dailycursor));

            }
            dailycursor.close();
            System.out.println("Size of dailyinfo " + dailyWeatherEvents.size());
        }
        } catch (Exception e) {
        e.printStackTrace();
    }
    return dailyWeatherEvents;
}

public WeatherEvent GetDailyWeatherEvent(Cursor dailycursor) {
    WeatherEvent wEvent = new WeatherEvent();
   // wEvent.Latitude = dailycursor.getDouble(dailycursor.getColumnIndex(COLUMN_LATITUDE));
  //  wEvent.Longitude = dailycursor.getDouble(dailycursor.getColumnIndex(COLUMN_LONGITUDE));
    wEvent.CurrTemp = dailycursor.getString(dailycursor.getColumnIndex(COLUMN_CURRENT_TEMPERATURES));
    System.out.println(wEvent.CurrTemp + " mariah this comes from cursor");
    wEvent.CurrDesc = dailycursor.getString(dailycursor.getColumnIndex(COLUMN_CURRENT_WEATHER_DESCRIPTION));
    try {
        wEvent.Time = timeStampFormat.parseDateTime(dailycursor.getString(dailycursor.getColumnIndex(COLUMN_TIME_STAMP)));
    } catch (Exception e) {
        Log.d("GetEvent()", "Error parsing date " + e.toString());
    }
    wEvent.CurrIcon = dailycursor.getString(dailycursor.getColumnIndex(COLUMN_CURRENT_ICONS));
    wEvent.SevereWeatherPresent = dailycursor.getInt(dailycursor.getColumnIndex(COLUMN_SEVERE_WEATHER_PRESENT))>0;

    return wEvent;

}

The lines from the asynctask class that start all of this. 从asynctask类开始的所有行。 The WeatherDBAccess is the DB class. WeatherDBAccess是数据库类。 The WeatherAzureAccess is the azure class: WeatherAzureAccess是azure类:

  WeatherDBAccess._context = this.context;
            WeatherDBAccess.Instance().AddWeatherEvent(wEvent);
            //starts azure
            WeatherAzureAccess.context = this.context;
            WeatherAzureAccess.Instance();


        //prep dailyinfo arraylist

            dailyinfo = WeatherDBAccess.Instance().DailyWeatherEvents(dailyinfo);

And this is my logcat, the "From DB, current temp: XX" lines are printing from the methods for azure: 这是我的日志,从蔚蓝的方法中打印出“来自数据库,当前温度:XX”行:

    01-12 15:15:43.869 29979-30189/pdgt.cat.com.noaahso I/SQLiteAssetHelper: successfully opened database HSO.sqlite
01-12 15:15:43.869 29979-30189/pdgt.cat.com.noaahso D/WeatherDBAccess: Instance Created /data/data/pdgt.cat.com.noaahso/databases/HSO.sqlite
01-12 15:15:43.869 29979-30189/pdgt.cat.com.noaahso I/System.out: Current Temp: 54
01-12 15:15:43.899 29979-30189/pdgt.cat.com.noaahso I/System.out: Weather Event Added
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso D/DB Access: got to dailyweatherevents
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso E/CursorWindow: Failed to read row 1, column -1 from a CursorWindow which has 3 rows, 3 columns.
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err: java.lang.IllegalStateException: Couldn't read row 1, col -1 from CursorWindow.  Make sure the Cursor is initialized correctly before accessing data from it.
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso D/AzureAccess: WeatherSync thread STARTED!
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at android.database.CursorWindow.nativeGetString(Native Method)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at android.database.CursorWindow.getString(CursorWindow.java:451)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:51)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at pdgt.cat.com.noaahso.WeatherDBAccess.GetDailyWeatherEvent(WeatherDBAccess.java:235)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at pdgt.cat.com.noaahso.WeatherDBAccess.DailyWeatherEvents(WeatherDBAccess.java:219)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at pdgt.cat.com.noaahso.WeatherTask.doInBackground(WeatherTask.java:228)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at pdgt.cat.com.noaahso.WeatherTask.doInBackground(WeatherTask.java:47)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at android.os.AsyncTask$2.call(AsyncTask.java:288)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:237)
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 49
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
01-12 15:15:43.919 29979-30189/pdgt.cat.com.noaahso W/System.err:     at java.lang.Thread.run(Thread.java:818)
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 49
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 49
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 49
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 50
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 50
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 50
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-29979/pdgt.cat.com.noaahso D/AsyncTask: got to onpostExecute
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51
01-12 15:15:43.919 29979-30298/pdgt.cat.com.noaahso I/System.out: From DB, current temp: 51

Do I need to use a FutureCallback on the first cursor to know when to start the second cursor? 我是否需要在第一个光标上使用FutureCallback才能知道何时启动第二个光标? Or do I need to make my first cursor global and wait until the first query is done before I reset the one cursor to do my second query? 还是我需要将第一个游标设置为全局游标,并等到第一个查询完成后才重置一个游标以执行第二个查询? Looking for a solution I have learned that starting the second cursor is expensive. 在寻找解决方案时,我了解到启动第二个游标非常昂贵。 My problem is that the second cursor would be used rarely (possibly only onCreate()) and the first cursor will almost be always going as it's constantly used to send stuff to Azure. 我的问题是,第二个游标很少使用(可能仅用于onCreate()),而第一个游标几乎总是运行,因为它经常用于向东芝发送内容。 Also FYI I close my db onDestroy(). 仅供参考,我关闭我的数据库onDestroy()。

Firstly, your error is: 首先,您的错误是:

java.lang.IllegalStateException: Couldn't read row 1, col -1 from CursorWindow. java.lang.IllegalStateException:无法从CursorWindow中读取第1行,col -1。 Make sure the Cursor is initialized correctly before accessing data from it. 在从游标访问数据之前,请确保正确初始化了游标。

That means, that you have results (row 1), but you are trying to read an invalid column index (col -1). 这意味着,您有结果(第1行),但是您正在尝试读取无效的列索引(列-1)。

The problem area is likely here: 问题区域可能在这里:

wEvent.CurrTemp = dailycursor.getString(dailycursor.getColumnIndex(COLUMN_CURRENT_TEMPERATURES));

You are getting a -1 result from getColumnIndex because COLUMN_CURRENT_TEMPERATURES does not exist in your SQL query. 您从getColumnIndex获得-1结果,因为SQL查询中不存在COLUMN_CURRENT_TEMPERATURES

Cursor dailycursor = db.rawQuery("SELECT avg(" + COLUMN_CURRENT_TEMPERATURES + "), " + COLUMN_TIME_STAMP + ", " +
            "CASE WHEN  strftime('%M', " + COLUMN_TIME_STAMP + ") < '30' " +
            "THEN strftime('%H', " + COLUMN_TIME_STAMP + ") " +
            "ELSE strftime('%H', " + COLUMN_TIME_STAMP + ", '+1 hours') END " +
            "FROM " + TABLE_WEATHER +  " "+
            "GROUP BY strftime('%H', " + COLUMN_TIME_STAMP + ", '+30 minutes')", null);

You need to include all columns that you intent to read from in your SELECT statement: 您需要在SELECT语句中包括所有要读取的列:

Cursor dailycursor = db.rawQuery("SELECT avg(" + COLUMN_CURRENT_TEMPERATURES + "), " + COLUMN_CURRENT_TEMPERATURES + ", " + COLUMN_CURRENT_WEATHER_DESCRIPTION + ", " + COLUMN_CURRENT_ICONS + ", " + COLUMN_SEVERE_WEATHER_PRESENT + ", " + COLUMN_TIME_STAMP + ", " +
            "CASE WHEN  strftime('%M', " + COLUMN_TIME_STAMP + ") < '30' " +
            "THEN strftime('%H', " + COLUMN_TIME_STAMP + ") " +
            "ELSE strftime('%H', " + COLUMN_TIME_STAMP + ", '+1 hours') END " +
            "FROM " + TABLE_WEATHER +  " "+
            "GROUP BY strftime('%H', " + COLUMN_TIME_STAMP + ", '+30 minutes')", null);

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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