2014-02-25 144 views
2

如果我沒有弄錯,Google已經啓用了AsyncTasks以提高執行速度並行運行,但有幾個Android API(在donut之後,蜂窩之前)。然後,很多開發人員在使用多個AsyncTasks訪問同一個數據庫時犯了錯誤,而且由於Android 3.0 AsyncTasks默認是串行運行的。如何在Android 2.x中強制串行/順序執行AsyncTasks

我與我的SQLite

  • 首先,即時得到類別的服務器,我打開數據庫,將它們插入接近DB在Android 2.3.4設備上測試我的應用程序時的痛苦,現在這個問題。

  • 其次,我從服務器獲取的子類別,打開數據庫,將它們插入到數據庫,靠近DB

  • 第三我從服務器上,打開數據庫用戶的項目,插入項目,然後關閉DB

我正在小心翼翼地確保一個接一個地開始,但是在每個8-10次迭代中,某個地方的任務放慢並與另一個程序重疊,此時任務正在打開數據庫,另一個任務將在其後立即關閉,第一個任務開始嘗試寫入一個封閉的分貝....

我該怎麼辦?我想幹淨,可靠的分離,順序執行,我不想從以前的asynctask的onPostExecute啓動asynctasks,因爲這三個不會總是連續運行

我昨天讀了一篇文章,你可以在android 2上做到這一點.x

我應該嘗試在所有操作之前打開DB和DBHelper,然後關閉DB?

編輯:通常我得到的錯誤在這裏(在開始交易): (錯誤說,DB被關閉)

@Override 
protected Void doInBackground(Void... arg0) { 

    // dbTools.close(); 

    try { 
     if (database == null) { 
      database = dbTools.getWritableDatabase(); 
     } 
    } catch (Exception e) { 
     e.printStackTrace(); 

    } 

    ContentValues values = new ContentValues(); 

    database.beginTransaction(); 

    try { 

     // Iterating all UserItem objects from the LinkedHashSet and getting their info 
     for (UserItem userItem : userItems) { 


      // Inserting values for the database to insert in a new record 
      values.put(C.DBColumns.ITEM_ID, userItem.getItemId()); 
      values.put(C.DBColumns.ITEM_NAME, userItem.getItemName()); 


      // database.insertWithOnConflict(C.DBTables.ITEMS, null, values, SQLiteDatabase.CONFLICT_REPLACE); 
      database.insert(C.DBTables.ITEMS, null, values); 

     } // End of For loop 

     database.setTransactionSuccessful(); 

    } finally { 

     database.endTransaction(); 

    } 

    // Closing all cursors, databases and database helpers properly because not closing them can spring lots of trouble. 
    if (database != null && database.isOpen()) { 
     try { 
      database.close(); 

     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 

    return null; 

} // End of doInBackground 

,這是我的DBTools類:

public class DBTools extends SQLiteOpenHelper { 

    // Its a good practice for DBTools to be a singleton. Do not instantiate it with "new DBTools(context)" but with 
    // DBTools.getInstance(context) instead 
    private static DBTools sInstance; 

    public static DBTools getInstance(Context context) { 

     if (sInstance == null) { 
      sInstance = new DBTools(context); 
     } 
     return sInstance; 
    } 

    public DBTools(Context context) { 
     super(context, C.Preferences.LOCAL_SQLITE_DATABASE_NAME, null, 1); 
    } 

    public void onCreate(SQLiteDatabase database) { 
     database.execSQL(SQLQueries.tableCategoriesCreate); 
     database.execSQL(SQLQueries.tableSubcategoriesCreate); 
     database.execSQL(SQLQueries.tableItemsCreate); 
    } 

    public void onOpen(SQLiteDatabase database) { 
     database.execSQL(SQLQueries.tableCategoriesCreate); 
     database.execSQL(SQLQueries.tableSubcategoriesCreate); 
     database.execSQL(SQLQueries.tableItemsCreate); 
    } 

    public void onUpgrade(SQLiteDatabase database, int version_old, int current_version) { 
     database.execSQL(SQLQueries.tableCategoriesDrop); 
     database.execSQL(SQLQueries.tableSubcategoriesDrop); 
     database.execSQL(SQLQueries.tableItemsDrop); 
     onCreate(database); 
    } 

} // End of Class 

回答

1

既然你不能從onPostExecute調用,我會說你有兩個選擇,一個是將你打開的關閉調用移動到你的活動或服務的開始和結束。

選項二將在您的DB和DBHelper中設置一個引用計數器,您可以在其中跟蹤打開被調用的次數,然後在調用close時減少該計數。這樣,只有在計數爲0時才能執行關閉。在採取這種方法時要記住的一件事是,您應該有一個方法,當您確定其他連接完成時,您可能會強制關閉所調用的db。這不應該是必要的,但將是一個故障安全來確保數據庫在出現問題時關閉。

編輯:你將不得不使DBTools成爲一個單獨的工作,但它不是等價的。這是一個簡單的例子。

public class DBTools { 
    private static DBTools instance; 
    private static int openCount; 

    public DBTools getInstance() { 
    if (instance == null) { 
     instance = new DBTools(); 
    } 
    return instance; 
    } 

    private DBTools() { 
    openCount = 0; 
    } 

    public void open() { 
    openCount++; 
    //Do open 
    } 

    public close() { 
    openCount--; 
    if (openCount == 0) { 
     //Do close 
    } 

    public void forceDBClose() { 
     //Do close 
    } 
} 
+0

是選項B equivallent以使DBTool中一個單身? –

+0

你需要使用一個單身,但它不只是一個問題使它成爲一個單例我已經添加了一些代碼以供參考 – Ben

+0

因此在openCount> 1時調用forceDBClose –

1

我也是Android的新手。我也有這樣的問題。 爲了克服這個,我用單身類

我創建了DBHelper類的一個實例,並在我所有的asynctasks中使用它。 因此,在數據庫關閉之前,所有的asynctasks都會訪問初始化的數據庫對象。 如果內存中沒有對象,異步任務將實例化並使用它。

+0

我已經這樣做了,但沒有幫助:(我將一些代碼附加到我的問題 –