【问题标题】:SQLite in Android error insertAndroid错误插入中的SQLite
【发布时间】:2014-03-27 18:43:23
【问题描述】:

我需要每 30 秒运行一次以下代码。

public void push(Context context,String codigoEvento){
    SessionManager manager = new SessionManager();
    folioEvento = manager.getValue(context,"folioEvento");
    nombreCliente = manager.getValue(context,"nombreCliente");
    nombreUser = manager.getValue(context, "nombreUser");
    hashUser = manager.getValue(context, "hashUsuario");
    if(!(folioEvento.equals("") || nombreCliente.equals(""))){
        Connection cn = new Connection();
        if(cn.isNetworkAvailable(context)){
        String ids = "";
        SQLiteDatabase db = TicketsBaseDatos.getInstance(context).getWritableDatabase();
        Cursor c = db.rawQuery("SELECT inscripcion_id FROM Inscripcion WHERE validado=1 and sincronizado = 1",null);
        if (c.moveToFirst()) {
             do {
                ids += c.getString(0)+",";
                ContentValues valores = new ContentValues();
                valores.put("sincronizado","1");
                String[] args = new String[]{c.getString(0), codigoEvento};
                db.update("Inscripcion", valores, "inscripcion_id=? AND codigo_evento=?", args);
             } while(c.moveToNext());
        }
        db.close();
        c.close();
        JSONParser jParser = new JSONParser();
        JSONObject json = jParser.getJSONFromUrl(Config.URL_BASE+nombreCliente+"/"+Config.URL_PUSH+nombreUser+"/"+hashUser+"/"+folioEvento+"/"+ids);
        try {
              String status = json.getString("status");
              if(status.equals("1")){
                  System.out.println("BIEN");
              }
              else{
                  System.out.println("MAL");
              }
          } catch (JSONException e) {
            e.printStackTrace();
          }
        }
    }
}

之后,用户将能够从 Web 服务下载数据,是以下代码,这个任务,我在 AsyncTask 中完成:

