Android 应用程序在 SQLite 数据库插入时冻结

Android app freezing on SQLite db insert

我 运行 在尝试插入本地数据库时遇到了一个非常奇怪的问题。我正在向 2 个不同的表添加一条记录,第一次添加它显示在列表中的值,直到 activity 被销毁。我可以离开并返回,新值在那里,但是当我关闭应用程序并将其从历史记录中清除时,它就消失了。

我第二次尝试向数据库输入一个值时,UI 冻结了,它似乎没有抛出任何异常,也没有告诉我发生了什么事。

这是一些代码。

public void addVehicleService(VehicleService service)
{

    SQLiteDatabase dbWritable = getWritableDatabase();
    int serviceId;
    if (serviceExists(service))
    {
        addServicePerformed(service, null, dbWritable);
    }
    else
    {
        ContentValues values = new ContentValues();
        values.put(VEHICLE_ID, service.getVehicleId());
        values.put(SERVICE_NAME, service.getServiceName());
        values.put(SERVICE_INTERVAL, service.getInterval());
        values.put(SERVICE_MILEAGE, service.getOdometer());
        values.put(DAYS_TO_NEXT_NOTIFICATION, 0);
        values.put(NOTIFIED, 0);
        values.put(INITIAL_NOTIFICATION_DATE, Utility.FormatDate(Calendar.getInstance()));

        serviceId = (int) dbWritable.insert(VEHICLE_SERVICE_TABLE, null, values);
        if (serviceId != -1)
            addServicePerformed(service, serviceId, dbWritable);
        else
            Log.d("DBTAG", "Error inserting new Service");
    }
}


private boolean serviceExists(VehicleService service)
{
    SQLiteDatabase db = getReadableDatabase();

    Cursor cursor = db.query(VEHICLE_SERVICE_TABLE, new String[]{ID}, VEHICLE_ID + " = ? AND " + SERVICE_NAME + " = ? AND " + SERVICE_INTERVAL + " = ?",
            new String[]{service.getVehicleId().toString(), service.getServiceName(), service.getInterval().toString()}, null, null, null);
    int count = cursor.getCount();
    cursor.close();

    return count > 0;
}

private void addServicePerformed(VehicleService service, @Nullable Integer serviceId, SQLiteDatabase dbWritable)
{

    if (serviceId == null)
    {
        dbWritable.beginTransaction();
        serviceId = getServiceId(service, dbWritable);
    }

    ContentValues values = new ContentValues();
    values.put(SERVICE_ID, serviceId);
    values.put(ODOMETER_AT_SERVICE, service.getOdometer());
    values.put(DATE_OF_SERVICE, Utility.FormatDate(service.getDate()));
    values.put(COST_OF_SERVICE, service.getCost());

    dbWritable.insert(SERVICE_PERFORMED_TABLE, null, values);

}

我确实有一些方法可以插入数据库并保留更改,所以我真的很困惑到底发生了什么。

public void addVehicleService(VehicleService service)
{

    int serviceId;
    if (serviceExists(service))
    {
        addServicePerformed(service, null);
    }
    else
    {
        SQLiteDatabase dbWritable = getWritableDatabase();
        ContentValues values = new ContentValues();
        values.put(VEHICLE_ID, service.getVehicleId());
        values.put(SERVICE_NAME, service.getServiceName());
        values.put(SERVICE_INTERVAL, service.getInterval());
        values.put(SERVICE_MILEAGE, service.getOdometer());
        values.put(DAYS_TO_NEXT_NOTIFICATION, 0);
        values.put(NOTIFIED, 0);
        values.put(INITIAL_NOTIFICATION_DATE, Utility.FormatDate(Calendar.getInstance()));

        serviceId = (int) dbWritable.insert(VEHICLE_SERVICE_TABLE, null, values);
        if (serviceId != -1)
            addServicePerformed(service, serviceId);
        else
            Log.d("DBTAG", "Error inserting new Service");
    }
}


private void addServicePerformed(VehicleService service, @Nullable Integer serviceId)
{
    SQLiteDatabase dbWritable = getWritableDatabase();

    if (serviceId == null)
    {
        dbWritable.beginTransaction();
        serviceId = getServiceId(service, dbWritable);
    }

    ContentValues values = new ContentValues();
    values.put(SERVICE_ID, serviceId);
    values.put(ODOMETER_AT_SERVICE, service.getOdometer());
    values.put(DATE_OF_SERVICE, Utility.FormatDate(service.getDate()));
    values.put(COST_OF_SERVICE, service.getCost());

    dbWritable.insert(SERVICE_PERFORMED_TABLE, null, values);

}

按照@Shree Krishna 所说的行事。

首先要注意的是,如果服务存在,您将两次创建 SQLiteDatabase 的实例。 if(serviceExists(service)).

所以我建议不要将dbWritable作为参数传递给

addServicePerformed(service, null, dbWritable);。只需在那里创建一个新实例,例如

private void addServicePerformed(VehicleService service, @Nullable Integer serviceId){
     SQLiteDatabase dbWritable = getWritableDatabase();
}

您的代码中实际发生了什么?

在方法中创建一个实例或者说一个对象不会导致任何冻结,因为它的作用域将在方法完成执行后完成,但是全局创建一个实例,并在单独的方法中使用不同的方法再次实例化和在另一种方法中重新使用前一个(全局实例)可能会导致冻结。不总是,但可能有一段时间。所以需要的时候创建实例,不要和它们冲突。