Welkom bij de Android SQLite Voorbeeld Tutorial. Android SQLite is de meest gebruikte manier om gegevens op te slaan voor Android-applicaties. Voor veel toepassingen is SQLite het fundament van de apps, of het nu rechtstreeks wordt gebruikt of via een wrapper van een derde partij. Hieronder staat de uiteindelijke app die we vandaag zullen maken met behulp van de Android SQLite-database.
Android SQLite
Android SQLite is een zeer lichte database die wordt geleverd met het Android-besturingssysteem. Android SQLite combineert een schone SQL-interface met een zeer klein geheugengebruik en redelijke snelheid. Voor Android is SQLite “ingebakken” in de Android-runtime, zodat elke Android-applicatie zijn eigen SQLite-databases kan maken. De Android SQLite-native API is niet JDBC, omdat JDBC te veel overhead zou kunnen zijn voor een smartphone met beperkt geheugen. Zodra een database succesvol is aangemaakt, bevindt deze zich in data/data//databases/, toegankelijk vanuit de Android Device Monitor. SQLite is een typische relationele database, met tabellen (bestaande uit rijen en kolommen), indexen, enz. We kunnen onze eigen tabellen maken om de gegevens op de juiste manier vast te houden. Deze structuur wordt aangeduid als een schema.
Android SQLite SQLiteOpenHelper
Android heeft functies beschikbaar om wijzigingen in databaseschema’s te verwerken, die voornamelijk afhangen van het gebruik van de klasse SQLiteOpenHelper
. SQLiteOpenHelper is ontworpen om twee veelvoorkomende problemen op te lossen.
- Wanneer de toepassing voor het eerst wordt uitgevoerd – Op dit moment hebben we nog geen database. Dus moeten we de tabellen, indexen, startgegevens, enzovoort aanmaken.
- Wanneer de toepassing wordt bijgewerkt naar een nieuwer schema – Onze database zal nog steeds het oude schema hebben van de oudere versie van de app. We hebben de mogelijkheid om het databaseschema te wijzigen om aan de behoeften van de rest van de app te voldoen.
SQLiteOpenHelper
verpakt deze logica om een database te maken en bij te werken volgens onze specificaties. Hiervoor moeten we een aangepaste subklasse van SQLiteOpenHelper
maken die ten minste de volgende drie methoden implementeert.
-
Constructor: Deze neemt de Context (bijvoorbeeld een Activity), de naam van de database, een optionele cursor-fabriek (hier komen we later op terug) en een integer die het versienummer van het databaseschema aangeeft dat je gebruikt (meestal beginnend bij 1 en later verhogen).
public DatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); }
-
onCreate(SQLiteDatabase db) : Dit wordt opgeroepen wanneer er geen database is en de app er een nodig heeft. Het geeft ons een
SQLiteDatabase
-object door, dat wijst naar een nieuw aangemaakte database, die we kunnen vullen met tabellen en initiële gegevens. -
onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) : Dit wordt opgeroepen wanneer de versie van het schema die we nodig hebben niet overeenkomt met de versie van het databaseschema. Het geeft ons een SQLiteDatabase-object en de oude en nieuwe versienummers door. Daarom kunnen we de beste manier bedenken om de database van het oude schema naar het nieuwe te converteren.
We definiëren een DBManager
-klasse om alle database-CRUD(Create, Read, Update and Delete)-bewerkingen uit te voeren.
Openen en Sluiten van Android SQLite Database Connectie
Voordat u databasebewerkingen zoals het invoegen, bijwerken, verwijderen van records in een tabel uitvoert, opent u eerst de databaseverbinding door de getWritableDatabase()-methode te bellen zoals hieronder wordt getoond:
public DBManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
database = dbHelper.getWritableDatabase();
return this;
}
De dbHelper is een instantie van de subklasse van SQLiteOpenHelper
. Om een databaseverbinding te sluiten, wordt de volgende methode aangeroepen.
public void close() {
dbHelper.close();
}
Nieuwe Record Invoegen in Android SQLite database tabel
De volgende codefragment toont hoe u een nieuw record invoegt in de Android SQLite-database.
public void insert(String name, String desc) {
ContentValues contentValue = new ContentValues();
contentValue.put(DatabaseHelper.SUBJECT, name);
contentValue.put(DatabaseHelper.DESC, desc);
database.insert(DatabaseHelper.TABLE_NAME, null, contentValue);
}
Content Values maakt een lege set waarden aan met de gegeven initiële grootte. We zullen de andere instantiewaarden bespreken wanneer we bij het codegedeelte komen.
Record Bijwerken in Android SQLite database tabel
De volgende code toont hoe een enkel record bijgewerkt kan worden.
public int update(long _id, String name, String desc) {
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.SUBJECT, name);
contentValues.put(DatabaseHelper.DESC, desc);
int i = database.update(DatabaseHelper.TABLE_NAME, contentValues, DatabaseHelper._ID + " = " + _id, null);
return i;
}
Android SQLite – Het verwijderen van een record
We hoeven alleen het id van het te verwijderen record door te geven, zoals hieronder wordt getoond.
public void delete(long _id) {
database.delete(DatabaseHelper.TABLE_NAME, DatabaseHelper._ID + "=" + _id, null);
}
Android SQLite Cursor
A Cursor represents the entire result set of the query. Once the query is fetched a call to cursor.moveToFirst() is made. Calling moveToFirst() does two things:
- Hiermee kunnen we testen of de query een lege set heeft opgeleverd (door de retourwaarde te testen)
- Het verplaatst de cursor naar het eerste resultaat (wanneer de set niet leeg is)
De volgende code wordt gebruikt om alle records op te halen:
public Cursor fetch() {
String[] columns = new String[] { DatabaseHelper._ID, DatabaseHelper.SUBJECT, DatabaseHelper.DESC };
Cursor cursor = database.query(DatabaseHelper.TABLE_NAME, columns, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
Een andere manier om een Cursor te gebruiken, is door deze in een CursorAdapter
te wikkelen. Net zoals ArrayAdapter
arrays aanpast, past CursorAdapter
Cursor-objecten aan, waardoor hun gegevens beschikbaar zijn voor een AdapterView
zoals een ListView
. Laten we naar ons project springen dat SQLite gebruikt om wat zinvolle gegevens op te slaan.
Android SQLite Voorbeeld Projectstructuur
In deze toepassing willen we records maken die landennamen en hun respectieve valuta opslaan in de vorm van een ListView. We dekken alle bovengenoemde functies.
Android SQLite Project Code
De toepassing bestaat uit 5 klassen. We beginnen met het definiëren van DatabaseHelper, die een subklasse is van SQLiteOpenHelper als volgt: DatabaseHelper.java
package com.journaldev.sqlite;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
public class DatabaseHelper extends SQLiteOpenHelper {
// Tabelnaam
public static final String TABLE_NAME = "COUNTRIES";
// Tabelkolommen
public static final String _ID = "_id";
public static final String SUBJECT = "subject";
public static final String DESC = "description";
// Database-informatie
static final String DB_NAME = "JOURNALDEV_COUNTRIES.DB";
// databaseversie
static final int DB_VERSION = 1;
// Query om tabel te maken
private static final String CREATE_TABLE = "create table " + TABLE_NAME + "(" + _ID
+ " INTEGER PRIMARY KEY AUTOINCREMENT, " + SUBJECT + " TEXT NOT NULL, " + DESC + " TEXT);";
public DatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE_NAME);
onCreate(db);
}
}
Zoals hierboven besproken hebben we de methoden onCreate()
en onUpgrade()
overschreven naast de constructor. We hebben de namen aan de database en de tabel toegewezen als respectievelijk JOURNALDEV_COUNTRIES.DB en COUNTRIES. De indexkolom wordt automatisch geïncrementeerd wanneer een nieuwe rij wordt ingevoegd. De kolomnamen voor land en valuta zijn “onderwerp” en “omschrijving”. De klasse DBManager is waar de DatabaseHelper wordt geïnitialiseerd en de CRUD-bewerkingen worden gedefinieerd. Hieronder staat de code voor deze klasse: DBManager.java
package com.journaldev.sqlite;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
public class DBManager {
private DatabaseHelper dbHelper;
private Context context;
private SQLiteDatabase database;
public DBManager(Context c) {
context = c;
}
public DBManager open() throws SQLException {
dbHelper = new DatabaseHelper(context);
database = dbHelper.getWritableDatabase();
return this;
}
public void close() {
dbHelper.close();
}
public void insert(String name, String desc) {
ContentValues contentValue = new ContentValues();
contentValue.put(DatabaseHelper.SUBJECT, name);
contentValue.put(DatabaseHelper.DESC, desc);
database.insert(DatabaseHelper.TABLE_NAME, null, contentValue);
}
public Cursor fetch() {
String[] columns = new String[] { DatabaseHelper._ID, DatabaseHelper.SUBJECT, DatabaseHelper.DESC };
Cursor cursor = database.query(DatabaseHelper.TABLE_NAME, columns, null, null, null, null, null);
if (cursor != null) {
cursor.moveToFirst();
}
return cursor;
}
public int update(long _id, String name, String desc) {
ContentValues contentValues = new ContentValues();
contentValues.put(DatabaseHelper.SUBJECT, name);
contentValues.put(DatabaseHelper.DESC, desc);
int i = database.update(DatabaseHelper.TABLE_NAME, contentValues, DatabaseHelper._ID + " = " + _id, null);
return i;
}
public void delete(long _id) {
database.delete(DatabaseHelper.TABLE_NAME, DatabaseHelper._ID + "=" + _id, null);
}
}
De klasse `CountryListActivity.java` is de activiteit die wordt gestart wanneer de applicatie wordt gestart. Hieronder is de lay-out ervoor gedefinieerd: `fragment_emp_list.xml`
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="@+id/list_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:dividerHeight="1dp"
android:padding="10dp" >
</ListView>
<TextView
android:id="@+id/empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/empty_list_text" />
</RelativeLayout>
Hierin wordt een ListView-component gedefinieerd om de records op te nemen die zijn opgeslagen in de database. In eerste instantie zou de ListView leeg zijn, dus wordt een TextView gebruikt om hetzelfde weer te geven. `CountryListActivity.java`
package com.journaldev.sqlite;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.support.v4.widget.SimpleCursorAdapter;
import android.support.v7.app.ActionBarActivity;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
public class CountryListActivity extends ActionBarActivity {
private DBManager dbManager;
private ListView listView;
private SimpleCursorAdapter adapter;
final String[] from = new String[] { DatabaseHelper._ID,
DatabaseHelper.SUBJECT, DatabaseHelper.DESC };
final int[] to = new int[] { R.id.id, R.id.title, R.id.desc };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_emp_list);
dbManager = new DBManager(this);
dbManager.open();
Cursor cursor = dbManager.fetch();
listView = (ListView) findViewById(R.id.list_view);
listView.setEmptyView(findViewById(R.id.empty));
adapter = new SimpleCursorAdapter(this, R.layout.activity_view_record, cursor, from, to, 0);
adapter.notifyDataSetChanged();
listView.setAdapter(adapter);
// OnCLickListiner Voor Lijstitems
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView > parent, View view, int position, long viewId) {
TextView idTextView = (TextView) view.findViewById(R.id.id);
TextView titleTextView = (TextView) view.findViewById(R.id.title);
TextView descTextView = (TextView) view.findViewById(R.id.desc);
String id = idTextView.getText().toString();
String title = titleTextView.getText().toString();
String desc = descTextView.getText().toString();
Intent modify_intent = new Intent(getApplicationContext(), ModifyCountryActivity.class);
modify_intent.putExtra("title", title);
modify_intent.putExtra("desc", desc);
modify_intent.putExtra("id", id);
startActivity(modify_intent);
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.add_record) {
Intent add_mem = new Intent(this, AddCountryActivity.class);
startActivity(add_mem);
}
return super.onOptionsItemSelected(item);
}
}
In deze activiteit wordt het DBManager-object aangeroepen om de CRUD-bewerkingen uit te voeren. Een SimpleCursorAdapter is gedefinieerd om elementen aan de lijst toe te voegen vanuit de queryresultaten die worden geretourneerd in een Cursor-object. Bij het klikken op een lijstitem wordt een intentie uitgevoerd om de klasse ModifyCountryActivity te openen. Het menu bevat een item om een nieuw record toe te voegen vanuit de ActionBar. Hier wordt opnieuw een intentie uitgevoerd om de klasse AddCountryActivity te openen. Hieronder staat de code van `menu.xml`. `menu.xml`
<menu xmlns:android="https://schemas.android.com/apk/res/android"
xmlns:app="https://schemas.android.com/apk/res-auto"
xmlns:tools="https://schemas.android.com/tools"
tools:context="com.example.sqlitesample.MainActivity" >
<item
android:id="@+id/add_record"
android:icon="@android:drawable/ic_menu_add"
android:orderInCategory="100"
android:title="@string/add_record"
app:showAsAction="always"/>
</menu>
De xml-lay-out en code van het bestand `AddCountryActivity.java` zijn hieronder gedefinieerd: `activity_add_record.xml`
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="20dp" >
<EditText
android:id="@+id/subject_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_title" >
<requestFocus />
</EditText>
<EditText
android:id="@+id/description_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_desc"
android:inputType="textMultiLine"
android:minLines="5" >
</EditText>
<Button
android:id="@+id/add_record"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="@string/add_record" />
</LinearLayout>
Er worden twee EditText-componenten gedefinieerd die de invoer voor land en valuta accepteren, samen met een knop om de waarden aan de database toe te voegen en deze weer te geven in de ListView. `AddCountryActivity.java`
package com.journaldev.sqlite;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class AddCountryActivity extends Activity implements OnClickListener {
private Button addTodoBtn;
private EditText subjectEditText;
private EditText descEditText;
private DBManager dbManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Add Record");
setContentView(R.layout.activity_add_record);
subjectEditText = (EditText) findViewById(R.id.subject_edittext);
descEditText = (EditText) findViewById(R.id.description_edittext);
addTodoBtn = (Button) findViewById(R.id.add_record);
dbManager = new DBManager(this);
dbManager.open();
addTodoBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.add_record:
final String name = subjectEditText.getText().toString();
final String desc = descEditText.getText().toString();
dbManager.insert(name, desc);
Intent main = new Intent(AddCountryActivity.this, CountryListActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(main);
break;
}
}
}
De CRUD-bewerking die hier wordt uitgevoerd, is het toevoegen van een nieuw record aan de database. De xml-lay-out en code van het bestand ModifyCountryActivity.java zijn hieronder gedefinieerd: `activity_modify_record.xml`
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="10dp" >
<EditText
android:id="@+id/subject_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:ems="10"
android:hint="@string/enter_title" />
<EditText
android:id="@+id/description_edittext"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:ems="10"
android:hint="@string/enter_desc"
android:inputType="textMultiLine"
android:minLines="5" >
</EditText>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:weightSum="2"
android:gravity="center_horizontal"
android:orientation="horizontal" >
<Button
android:id="@+id/btn_update"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/btn_update" />
<Button
android:id="@+id/btn_delete"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="@string/btn_delete" />
</LinearLayout>
</LinearLayout>
Het is vergelijkbaar met de vorige lay-out, behalve dat er knoppen voor wijzigen en verwijderen zijn toegevoegd. `ModifyCountryActivity.java`
package com.journaldev.sqlite;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
public class ModifyCountryActivity extends Activity implements OnClickListener {
private EditText titleText;
private Button updateBtn, deleteBtn;
private EditText descText;
private long _id;
private DBManager dbManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setTitle("Modify Record");
setContentView(R.layout.activity_modify_record);
dbManager = new DBManager(this);
dbManager.open();
titleText = (EditText) findViewById(R.id.subject_edittext);
descText = (EditText) findViewById(R.id.description_edittext);
updateBtn = (Button) findViewById(R.id.btn_update);
deleteBtn = (Button) findViewById(R.id.btn_delete);
Intent intent = getIntent();
String id = intent.getStringExtra("id");
String name = intent.getStringExtra("title");
String desc = intent.getStringExtra("desc");
_id = Long.parseLong(id);
titleText.setText(name);
descText.setText(desc);
updateBtn.setOnClickListener(this);
deleteBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_update:
String title = titleText.getText().toString();
String desc = descText.getText().toString();
dbManager.update(_id, title, desc);
this.returnHome();
break;
case R.id.btn_delete:
dbManager.delete(_id);
this.returnHome();
break;
}
}
public void returnHome() {
Intent home_intent = new Intent(getApplicationContext(), CountryListActivity.class)
.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(home_intent);
}
}
De CRUD-operaties die hier worden uitgevoerd, zijn het bijwerken en verwijderen van een record. De onderstaande afbeeldingen zijn schermafbeeldingen van de uiteindelijke uitvoer van ons project. De eerste afbeelding is de uitvoer die wordt gezien wanneer de toepassing voor de eerste keer wordt gelanceerd. De tweede afbeelding is het resultaat van het klikken op de menuoptie in de ActionBar om een nieuw record toe te voegen, zoals hieronder getoond.
De derde afbeelding toont een uitvoer wanneer er 3 records zijn toegevoegd:
De vierde afbeelding toont de uitvoer wanneer er op een lijstitem wordt geklikt om een record te wijzigen of te verwijderen:
De laatste afbeelding is de uitvoer wanneer een record wordt verwijderd. In dit voorbeeld verwijderen we het eerste record:
Het openen van het Android SQLite-databasebestand
Zoals we eerder hebben besproken in deze tutorial, wordt het databasebestand opgeslagen in de interne opslag die toegankelijk is vanuit de Android Device Monitor zoals te zien is in de afbeelding hieronder. Om deze database te bekijken moeten we dit bestand van het apparaat naar onze desktop halen. Dit wordt gedaan door op de menuoptie in de rechterbovenhoek te klikken zoals te zien is in de afbeelding hieronder:
Om dit bestand te openen, download de SQLiteBrowser van deze link. De fragmenten hieronder tonen het schema en de tabellen in de browser.
Om de tabel te bekijken, ga naar het tabblad Browse Data bovenaan. De volgende afbeelding is te zien:
Hiermee komt een einde aan de Android SQLite tutorial. Het uiteindelijke Android SQLite-project is te downloaden vanaf de onderstaande link.
Source:
https://www.digitalocean.com/community/tutorials/android-sqlite-database-example-tutorial