如何强制在Android 2.x中串行/顺序执行AsyncTasks

时间:2014-02-25 11:39:58

标签: android android-asynctask

有一些Android API(在甜甜圈之后和蜂窝之前),如果我没有弄错的话,谷歌已经启用了AsyncTasks并行运行,旨在加快执行速度。然后,许多开发人员在使用多个AsyncTasks到达同一个数据库时出错,并且因为Android 3.0 AsyncTasks默认是串行运行。

我在使用我的SQLite

在Android 2.3.4设备上测试我的应用时遇到了这个问题
  • 首先,我从服务器获取类别,我打开数据库,将它们插入数据库。

  • 其次我从服务器获取子类别,打开数据库,将它们插入数据库,关闭数据库

  • 第三,我从服务器获取用户项,打开数据库,插入项目,然后关闭数据库

我要小心翼翼地确保一个接一个地开始,但是在每8到8次迭代中某个地方的某个地方在任务打开数据库的那一刻减速并与另一个程序重叠,另一个任务立即关闭它,并且第一个任务开始尝试写入已关闭的数据库....

我该怎么办?我想要干净,可靠的分离,顺序执行,我不想从之前的asynctask的onPostExecute启动asynctasks,因为这三个并不总是连续运行

昨天我读了一篇文章说你不能在android 2.x

上做

我应该在所有操作之前尝试打开DB和DBHelper,然后关闭数据库吗?

编辑:通常我在这里得到错误(在Begin事务处): (错误表明数据库已关闭)

@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 CLASS:

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

2 个答案:

答案 0 :(得分:1)

我也是android中的新手。我也有这样的问题。 为了解决这个问题,我使用了 Singleton类

我创建了一个DBHelper类的实例,并在我所有的asynctasks中使用它。 因此,在DB关闭之前,所有asynctasks都会访问初始化的DB对象。 如果内存中没有对象,则执行异步任务,然后使用它。

答案 1 :(得分: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 
   }
}