Tässä luvussa käymme läpi, kuinka luoda yksinkertainen sanakirjasovellus Androidille käyttäen SQLite-tietokantaa. Käytämme tämän sovelluksen kehittämisessä muutamia keskeisiä Androidin tietokantatoimintoja, kuten tietokannan luomista, tietueiden lisäämistä ja muokkaamista sekä niiden näyttämistä käyttöliittymässä.

Sovelluksen pääkomponentti on DictionaryDatabase-luokka, joka hallitsee tietokannan käyttöä. Ensimmäinen askel on määrittää tietokannan nimi, taulun nimi sekä kenttien nimet, jotka tallentavat sanan ja sen määritelmän:

java
private static final String DATABASE_NAME = "dictionary.db";
private static final String TABLE_DICTIONARY = "dictionary"; private static final String FIELD_WORD = "word"; private static final String FIELD_DEFINITION = "definition"; private static final int DATABASE_VERSION = 1;

Tietokannan versio on tärkeä, sillä sitä tarvitaan, kun päivitetään tietokannan rakennetta. Tietokannan luominen tapahtuu onCreate()-metodissa:

java
@Override public void onCreate(SQLiteDatabase db) { db.execSQL("CREATE TABLE " + TABLE_DICTIONARY + "(_id integer PRIMARY KEY," + FIELD_WORD + " TEXT, " + FIELD_DEFINITION + " TEXT);"); }

Tämä metodi suoritetaan vain, kun tietokanta luodaan ensimmäistä kertaa. Mikäli tietokannan rakennetta täytyy päivittää, käytetään onUpgrade()-metodia, jossa hallitaan muutoksia tietokannan versiota kasvatettaessa.

Seuraavaksi luodaan metodeja, jotka mahdollistavat tietueiden luomisen, päivittämisen ja poistamisen. saveRecord()-metodi tarkistaa, onko sana jo tietokannassa. Jos on, se päivittää vanhan tietueen, jos ei, se lisää uuden:

java
public void saveRecord(String word, String definition) {
long id = findWordID(word); if (id > 0) { updateRecord(id, word, definition); } else { addRecord(word, definition); } }

addRecord()-metodi lisää sanan ja määritelmän tietokantaan:

java
public long addRecord(String word, String definition) { SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(FIELD_WORD, word); values.put(FIELD_DEFINITION, definition);
return db.insert(TABLE_DICTIONARY, null, values); }

Tietueen päivitys ja poistaminen tapahtuvat updateRecord() ja deleteRecord()-metodeilla:

java
public int updateRecord(long id, String word, String definition) { SQLiteDatabase db = getWritableDatabase();
ContentValues values = new ContentValues();
values.put(
"_id", id); values.put(FIELD_WORD, word); values.put(FIELD_DEFINITION, definition); return db.update(TABLE_DICTIONARY, values, "_id = ?", new String[]{String.valueOf(id)}); }
public int deleteRecord(long id) {
SQLiteDatabase db = getWritableDatabase(); return db.delete(TABLE_DICTIONARY, "_id = ?", new String[]{String.valueOf(id)}); }

Tietojen lukeminen tietokannasta hoituu metodien findWordID() ja getDefinition() avulla:

java
public long findWordID(String word) {
long returnVal = -1; SQLiteDatabase db = getReadableDatabase(); Cursor cursor = db.rawQuery( "SELECT _id FROM " + TABLE_DICTIONARY + " WHERE " + FIELD_WORD + " = ?", new String[]{word}); if (cursor.getCount() == 1) { cursor.moveToFirst(); returnVal = cursor.getInt(0); } return returnVal; } public String getDefinition(long id) { String returnVal = ""; SQLiteDatabase db = getReadableDatabase(); Cursor cursor = db.rawQuery( "SELECT definition FROM " + TABLE_DICTIONARY + " WHERE _id = ?", new String[]{String.valueOf(id)}); if (cursor.getCount() == 1) { cursor.moveToFirst(); returnVal = cursor.getString(0); } return returnVal; }

Kun findWordID()-metodi palauttaa sanan ID:n, sitä voidaan käyttää määritelmän hakemiseen. getWordList() puolestaan palauttaa kaikki sanat tietokannasta:

