【问题标题】:Idiom to close a cursor关闭光标的成语
【发布时间】:2011-05-07 20:34:41
【问题描述】:

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

    Cursor c = getCursor(); 

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

或

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

请指教。

【问题讨论】:

    标签: android sqlite android-cursor


    【解决方案1】:

    不是,但第二个最接近。

    • 选项 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(); 
        }
    }
    

    【讨论】:

    • 我不认为使用 getCount 是一个好方法。如果你使用 moveToFirst,你可以获得更好的性能
    • @wangzhengyi - 这是一个有效的点 moveToFirst 性能更高,并回答了“结果集中有什么”的问题......但 OP 在他们的例子中使用了 getCount() 所以我在这里继续.
    【解决方案2】:

    这样更好:

    • 不使用 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 可能在错误或空游标的情况下为空。见https://stackoverflow.com/a/16108435/952135。不过,如果光标为空,我会报告 null 返回值作为错误。

    【讨论】:

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

    最佳做法如下:

    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.
    }
    

    【讨论】:

    • 我想知道在这种情况下将光标设置为null是否真的是最佳实践,因为它是一个局部变量,GC应该足够聪明来处理它吧?
    • @Shyri 你的逻辑是合乎逻辑的,但是没有将Cursor设置为null,进入finally块时可能没有初始化。你知道这很严重,甚至 Android Studio 都觉得不需要解释。
    【解决方案4】:

    取决于您要捕获的内容,但我会说第二个,以防c.getCount() 引发异常。

    另外,一些缩进也不会出错:)

    【讨论】:

      【解决方案5】:

      我会说第一个,主要是因为第二个会尝试调用c.close(),即使c 是null。此外,根据文档,getCount() 不会引发任何异常,因此无需将其包含在 try 块中。

      【讨论】:

      • 我们需要在计数为 0 的游标上调用 close() 吗?因为在这种情况下,对于第一个习语,永远不会调用 close()。它假定对于没有元素的游标,游标永远不会被打开。这是一个有效的假设吗?
      • 没有。 Cursor 无论有多少项目都需要关闭。
      • 您可以跳过c.getCount() > 0 条件。这样,您的光标将始终关闭,而您的 try 块将什么也不做。
      【解决方案6】:

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

          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;
              }
          }
      

      【讨论】:

      • 如果这个答案不好,请告诉我为什么你认为这个模型更差
      【解决方案7】:

      我认为@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();
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2012-05-05
        • 1970-01-01
        • 2012-04-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多