SQLite
 sql >> Database >  >> RDS >> SQLite

come avviare l'app con SQLite darabase sull'emulatore di Android Studio?

Poiché stai riscontrando difficoltà, il seguente è un tutorial messo insieme frettolosamente insieme al codice.

  1. Crea il database e le tabelle in uno strumento SQLite, aggiungendo i dati come richiesto e quindi salvalo.

  2. Chiudere il database e riaprirlo per verificare che le tabelle ei dati siano come previsto. In caso contrario, apportare le modifiche e ripetere 2 finché non si è sicuri che il database salvato corrisponda.

  3. Ottieni il nome del file del database salvato e registralo includendo l'estensione del file.

  4. Se non hai ancora creato un progetto per l'app, fallo e salva il progetto.

  5. Al di fuori dell'IDE, vai alla cartella app/src/main dei progetti e crea una cartella denominata assets se non esiste già.

  6. Copia il file di database nella cartella delle risorse.

  7. Apri il progetto in Android Studio.

  8. Crea una nuova classe Java denominata DatabaseHelper con SuperClass come SQLiteOpenHelper (si risolverà in android.database.sqlite.SQLiteOpenHelper ) e seleziona Mostra sostituzioni selezionate Casella di controllo. Fare clic su OK.

Dovrebbe assomigliare a :-