public void sincronizarBD(Context context, String codigoEvento) {
    Connection cn = new Connection();
    if(cn.isNetworkAvailable(context)){
        SessionManager manager = new SessionManager();
        folioEvento = manager.getValue(context,"folioEvento");
        nombreCliente = manager.getValue(context,"nombreCliente");
        codigoUser = manager.getValue(context,"codigoUser");
        nombreUser = manager.getValue(context, "nombreUser");
        hashUser = manager.getValue(context, "hashUsuario");
        JSONParser jParser = new JSONParser();
        BaseDeDatos nueva = new BaseDeDatos();
        try {
              do{
                  int recorrido = 0;
                  JSONObject json = jParser.getJSONFromUrl(Config.URL_BASE+nombreCliente+"/"+Config.URL_DESCARGA_BD+nombreUser+"/"+hashUser+"/"+folioEvento+"/"+start+"/"+cantidad);
                  JSONArray array = json.getJSONArray("Inscripciones");
                  for (int i = 0; i < array.length(); i++) {
                          recorrido++;
                          JSONObject rowParticipante = array.getJSONObject(i);
                              SQLiteDatabase db = TicketsBaseDatos.getInstance(context).getWritableDatabase();
                              System.out.println(i);
                              ContentValues nuevoRegistro = new ContentValues();
                              nuevoRegistro.put("hash", rowParticipante.getString("hash"));
                              nuevoRegistro.put("codigo_evento", rowParticipante.getString("codigo_evento"));
                              nuevoRegistro.put("ticket",rowParticipante.getString("ticket"));
                              nuevoRegistro.put("nombre",rowParticipante.getString("nombre"));
                              nuevoRegistro.put("inscripcion_id",rowParticipante.getString("inscripcion_id"));
                              nuevoRegistro.put("validado", rowParticipante.getInt("validado"));
                              nuevoRegistro.put("sincronizado", 0);
                              nuevoRegistro.put("numero", rowParticipante.getString("numero"));
                              nuevoRegistro.put("categoria", rowParticipante.getString("categoria"));
                              nuevoRegistro.put("codigo_usuario", codigoUser);
                              nuevoRegistro.put("rut", rowParticipante.getString("rut_clean"));
                              nuevoRegistro.put("talla", rowParticipante.getString("talla"));
                              System.out.println("Guardado con exito");
                              db.insert("Inscripcion", null, nuevoRegistro);
                              nuevoRegistro.clear();
                              db.close();
                  }
                  if(recorrido>0){
                      start = start + cantidad;
                  } else {
                      continuar = false;
                  }
              }while(continuar == true);
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
}

这是我在“sincronizarBD”中下载时“拉”时出现的错误,会引发错误。

03-28 02:30:14.547: E/AndroidRuntime(16117): FATAL EXCEPTION: AsyncTask #3

03-28 02:30:14.547: E/AndroidRuntime(16117): java.lang.RuntimeException: 执行 doInBackground() 时出错 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 android.os.AsyncTask$3.done(AsyncTask.java:299) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:352) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 java.util.concurrent.FutureTask.setException(FutureTask.java:219) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 java.util.concurrent.FutureTask.run(FutureTask.java:239) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1080) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:573) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 java.lang.Thread.run(Thread.java:856) 03-28 02:30:14.547:E/AndroidRuntime(16117):原因:java.lang.IllegalStateException:尝试重新打开已经关闭的对象:SQLiteDatabase:/data/data/com.androidaz.scanner/databases /事件中 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:55) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 android.database.sqlite.SQLiteDatabase.insertWithOnConflict(SQLiteDatabase.java:1543) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 android.database.sqlite.SQLiteDatabase.insert(SQLiteDatabase.java:1445) 03-28 02:30:14.547: E/AndroidRuntime(16117): at com.androidaz.scanner.Sincronizacion.sincronizarBD(Sincronizacion.java:73) 03-28 02:30:14.547: E/AndroidRuntime(16117): at com.androidaz.scanner.MenuEvento$sincronizarBD.doInBackground(MenuEvento.java:205) 03-28 02:30:14.547: E/AndroidRuntime(16117): at com.androidaz.scanner.MenuEvento$sincronizarBD.doInBackground(MenuEvento.java:1) 03-28 02:30:14.547: E/AndroidRuntime(16117): 在 android.os.AsyncTask$2.call(AsyncTask.java:287) 03-28 02:30:14.547: E/AndroidRuntime(16117): at java.util.concurrent.FutureTask.run(FutureTask.java:234)

我的 SQL 助手

public class TicketsBaseDatos extends SQLiteOpenHelper {

String sqlCreateBDEvent = "CREATE TABLE IF NOT EXISTS Evento  (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, codigo_evento TEXT , nombre TEXT, codigo_usuario TEXT, folio TEXT, nombre_cliente TEXT)";
String sqlCreateBDInscripcion = "CREATE TABLE IF NOT EXISTS Inscripcion (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, hash TEXT, codigo_evento TEXT, ticket TEXT, nombre TEXT, inscripcion_id TEXT, validado int, sincronizado int, numero TEXT, categoria TEXT, codigo_usuario TEXT, rut TEXT, talla TEXT)";
private static TicketsBaseDatos sInstance;
public static TicketsBaseDatos getInstance(Context context) {
    if (sInstance == null) {
      sInstance = new TicketsBaseDatos(context.getApplicationContext());
    }
    return sInstance;
  }


public TicketsBaseDatos(Context ctx) {
    super(ctx, "Eventrid", null, 1);
}

}

要运行一段时间我的推送操作,请占用 Timer :

