问题 成语关闭光标


我应该使用以下哪两个来确保所有游标都关闭?

    Cursor c = getCursor(); 

    if(c!=null && c.getCount()>0){ 
        try{ 
            // read values from cursor 
        }catch(..){} 
        finally{ 
            c.close(); 
        } 
    }//end if

    OR

    Cursor c = getCursor(); 
    try{ 
        if(c!=null && c.getCount()>0){ 
            // read values from cursor 
        }//end if 
    }catch(..){

    }finally{ 
        c.close(); 
    } 

编辑:
几个问题:
1.我们是否需要在计数为0的游标上调用close()?
因为在第一个习语的情况下,将永远不会调用close()。它假定对于没有元素的游标,永远不会打开游标。这是一个有效的假设吗?

请指教。


6883
2017-11-10 12:15


起源



答案:


两者都没有,但第二个是最接近的。

  • 选项1没有正确关闭 getCount()== 0时的游标
  • 选项2使finally块暴露于空指针异常

我会用:

Cursor c = getCursor(); 
try { 
    if(c!=null && c.getCount()>0){ 
         // do stuff with the cursor
    }
}
catch(..) {
    //Handle ex
}
finally { 
    if(c != null) {
        c.close(); 
    }
}

...或者如果您希望光标经常为空,您可以稍微转过头:

Cursor c = getCursor(); 
if(c != null) {
    try { 
        if(c.getCount()>0) { 
             // do stuff with the cursor
        }
    }
    catch(..) {
        //Handle ex
    }
    finally { 
        c.close(); 
    }
}

13
2017-11-10 15:48



感谢您的回答! - Manish Khot
我不认为使用getCount是一个好方法。如果您使用moveToFirst,您可以获得更好的性能 - wangzhengyi
@wangzhengyi - 这是一个有效的点moveToFirst更高效并且回答“结果集中有什么东西”的问题......但OP在他们的例子中使用了getCount()所以我继续在这里。 - Skylar Sutton


答案:


两者都没有,但第二个是最接近的。

  • 选项1没有正确关闭 getCount()== 0时的游标
  • 选项2使finally块暴露于空指针异常

我会用:

Cursor c = getCursor(); 
try { 
    if(c!=null && c.getCount()>0){ 
         // do stuff with the cursor
    }
}
catch(..) {
    //Handle ex
}
finally { 
    if(c != null) {
        c.close(); 
    }
}

...或者如果您希望光标经常为空,您可以稍微转过头:

Cursor c = getCursor(); 
if(c != null) {
    try { 
        if(c.getCount()>0) { 
             // do stuff with the cursor
        }
    }
    catch(..) {
        //Handle ex
    }
    finally { 
        c.close(); 
    }
}

13
2017-11-10 15:48



感谢您的回答! - Manish Khot
我不认为使用getCount是一个好方法。如果您使用moveToFirst,您可以获得更好的性能 - wangzhengyi
@wangzhengyi - 这是一个有效的点moveToFirst更高效并且回答“结果集中有什么东西”的问题......但OP在他们的例子中使用了getCount()所以我继续在这里。 - Skylar Sutton


这甚至更好:

  • 不使用c.getCount() - 计数可能需要额外的数据库工作,不需要
  • 在查询块之前初始化游标,因此创建查询失败后不会跟随finally块

代码:

Cursor c = query(....);
if (c != null) {
   try {        
       while (c.moveToNext()) {  // If empty or after last record it returns false.    
          // process row...
       }
   } 
   finally {
       c.close();
    }
}

注意 c 如果出现错误或空光标,则可能为null。看到 https://stackoverflow.com/a/16108435/952135。但是,如果将空光标作为错误,我会报告null返回值。


3
2017-08-05 07:32



NPE是个问题, query 可以回来 null。 - Pin
我的意思是不 c != null 最后检查是必要的。如果查询返回null,它将与NPE失败,与Hemant的片段相同。我认为 query() 方法永远不会返回null。它应该创建查询,或抛出异常,在这种情况下,您不需要运行finally块。这是正常的清理模式:创建资源...尝试......做工作......最后......清理......结束。如果创建失败,则报告。如果工作失败或成功,最后进行清理。如果您理解,请删除反对票。如果没有,请写信。 - Oliv
它可以返回null并在文档中指定(请参阅ContentResolver.query)。另外,检查一下: stackoverflow.com/questions/13080540/... - Pin
好的,但未指定null返回值。正如帖子中提到的那样,可能是由于某些错误或由于空光标。我认为这种模糊性值得作为一个bug报告。我会更新我的答案。谢谢。 - Oliv


最佳做法如下:

Cursor c = null;    
try {        
   c = query(....);      
   while (c.moveToNext()) {  // If empty or next to last record it returns false.    
      // do stuff..       
   }
} finally {
   if (c != null && !c.isClosed()) {  // If cursor is empty even though should close it.       
   c.close();
   c = null;  // high chances of quick memory release.
}

1
2018-05-03 07:54



我想知道在这种情况下,将光标设置为null是最佳做法,因为它是一个局部变量,GC应该足够聪明地处理它吗? - Shyri


取决于你捕获的是什么,但我会说第二个,以防万一 c.getCount() 抛出一个例外。

另外,一些缩进不会有问题:)


0
2017-11-10 12:18





我会说第一个,主要是因为第二个会试着打电话 c.close() 即使 c 是 null。另外,根据文档, getCount()不会抛出任何异常,因此不需要将其包含在内 try 块。


0
2017-11-10 12:26



我们需要在计数为0的游标上调用close()吗?因为在第一个习语的情况下,将永远不会调用close()。它假定对于没有元素的游标,永远不会打开游标。这是一个有效的假设吗? - Manish Khot
没有.A Cursor 无论有多少物品,都需要关闭。 - Felix
你可以跳过 c.getCount() > 0 条件。这样,您的光标将始终关闭,并且您的光标将被关闭 try 块将无所事事。 - Felix


我认为我的答案是最好的答案:

    Cursor cursor = null;

    try {
        cursor = rsd.rawQuery(querySql, null);
        if (cursor.moveToFirst()) {
            do {
                // select your need data from database
            } while (cursor.moveToNext());
        }
    } finally {
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
            cursor = null;
        }
    }

-1
2017-09-13 01:58



如果这个答案不好,请告诉我为什么你认为这个模型更糟糕 - wangzhengyi


我认为@ skylarsutton是这个问题的正确答案。但是,我想留下问题的代码(答案中的任何代码似乎都有一些缺陷)。请考虑使用我的代码。

Cursor c = query(....);
if (c != null) {
   try {        
       //You have to use moveToFirst(). There is no quarantee that a cursor is located at the beginning.
       for(c.moveToFirst();!c.isAfterLast();c.moveToNext()) {  
          // process row...
       }
   } 
   finally {
       c.close();
    }
}

-1
2017-08-29 08:39