java
public Cursor getWordList() {
SQLiteDatabase db = getReadableDatabase(); String query = "SELECT _id, " + FIELD_WORD + " FROM " + TABLE_DICTIONARY + " ORDER BY " + FIELD_WORD + " ASC"; return db.rawQuery(query, null); }

MainActivity-luokassa määritellään käyttöliittymäkomponentit, kuten EditText-kentät sanan ja määritelmän syöttämistä varten, sekä ListView, johon sanakirjan sanat listataan:

java
EditText mEditTextWord;
EditText mEditTextDefinition; DictionaryDatabase mDB; ListView mListView;

Kun käyttäjä klikkaa "Tallenna" -painiketta, sanan ja määritelmän tiedot tallennetaan tietokantaan ja käyttöliittymä päivitetään:

java
private void saveRecord() { mDB.saveRecord(mEditTextWord.getText().toString(), mEditTextDefinition.getText().toString()); mEditTextWord.setText(""); mEditTextDefinition.setText(""); updateWordList(); }

ListView päivitetään seuraavalla metodilla, joka käyttää SimpleCursorAdapter-komponenttia sanalistan näyttämiseksi:

java
private void updateWordList() {
SimpleCursorAdapter simpleCursorAdapter = new SimpleCursorAdapter( this, android.R.layout.simple_list_item_1, mDB.getWordList(), new String[]{"word"}, new int[]{android.R.id.text1}, 0); mListView.setAdapter(simpleCursorAdapter); }

Kun sanaa klikkaa, sen määritelmä näytetään Toast-viestinä. Pitkällä klikkauksella sana poistetaan tietokannasta.

On tärkeää huomata, että SQLite-tietokannan käyttö Androidissa voi olla suorituskykyyn vaikuttava tekijä. Erityisesti, kun tietokanta kasvaa suureksi, on tärkeää optimoida kyselyjä ja käyttää tehokkaita rakenteita.

Lopuksi kannattaa muistaa, että tietokannan versionhallinta on olennainen osa Android-sovelluksen ylläpitoa. Jokainen muutettu versio vaatii tietokannan rakenteen päivityksen, joka voidaan toteuttaa onUpgrade()-metodissa. Samalla on hyvä pitää mielessä, että tietokannan hallinnan ja UI-päivitysten välillä tulee olla selkeä ero, jotta sovelluksen käyttäjäkokemus pysyy sujuvana.

Miten käytetään Androidin ilmoituksia ja hälytyksiä tehokkaasti?

Android tarjoaa monia tapoja ilmoittaa käyttäjille eri tilanteissa. Näitä ilmoituksia voi jakaa visuaalisiin ja ei-visuaalisiin menetelmiin, kuten valoihin, ääniin ja tärinään. Vaikka ilmoitukset voivat olla erittäin hyödyllisiä, niiden käyttöön on kuitenkin suhtauduttava varoen, sillä ne voivat helposti häiritä käyttäjää. Hyvin suunnitellut ja harkitut ilmoitukset voivat parantaa käyttäjäkokemusta, mutta liiallinen ilmoittelu voi johtaa käyttäjien ärsyyntymiseen ja sovelluksen poistamiseen. Tämän vuoksi on tärkeää osata käyttää ilmoituksia oikein ja antaa käyttäjälle mahdollisuus hallita niitä.

Androidissa on monenlaisia tapoja kiinnittää käyttäjän huomio. Yksi yleisimmistä menetelmistä on visuaaliset ilmoitukset, kuten Toast-viestit, AlertDialogit ja ProgressDialogit. Toisaalta, on olemassa myös ei-visuaalisia ilmoitusmenetelmiä, kuten äänet, tärinä ja valot. Käyttäjän huomion saaminen ei aina vaadi visuaalisia elementtejä, ja joskus yksinkertaisilla ei-visuaalisilla hälytyksillä voi olla suuri vaikutus.

Tässä osassa käsitellään erityisesti kolme keskeistä ei-visuaalista ilmoitustapaa: valo, ääni ja tärinä. Näiden avulla voidaan antaa käyttäjälle tehokasta palautetta ilman, että sovellus häiritsee heidän nykyistä toimintaa liikaa.