@Override
public int onStartCommand(Intent intent, int flags, int startId) {
    Sincronizacion s = new Sincronizacion();
    SessionManager ss = new SessionManager();
    try{
        codigoEvento = ss.getValue(this,"codigoEvento");
        folioEvento = ss.getValue(this,"folioEvento");
        nombreCliente = ss.getValue(this,"nombreCliente");
    if((codigoEvento != null) && (!codigoEvento.equals("") && (folioEvento != null) && (!folioEvento.equals("") && (nombreCliente != null) && (!nombreCliente.equals(""))))){
            s.push(getApplicationContext(), codigoEvento);
            s.pull(getApplicationContext(), codigoEvento);
            Toast.makeText(this, "PULL Y PUSH", Toast.LENGTH_SHORT).show();
        }else{
            Toast.makeText(this, "Push sin codigo", Toast.LENGTH_SHORT).show();
        }
    }catch(Exception e){
        Toast.makeText(this, "NO HAY CODIGOS", Toast.LENGTH_SHORT).show();
    }
    return START_STICKY;
}


cronTimerTask = new TimerTask() {
     @Override
     public void run() {
         startService(new Intent(getBaseContext(), CronPush.class));
     }
};
cron = new Timer();
cron.schedule(cronTimerTask, 0, 30000);

因为我抛出了这个错误?有什么解决办法吗?

【问题讨论】:

    标签: android sqlite android-asynctask


    【解决方案1】:

    抛出这个异常是因为你关闭了数据库连接然后你尝试用它做其他事情,你代码中的问题出在这行:

    for(..){
        SQLiteDatabase db = TicketsBaseDatos.getInstance(context).getWritableDatabase();                           
        ...
        db.insert("Inscripcion", null, nuevoRegistro);
        nuevoRegistro.clear();
        db.close();
    }
    

    你不应该在你的 for 循环中每次都询问数据库,最好(更快)只请求一次并在最后关闭它,如下所示:

    SQLiteDatabase db = TicketsBaseDatos.getInstance(context).getWritableDatabase();                           
    for(..){
                ...
        db.insert("Inscripcion", null, nuevoRegistro);
        nuevoRegistro.clear();
    }
    db.close();
    

    【讨论】:

    • 我做了你提到的更改,但错误仍然存​​在。
    • 好的,我没有注意到 for 外面的 while 循环,你能把 getWritable... 和 db.close 都移到这个循环之外吗?
    • 不工作,我有一个计时器正在运行 push 动作,是这个问题吗?编辑我的帖子
    • 是的!正如 Emanuel Moecklin 所说,问题在于您对 DB 对象使用 SingleTon,因此当其他线程将 DB 关闭时,您可以为每个线程使用一个新实例或使用锁来代替
    • 问题是没有关闭,所以我仍然抛出错误。例如,在一种情况下占用了一个进度对话框,不关闭数据库应用程序冻结并停止工作。
    【解决方案2】:

    您正在为您的 SQLiteOpenHelper 使用 Singleton,如果您想在多个线程中访问数据库,但如果您不时关闭它,则不是一个好主意。虽然一个线程可能会关闭数据库(如您的 push 方法),但另一个线程(如您的 AsyncTask)尝试使用相同的 - 现在已关闭 - 数据库。

    有两种方法可以解决这个问题:

    1. 除非不再需要,否则不要关闭数据库。对于 ContentProvider(请参阅 When should I call close() on SQLiteOpenHelper used by ContentProvider),或者在涉及 Activity 或 Fragments 的 onDestroy() 中,这可能永远不会发生。
    2. 跟踪关闭和打开语句,并且仅在所有线程完成它们应该执行的操作后才关闭它。有例如这个https://github.com/d4rxh4wx/MultiThreadSQLiteOpenHelper 或者您可以使用锁添加自己的同步机制(例如 ReentrantReadWriteLock)。

    Google for SQLiteOpenHelper 多线程,您会发现很多关于您面临的问题的帖子。

    【讨论】:

    • 我认为你是绝对正确的,试试看。我将仅基于“sincronizarBD”的单例数据放在更关心常见和常用方式的地方。但是我现在仍然插入错误。 android.database.sqlite.SQLiteDatabaseLockedException:数据库被锁定(代码5)
    • 我的猜测是,您现在打开了两个 SQLiteOpenHelper,它们将同时打开同一个数据库,这将不可避免地失败,但看不到一些实际代码,只是在黑暗中钓鱼。
    猜你喜欢
    • 2015-02-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多