public class DatabaseHelper extends SQLiteOpenHelper {
    public Databasehelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {
        super(context, name, factory, version);
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {

    }
}
  1. Aggiungi una riga, come variabile di classe, dopo public class DatabaseHelper extends SQLiteOpenHelper { è come :-

    public static final String DBNAME = "my_dic.db";
    
    • Nota che è importante che il valore tra le virgolette sia esattamente lo stesso del nome del file che è stato copiato nella cartella delle risorse.

.

  1. Aggiungi le seguenti variabili di classe

:-

public static final int DBVERSION = 1;
public static final String TB_BOOKMARK = "Bookmark";
public static final String COL_BOOKMARK_KEY = "key";
public static final String COL_BOOKMARK_VALUE = "value";
public static final String COL_BOOKMARK_DATE = "date";
SQLiteDatabase mDB;
  • Osservando che i valori tra virgolette devono corrispondere ai nomi delle colonne/tabelle dei valori definiti nel database per TB_BOOKMARK, COL_BOOKMARK_KEY, COL_BOOKMARK_VALUE e COl_BOOKMARK_DATE.
    • DBVERSION sarà il numero di versione memorizzato nel campo user_version del database.
    • SQliteDatabase mDB è una dichiarazione per una variabile che contiene SQLiteDatabase quando è stata aperta. NOTA attualmente il suo valore è nullo finché non è stato impostato.

.

  1. Cambia il costruttore per la classe Databasehelper da :-

    public DatabaseHelper(Context context, String name, SQLiteDatabase.CursorFactory factory, int version) {super(context, name, factory, version);}

a :-

public DatabaseHelper(Context context) {
    super(context, DBNAME, null, DBVERSION);
}
  • In questo modo è possibile creare un'istanza della classe Databasehelper con un solo parametro, il contesto. Gli altri valori sono stati definiti o nel caso della fabbrica nessuno verrà utilizzato, quindi null significa questo.

.

  1. Aggiungi un metodo, ifDBExists alla classe DatabaseHelper per verificare se il database esiste (vuoi copiarlo dal file delle risorse solo una volta)

:-

private boolean ifDBExists(Context context) {
    String dbparent = context.getDatabasePath(DBNAME).getParent();
    File f = context.getDatabasePath(DBNAME);
    if (!f.exists()) {
        Log.d("NODB MKDIRS","Database file not found, making directories."); //<<<< remove before the App goes live.
        File d = new File(dbparent);
        d.mkdirs();
        //return false;
    }
    return f.exists();
}
  • Oltre a verificare che il file di database esista (notare che si presume sia un file di database valido),
  • Inoltre, se il database non esiste, è possibile che la directory del database non esista, questo la creerà se non esiste.

.

  1. Aggiungi un altro metodo copyDBFromAssets per copiare il file della risorsa nel database

:-

private boolean copyDBFromAssets(Context context) {
    Log.d("CPYDBINFO","Starting attemtpt to cop database from the assets file.");
    String DBPATH = context.getDatabasePath(DBNAME).getPath();
    InputStream is;
    OutputStream os;
    int length = 8192;
    long bytes_read = 0;
    long bytes_written = 0;
    byte[] buffer = new byte[length];

    try {

        is = context.getAssets().open(DBNAME);
    } catch (IOException e) {
        Log.e("CPYDB FAIL - NO ASSET","Failed to open the Asset file " + DBNAME);
        e.printStackTrace();
        return false;
    }

    try {
        os = new FileOutputStream(DBPATH);
    } catch (IOException e) {
        Log.e("CPYDB FAIL - OPENDB","Failed to open the Database File at " + DBPATH);
        e.printStackTrace();
        return false;
    }
    Log.d("CPYDBINFO","Initiating copy from asset file" + DBNAME + " to " + DBPATH);
    while (length >= 8192) {
        try {
            length = is.read(buffer,0,length);
        } catch (IOException e) {
            Log.e("CPYDB FAIL - RD ASSET",
                    "Failed while reading in data from the Asset. " +
                            String.valueOf(bytes_read) +
                            " bytes read ssuccessfully."
            );
            e.printStackTrace();
            return false;
        }
        bytes_read = bytes_read + length;
        try {
            os.write(buffer,0,length);
        } catch (IOException e) {
            Log.e("CPYDB FAIL - WR ASSET","failed while writing Database File " +
                    DBPATH +
                    ". " +
            String.valueOf(bytes_written) +
                    " bytes written successfully.");
            e.printStackTrace();
            return false;

        }
        bytes_written = bytes_written + length;
    }
    Log.d("CPYDBINFO",
            "Read " + String.valueOf(bytes_read) + " bytes. " +
                    "Wrote " + String.valueOf(bytes_written) + " bytes."
    );
    try {
        os.flush();
        is.close();
        os.close();
    } catch (IOException e ) {
        Log.e("CPYDB FAIL - FINALISING","Failed Finalising Database Copy. " +
                String.valueOf(bytes_read) +
                " bytes read." +
                String.valueOf(bytes_written) +
                " bytes written."
        );
        e.printStackTrace();
        return false;
    }
    return true;
}
  • Nota che questo è intenzionalmente prolisso, in modo che qualsiasi errore possa essere individuato con precisione.

La classe DatabaseHelper completa sarebbe ora :-

public class DatabaseHelper extends SQLiteOpenHelper {

    public static final String DBNAME = "my_dic.db"; // <<<< VERY IMPORTANT THAT THIS MATCHES DATABASE FILE NAME
    public static final int DBVERSION = 1;
    public static final String TB_BOOKMARK = "Bookmark";
    public static final String COL_BOOKMARK_KEY = "key";
    public static final String COL_BOOKMARK_VALUE = "value";
    public static final String COL_BOOKMARK_DATE = "date";
    SQLiteDatabase mDB;

    public DatabaseHelper(Context context) {
        super(context, DBNAME, null, DBVERSION);
        if (!ifDBExists(context)) {
            if (!copyDBFromAssets(context)) {
                throw new RuntimeException("Failed to Copy Database From Assets Folder");
            }
        }
        mDB = this.getWritableDatabase();
    }

    @Override
    public void onCreate(SQLiteDatabase sqLiteDatabase) {

    }

    @Override
    public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    }

    private boolean ifDBExists(Context context) {
        String dbparent = context.getDatabasePath(DBNAME).getParent();
        File f = context.getDatabasePath(DBNAME);
        if (!f.exists()) {
            Log.d("NODB MKDIRS","Database file not found, making directories.");
            File d = new File(dbparent);
            d.mkdirs();
            //return false;
        }
        return f.exists();
    }

    private boolean copyDBFromAssets(Context context) {
        Log.d("CPYDBINFO","Starting attemtpt to cop database from the assets file.");
        String DBPATH = context.getDatabasePath(DBNAME).getPath();
        InputStream is;
        OutputStream os;
        int length = 8192;
        long bytes_read = 0;
        long bytes_written = 0;
        byte[] buffer = new byte[length];

        try {

            is = context.getAssets().open(DBNAME);
        } catch (IOException e) {
            Log.e("CPYDB FAIL - NO ASSET","Failed to open the Asset file " + DBNAME);
            e.printStackTrace();
            return false;
        }

        try {
            os = new FileOutputStream(DBPATH);
        } catch (IOException e) {
            Log.e("CPYDB FAIL - OPENDB","Failed to open the Database File at " + DBPATH);
            e.printStackTrace();
            return false;
        }
        Log.d("CPYDBINFO","Initiating copy from asset file" + DBNAME + " to " + DBPATH);
        while (length >= 8192) {
            try {
                length = is.read(buffer,0,length);
            } catch (IOException e) {
                Log.e("CPYDB FAIL - RD ASSET",
                        "Failed while reading in data from the Asset. " +
                                String.valueOf(bytes_read) +
                                " bytes read ssuccessfully."
                );
                e.printStackTrace();
                return false;
            }
            bytes_read = bytes_read + length;
            try {
                os.write(buffer,0,length);
            } catch (IOException e) {
                Log.e("CPYDB FAIL - WR ASSET","failed while writing Database File " +
                        DBPATH +
                        ". " +
                String.valueOf(bytes_written) +
                        " bytes written successfully.");
                e.printStackTrace();
                return false;

            }
            bytes_written = bytes_written + length;
        }
        Log.d("CPYDBINFO",
                "Read " + String.valueOf(bytes_read) + " bytes. " +
                        "Wrote " + String.valueOf(bytes_written) + " bytes."
        );
        try {
            os.flush();
            is.close();
            os.close();
        } catch (IOException e ) {
            Log.e("CPYDB FAIL - FINALISING","Failed Finalising Database Copy. " +
                    String.valueOf(bytes_read) +
                    " bytes read." +
                    String.valueOf(bytes_written) +
                    " bytes written."
            );
            e.printStackTrace();
            return false;
        }
        return true;
    }
}

.