Valon, äänen ja tärinän käyttö on erittäin yksinkertaista. Yksi esimerkki on kameran salaman käyttäminen taskulamppuna. Tämä ominaisuus on saatavilla Android 6.0 (API 23) ja sitä uudemmissa laitteissa, jotka tukevat salaman käyttöä. Taskulamppu voidaan kytkeä päälle ja pois päältä helposti setTorchMode()-metodilla. Toinen esimerkki on puhelimen tärinän hyödyntäminen käyttäjän huomion saamiseksi. Tärinä voidaan aktivoida suoraan sovelluksesta Vibrator-luokan avulla. Lisäksi voidaan soittaa ilmoitussoundeja, kuten soittoääniä, käyttämällä RingtoneManager-luokkaa.

Esimerkiksi, kun käyttäjä tarvitsee visuaalista palautetta, voidaan käyttää valon välähdystä tai vaikka puhelimen tärinää, mutta jos käyttäjän on vain tiedettävä, että jokin on tapahtunut ilman visuaalista häiriötä, äänet ja tärinä voivat riittää. Ääniä ja tärinää voidaan käyttää erityisesti, jos halutaan antaa käyttäjälle palautetta ilman, että tämä on aktiivisesti katsomassa puhelimen näyttöä.

Jos taas tarvitset visuaalisia hälytyksiä, Android tarjoaa Toast-viestejä ja AlertDialogeja. Toast-viestit ovat tilapäisiä viestejä, jotka ilmestyvät näytölle tietyksi ajaksi ja häviävät sen jälkeen automaattisesti. Tämä tekee niistä loistavan tavan antaa käyttäjälle pientä palautetta ilman häiritsemistä. AlertDialogit puolestaan ovat vuorovaikutteisia ikkunanäkymiä, joissa käyttäjä voi valita vaihtoehtoja tai vastata kysymyksiin. Näitä voidaan käyttää silloin, kun käyttäjän on tehtävä valinta tai annettava lisätietoja.

ProgressDialog puolestaan on kätevä tapa näyttää käyttäjälle, että sovellus tekee taustalla jotakin, kuten tiedon lataamista tai prosessin suorittamista. Tämä voidaan näyttää jatkuvana indikaattorina, joka kertoo, että prosessi on käynnissä ja että käyttäjän on odotettava.

On kuitenkin tärkeää muistaa, että ilmoitukset eivät saa olla liian häiritseviä. Ilmoitusten pitäisi olla harkittuja ja niitä pitäisi käyttää vain silloin, kun ne ovat todella tarpeen. Lisäksi käyttäjälle tulisi antaa mahdollisuus hallita ilmoituksia, esimerkiksi mahdollisuus kytkeä ne pois päältä, jos niin haluaa. Tämä luo käyttäjälle paremman kokemuksen ja estää ärsytystä.

Lisäksi, kun käytetään ei-visuaalisia ilmoituksia kuten ääniä, tärinää ja valoja, on tärkeää miettiä, kuinka usein niitä käytetään ja millaisessa kontekstissa. Liiallinen käyttö voi vaikuttaa negatiivisesti käyttäjäkokemukseen, ja on tärkeää valita oikea tyyppi ilmoitusta tilanteen mukaan.

Lopuksi, vaikka ei-visuaaliset ilmoitukset voivat olla hyödyllisiä, on hyvä yhdistää niitä tarvittaessa visuaalisiin ilmoituksiin, jotta varmistetaan, että käyttäjä saa halutun palautteen oikealla hetkellä.

Miten peruuttaa HTTP-pyynnöt Volleyllä Android-sovelluksessa

Volley on tehokas kirjasto, joka yksinkertaistaa HTTP-pyyntöjen hallintaa Android-sovelluksissa. Erityisesti, jos sovellus tekee useita samanaikaisia pyyntöjä, voi olla tarpeen peruuttaa osa niistä, erityisesti jos käyttäjä siirtyy toiseen aktiviteettiin tai jos tilanne muuttuu. Tässä osassa käsitellään, kuinka voit helposti peruuttaa HTTP-pyynnöt Volleyllä ja hallita niitä tehokkaasti.

Volley-kirjaston käyttöönottaminen Android-sovellukseen on helppoa. Mikäli et ole vielä lisännyt Volleya projektiisi, ensimmäinen askel on määrittää se. Luo uusi projekti Android Studiossa ja nimeä se esimerkiksi CancelVolleyRequest. Valitse "Phone & Tablet" ja "Empty Activity", kun sinua pyydetään valitsemaan Activity-tyyppi.

