2013-08-09 29 views
31

Tôi đã tìm thấy nhiều thứ như close the connectionclose the cursor nhưng tôi làm tất cả những thứ này. Vẫn có những rò rỉ kết nối SQLite và tôi nhận được một cảnh báo như thế này:Kết nối SQLite bị rò rỉ mặc dù mọi thứ đã đóng

A SQLiteConnection object for database was leaked! 

Tôi có một người quản lý cơ sở dữ liệu này, mà tôi gọi vào các hoạt động của tôi với đoạn mã sau:

DatabaseManager dbm = new DatabaseManager(this); 

Mã của cơ sở dữ liệu của tôi lớp quản lý sau bây giờ:

public class DatabaseManager { 

    private static final int DATABASE_VERSION = 9; 
    private static final String DATABASE_NAME = "MyApp"; 
    private Context context = null; 
    private DatabaseHelper dbHelper = null; 
    private SQLiteDatabase db = null; 


    public static class DatabaseHelper extends SQLiteOpenHelper { 

     public DatabaseHelper(Context context) { 
      super(context, DATABASE_NAME, null, DATABASE_VERSION); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 

        //create database tables 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
         //destroy and recreate them 
     } 

    } 

    public DatabaseManager(Context ctx) { 
     this.context = ctx; 
    } 

    private DatabaseManager open() throws SQLException { 
     dbHelper = new DatabaseHelper(context); 
     db = dbHelper.getWritableDatabase(); 

     if (!db.isReadOnly()) { 
      db.execSQL("PRAGMA foreign_keys = ON;"); 
     } 

     return this; 
    } 

    private void close() { 
     dbHelper.close(); 
    } 
} 

Khi tôi gọi một phương thức cơ sở dữ liệu, tôi làm điều sau đây:

public Object getData() { 

    open(); 

      //... database operations take place ... 

    close(); 

    return data; 
} 

Nhưng như tôi đã nói, tôi vẫn nhận được cảnh báo kết nối SQLite bị rò rỉ.

Tôi đang làm gì sai?

+0

Tôi nghĩ Bạn chỉ được đóng DBHelper của bạn, nhưng không phải là cơ sở dữ liệu riêng của mình – Opiatefuchs

+0

Tôi nghĩ bạn nên gọi db.close () quá –

+0

Không quan trọng, nếu tôi làm điều này hay không. Tôi sẽ nhận được tin nhắn. Nhưng tôi đọc ở đâu đó, rằng bạn không cần phải làm điều này, khi bạn gọi dbHelper.close() – flp

Trả lời

113

Phông chữ được in đậm trong trích dẫn tương ứng với phần này trong mã của bạn:

private DatabaseManager open() throws SQLException { 
    dbHelper = new DatabaseHelper(context); 
    db = dbHelper.getWritableDatabase(); 

từ: http://www.androiddesignpatterns.com/2012/05/correctly-managing-your-sqlite-database.html

Approach # 1: Sử dụng một máy trừu tượng để nhanh chóng SQLiteOpenHelper

Khai báo trình trợ giúp cơ sở dữ liệu của bạn dưới dạng biến đối tượng tĩnh và sử dụng mô hình Nhà máy Tóm tắt để đảm bảo đơn lẻ erty. Mã mẫu bên dưới sẽ cung cấp cho bạn một ý tưởng hay về cách đi về việc thiết kế lớp DatabaseHelper đúng cách .

Phương thức getInstance của nhà máy tĩnh đảm bảo rằng chỉ một Cơ sở dữ liệuHelper sẽ không bao giờ tồn tại tại bất kỳ thời điểm đã định nào. Nếu đối tượng mInstance chưa được khởi tạo, một đối tượng sẽ được tạo. Nếu có đã được tạo thì nó sẽ được trả về đơn giản.

Bạn nên không khởi tạo đối tượng trợ giúp của mình bằng cách sử dụng với new DatabaseHelper(context). Thay vào đó, hãy luôn sử dụng DatabaseHelper.getInstance(context) vì đảm bảo rằng chỉ có một người trợ giúp cơ sở dữ liệu sẽ tồn tại trong toàn bộ vòng đời của ứng dụng.

public static class DatabaseHelper extends SQLiteOpenHelper { 

    private static DatabaseHelper mInstance = null; 

    private static final String DATABASE_NAME = "database_name"; 
    private static final String DATABASE_TABLE = "table_name"; 
    private static final int DATABASE_VERSION = 1; 

    public static DatabaseHelper getInstance(Context ctx) { 

    // Use the application context, which will ensure that you 
    // don't accidentally leak an Activity's context. 
    // See this article for more information: http://bit.ly/6LRzfx 
    if (mInstance == null) { 
     mInstance = new DatabaseHelper(ctx.getApplicationContext()); 
    } 
    return mInstance; 
    } 

    /** 
    * Constructor should be private to prevent direct instantiation. 
    * make call to static factory method "getInstance()" instead. 
    */ 
    private DatabaseHelper(Context ctx) { 
    super(ctx, DATABASE_NAME, null, DATABASE_VERSION); 
    } 
} 
+1

dường như khắc phục được sự cố. Tôi sẽ tiến hành điều tra thêm – flp

+1

Câu trả lời hay. Tôi đã gặp phải vấn đề này khi làm việc với nhiều IntentServices, tất cả đều làm việc đồng thời trong hai cơ sở dữ liệu khác nhau. Tôi đã sử dụng câu trả lời này trừ hai phương pháp Nhà máy riêng biệt. Đã xóa tất cả các lỗi rò rỉ bộ nhớ. Nó đã thêm một nửa hoặc hai giây để thực hiện thời gian, có lẽ bởi vì tôi không còn có nhiều trường hợp cơ sở dữ liệu mở cùng một lúc. –

+1

Điều này đã khắc phục vấn đề tương tự đối với tôi. –

1
private void method() { 
     Cursor cursor = query(); 
     if (flag == false) { // WRONG: return before close() 
      return; 
     } 
     cursor.close(); 
    } 

thực hành tốt nên như thế này:

private void method() { 
     Cursor cursor = null; 
     try { 
      cursor = query(); 
     } finally { 
      if (cursor != null) 
       cursor.close(); // RIGHT: ensure resource is always recovered 
     } 
    } 
Các vấn đề liên quan