2013-03-24 1 views
20

Ho provato a creare un database SQLite e a fare alcune cose con esso. Ma ho scoperto che il mio metodo onCreate non è nemmeno invocato !!Quando viene chiamato il metodo onCreate di SQLiteOpenHelper?

Sto inviando un messaggio a LogCat all'inizio del metodo onCreate.

La mia ipotesi è, il (super) costruttore invocherà il metodo onCreate. È giusto?

My Code:

import android.database.sqlite.SQLiteOpenHelper; 
import android.database.sqlite.SQLiteDatabase; 
import android.content.Context; 
import android.database.Cursor; 
import android.content.ContentValues; 
import android.util.Log; 

public class DatabaseHandler extends SQLiteOpenHelper { 
    // Static Constants 
    /*** Database details ***/ 
    // Database version 
    private static final int DATABASE_VERSION   = 1; 

    // Database name 
    private static final String DATABASE_NAME   = "database_name"; 

    /*** Database Tables ***/ 
    /** Events **/ 
    // Event table 
    private static final String TABLE_EVENT    = "event"; 

    // Event table columns 
    private static final String COLUMN_EVENT_EID  = "_eid"; 

    private static final String COLUMN_EVENT_CREATION_DATE = "creation_date"; 

    private static final String COLUMN_EVENT_TITLE  = "title"; 
    private static final String COLUMN_EVENT_ICON  = "icon"; 

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

    @Override 
    public void onCreate(SQLiteDatabase db) { 
     Log.e("MyApp", "onCreate invoked"); 
     // Tables creation queries 
     String CREATE_EVENT_TABLE = "create table " + TABLE_EVENT + "(" + COLUMN_EVENT_EID + " integer primary key, " 
       + COLUMN_EVENT_CREATION_DATE + " text, " 
       + COLUMN_EVENT_TITLE + " text, " 
       + COLUMN_EVENT_ICON + " text)"; 

     // Creating tables 
     db.execSQL(CREATE_EVENT_TABLE); 
    } 

    @Override 
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     Log.e("MyApp", "onUpgrade invoked"); 
     db.execSQL("DROP TABLE IF EXISTS " + TABLE_EVENT); 
    } 
} 

Codice MainActivity:

import android.os.Bundle; 
import android.app.Activity; 
import android.view.Menu; 

public class MainActivity extends Activity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     DatabaseHandler db = new DatabaseHandler(this); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     // Inflate the menu; this adds items to the action bar if it is present. 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

} 

risposta

2

Hai ragione, il (super) costruttore invocherà il metodo onCreate, MA solo se il database effettivo non esce. Da http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#onCreate%28android.database.sqlite.SQLiteDatabase%29

una classe di supporto per gestire la creazione del database e la gestione delle versioni.

Si crea una sottoclasse attuazione onCreate (SQLiteDatabase), ONUPGRADE (SQLiteDatabase, int, int) e opzionalmente onOpen (SQLiteDatabase), e questa classe si occupa di apertura del database se esiste, creandolo se lo fa no, e l'aggiornamento come necessario.

1

Come i documenti ufficiali dice: "getWritableDatabase() creare e/o aprire un database che verrà utilizzato per la lettura e la scrittura. La prima volta che questo si chiama, il database sarà aperto e onCreate (SQLiteDatabase), verranno chiamati onUpgrade (SQLiteDatabase, int, int) e/o onOpen (SQLiteDatabase). "

Una volta aperto correttamente, il database viene memorizzato nella cache, quindi è possibile chiamare questo metodo ogni volta che è necessario scrivere nel database. (Assicurati di chiamare close() quando non hai più bisogno del database.) Errori come permessi non validi o un disco completo possono causare il fallimento di questo metodo, ma i tentativi futuri potrebbero riuscire se il problema è risolto.

http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase()

2

vorrei chiarire il sul flusso logico. Ecco il concetto Inizializzazione pigra.

Il (super) costruttore su DatabaseHandlernon invoca il metodo onCreate. Chiama il costruttore DatabaseHandler inizializza: contesto, nome del database, factory che crea il database, la versione del database e il gestore degli errori del database.

getWritableDatabase()>getDatabaseLocked()> - SQLiteDatabase.create()

O

getReadableDatabase()>getDatabaseLocked()> - SQLiteDatabase.create()