Kun Volley on lisätty projektiin, seuraavat vaiheet vievät sinut peruutustoiminnon toteuttamiseen:

  1. Muokkaa activity_main.xml -tiedostoa:
    Korvaa olemassa oleva TextView seuraavalla XML-koodilla:

    xml
    <TextView android:id="@+id/textView" android:layout_width="match_parent" android:layout_height="match_parent" android:text="HTTP response will appear here" android:textSize="18sp" android:padding="16dp"/>
  2. Lisää globaalit muuttujat MainActivity.java -tiedostoon:
    Määrittele RequestQueue-muuttuja, joka hallitsee kaikkia pyyntöjä:

    java
    RequestQueue mRequestQueue;
  3. Muokkaa onCreate()-metodia alustamaan RequestQueue:
    Lisää seuraava koodi, joka luo uuden RequestQueue-instanssin:

    java
    mRequestQueue = Volley.newRequestQueue(this);
  4. Luo sendRequest()-metodi:
    Tämä metodi lähettää HTTP-pyynnön ja käsittelee vastauksen. Muista, että se on hyvin samanlainen kuin edellisessä reseptissä, mutta siinä on muutamia lisämuutoksia:

    java
    public void sendRequest(View view) {
    final TextView textView = (TextView) findViewById(R.id.textView);
    String url = "https://www.packtpub.com/";
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url, new Response.Listener<String>() { @Override
    public void onResponse(String response) {
    textView.setText(response.substring(
    0, 500)); } }, new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { textView.setText("onErrorResponse(): " + error.getMessage()); } }); stringRequest.setTag(this); mRequestQueue.add(stringRequest); finish(); }
  5. Lisää Close-painikkeen onClick-metodi:
    Tämä metodi sulkee aktiviteetin ja lopettaa mahdolliset aktiiviset pyynnöt:

    java
    public void close(View view) {
    finish(); }
  6. Ylikirjoita onStop()-metodi peruuttaaksesi kaikki pyynnöt:
    Tämä koodi peruuttaa kaikki pyynnöt, joissa käytetään tätä aktiviteettia tunnisteena:

    java
    @Override protected void onStop() { super.onStop(); mRequestQueue.cancelAll(this); }

Kun tämä on valmis, voit ajaa sovelluksen laitteessa tai emulaattorissa. Volley takaa, että peruutetut pyynnöt eivät koskaan tuota vastauksia, mikä estää mahdolliset virheet ja muistivuodot.


Tärkeää on ymmärtää, että pyynnön peruutus ei ole vain yksinkertainen mekanismi. Se on osa puolustavaa ohjelmointia, joka auttaa varmistamaan, että sovelluksen tilassa ei ole epätoivottuja reaktioita. Kun peruutamme pyynnön, ei tarvitse lisätä koodia, joka tarkistaa, onko aktiviteetti edelleen olemassa, sillä Volley varmistaa, ettei vastauksia tule peruutetuilta pyynnöiltä.

Toinen oleellinen seikka on, että pyyntöjen hallintaa voi säätää tarkemmin, kun käytämme erillisiä tunnisteita (tag). Näin voimme ryhmitellä pyynnöt ja peruuttaa niitä tarkasti tarpeen mukaan. Tunnisteita voi käyttää monella tavalla, esimerkiksi aktivoimalla tietyt toiminnot vain tietyille pyyntöryhmille.

Volley ei rajoitu vain HTTP-pyyntöjen tekemiseen ja hallintaan. Se tukee myös JSON-vastauksia ja kuvien lataamista, jolloin sen käyttöalue laajenee monenlaisiin mobiilisovelluksiin. JSON-vastauksen pyytämiseksi Volley tarjoaa JsonObjectRequest- ja JsonArrayRequest-luokkia, joilla voidaan käsitellä JSON-muotoista dataa suoraan. Kuvat puolestaan voidaan ladata ja näyttää ImageRequest-luokan avulla.

Jos sovelluksessa käsitellään paljon ulkoisia HTTP-pyyntöjä, kuten JSON-dataa tai kuvia, Volley tarjoaa nopean ja luotettavan tavan toteuttaa nämä pyynnöt. Tämä ei ainoastaan paranna sovelluksen suorituskykyä, vaan myös sen käytettävyyttä ja vakaudenhallintaa.