  1. Cambia il costruttore per eseguire copyDBFromAssets metodo quando/se il database non esiste (utilizzando il metodo ifDBExists metodo)

:-

public DatabaseHelper(Context context) {
    super(context, DBNAME, null, DBVERSION);
    if (!ifDBExists(context)) {
        if (!copyDBFromAssets(context)) {
            throw new RuntimeException("Failed to Copy Database From Assets Folder");
        }
    }
    mDB = this.getWritableDatabase();
}
  • Nota se si è verificato un problema durante la copia del database, l'app verrà interrotta a causa di RunTimeExcpetion rilasciato.

.

  1. Ultima modifica del metodo onCreate di un'attività (normalmente sarebbe l'attività principale) per creare un'istanza della classe DatabaseHelper. Quindi esegui l'App (se l'App è stata eseguita sarebbe meglio eliminare i dati dell'App prima di farlo, nel caso in cui sia stato creato un database, magari vuoto.)

Il codice seguente include anche una query che ti dirà quali tabelle esistono nel database:-

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DatabaseHelper mDBHlpr = new DatabaseHelper(this);
        Cursor csr = mDBHlpr.getWritableDatabase().query(
                "sqlite_master",
                null,null,null,null,null,null
        );
        while (csr.moveToNext()) {
            Log.d("DB TABLES", csr.getString(csr.getColumnIndex("name")));
        }
        csr.close();
    }
}

Basato sullo screenshot e su un file di database denominato my_dic.db . L'output nel registro è :-

06-16 02:28:45.208 4467-4467/? D/NODB MKDIRS: Database file not found, making directories.
06-16 02:28:45.208 4467-4467/? D/CPYDBINFO: Starting attemtpt to cop database from the assets file.
    Initiating copy from asset filemy_dic.db to /data/data/com.mydictionaryapp.mydictionaryapp/databases/my_dic.db
    Read 12288 bytes. Wrote 12288 bytes.
06-16 02:28:45.224 4467-4467/? D/DB TABLES: Bookmark
    sqlite_autoindex_Bookmark_1
    android_metadata
  • Questo indica che :-
    • Il database non esisteva ed è stata creata la directory dei database (ad esempio data/data/<package name>/databases )
    • 12288 byte sono stati copiati dal file dell'asset al file del database (ovvero è stata eseguita una copia corretta).
    • Il database risultante ha tre voci nella tabella sqlite_master, la tabella BookMark, una tabella chiamata android_metadata (una tabella creata automaticamente per i dispositivi Android dall'SDK che memorizza le impostazioni locali) e un indice generato automaticamente per la tabella BookMark.

Problema successivo

Fondamentalmente l'oggetto non ha un metodo chiamato getClass, piuttosto è necessario utilizzare il metodo getClass ereditato dal frammento. Quindi è necessario racchiudere tra parentesi il frammento restituito.

Quindi invece di :-

String activeFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container).getClass().getSimpleName();

Potresti usare :-

String activeFragment = (getSupportFragmentManager().findFragmentById(R.id.fragment_container)).getClass().getSimpleName();

In alternativa potresti usare :-

Fragment activeFragment = getSupportFragmentManager().findFragmentById(R.id.fragment_container);

insieme all'utilizzo di :-

if (activeFragment instanceOf BookmarkFragment) { ...... rest of your code

invece di usare if (activeFragment.equals(BookmarkFragment.class.getSimpleName())) { ......