Risposta: Dopo aver creato correttamente il database, le configurazioni cambiano, la volta successiva ancora getReadableDatabase() o getWritableDatabase() chiamate getDatabaseLocked() e il metodo onCreate(db)getDatabaseLocked() viene eseguito.

enter image description here

Spiegazione:

Il metodo sopra SQLiteDatabase.create() è responsabile per creare SQLiteDatabase nel disco.

Ma il processo in pigro-inizializzazione (significa che non rende tutto pronto. Crea quegli oggetti sul runtime se ne hai bisogno.Per questo ha usato un sacco di istruzioni if..else).

Se vedi il corpo completo di getDatabaseLocked(), questo è sotto. [È possibile cercare onCreate() metodo all'interno del corpo di getDatabaseLocked()]

private SQLiteDatabase getDatabaseLocked(boolean writable) { 
     if (mDatabase != null) { 
      if (!mDatabase.isOpen()) { 
       // Darn! The user closed the database by calling mDatabase.close(). 
       mDatabase = null; 
      } else if (!writable || !mDatabase.isReadOnly()) { 
       // The database is already open for business. 
       return mDatabase; 
      } 
     } 

     if (mIsInitializing) { 
      throw new IllegalStateException("getDatabase called recursively"); 
     } 

     SQLiteDatabase db = mDatabase; 
     try { 
      mIsInitializing = true; 

      if (db != null) { 
       if (writable && db.isReadOnly()) { 
        db.reopenReadWrite(); 
       } 
      } else if (mName == null) { 
       db = SQLiteDatabase.create(null); 
      } else { 
       try { 
        if (DEBUG_STRICT_READONLY && !writable) { 
         final String path = mContext.getDatabasePath(mName).getPath(); 
         db = SQLiteDatabase.openDatabase(path, mFactory, 
           SQLiteDatabase.OPEN_READONLY, mErrorHandler); 
        } else { 
         db = mContext.openOrCreateDatabase(mName, mEnableWriteAheadLogging ? 
           Context.MODE_ENABLE_WRITE_AHEAD_LOGGING : 0, 
           mFactory, mErrorHandler); 
        } 
       } catch (SQLiteException ex) { 
        if (writable) { 
         throw ex; 
        } 
        Log.e(TAG, "Couldn't open " + mName 
          + " for writing (will try read-only):", ex); 
        final String path = mContext.getDatabasePath(mName).getPath(); 
        db = SQLiteDatabase.openDatabase(path, mFactory, 
          SQLiteDatabase.OPEN_READONLY, mErrorHandler); 
       } 
      } 

      onConfigure(db); 

      final int version = db.getVersion(); 
      if (version != mNewVersion) { 
       if (db.isReadOnly()) { 
        throw new SQLiteException("Can't upgrade read-only database from version " + 
          db.getVersion() + " to " + mNewVersion + ": " + mName); 
       } 

       db.beginTransaction(); 
       try { 
        if (version == 0) { 
         onCreate(db); 
        } else { 
         if (version > mNewVersion) { 
          onDowngrade(db, version, mNewVersion); 
         } else { 
          onUpgrade(db, version, mNewVersion); 
         } 
        } 
        db.setVersion(mNewVersion); 
        db.setTransactionSuccessful(); 
       } finally { 
        db.endTransaction(); 
       } 
      } 

      onOpen(db); 

      if (db.isReadOnly()) { 
       Log.w(TAG, "Opened " + mName + " in read-only mode"); 
      } 

      mDatabase = db; 
      return db; 
     } finally { 
      mIsInitializing = false; 
      if (db != null && db != mDatabase) { 
       db.close(); 
      } 
     } 
    } 

Si prega di notare, all'interno del corpo di getDatabaseLocked() metodo, ci sono così tanti se .. casi altro. Questi casi if else determinano l'ambiente corrente (configurazione) e, in base all'ambiente corrente, chiamano i metodi appropriati per inizializzare/configurare tutto ciò che è necessario.

Inoltre, nota: Tutti i metodi di callback nel DatabaseHandler (classe che ha implementato SQLiteOpenHelper) sono chiamati all'interno del corpo getDatabaseLocked().

Codice sorgente SQLiteOpenHelper.java: https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/core/java/android/database/sqlite/SQLiteOpenHelper.java

Codice sorgente SQLiteDatabase.java: https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/database/sqlite/SQLiteDatabase.java

Esempio da seguire: https://github.com/uddhavgautam/SQLiteBasicSample