Changes between Version 35 and Version 36 of Android


Ignore:
Timestamp:
2011-05-17 17:27:28 (7 years ago)
Author:
hesaburt
Comment:

Siirretty bensalaskuri uudelle sivulle

Legend:

Unmodified
Added
Removed
Modified
  • Android

    v35 v36  
    292292 
    293293 
    294  
    295  
    296 == 3. Bensalaskuri - Tiedon tallentaminen tietokantaan Androidissa == 
    297  
    298  
    299 === 3.1 Luo uusi android projekti === 
    300   - Project Name: BensaLaskuri 
    301   - Build Target: Google APIs 2.2  
    302   - Application Name: Bensalaskuri 
    303   - Package Name: fi.jyu.mit.android.bensalaskuri 
    304   - Create Activity: BensaLaskuri 
    305  
    306 Järjestelmä luo automaattisesti tarvittavat tiedostot, niihin ei tarvitse 
    307 kiinnittää huomiota.  
    308  
    309 [Image(bensalaskuri1.png)]] 
    310  
    311 === 3.2 GUI === 
    312 Ensin lähdetään muokkaamaan ulkoasua. Uudemmassa 
    313 SDK:ssa on jokseenkin toimiva graafinen työkalu ulkoasun suunnittelemiseen. 
    314 XML-tiedosto löytyy BensaLaskuri -> res -> layout -> main.xml 
    315  
    316 Piirretään sopiva GUI. Esimerkkitapauksessa päädyttiin kolmeen EditTextiin, 
    317 kahteen Buttoniin ja yhteen kulutuksen kertovaan TexTviewiin ja 
    318 yhteen tietokantatestejä varten olevaan TextViewiin. 
    319  
    320 Vinkki: Tyhjissä EditText kentissä selite on näppärä laittaa Hint propertyyn. 
    321  
    322 XML:stä tulee suunnilleen seuraavanlainen 
    323  
    324 {{{ 
    325 <?xml version="1.0" encoding="utf-8"?> 
    326 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    327     android:orientation="vertical" 
    328     android:layout_width="fill_parent" 
    329     android:layout_height="fill_parent" 
    330     > 
    331     <EditText android:layout_width="fill_parent" android:layout_height="wrap_content"  
    332  
    333 android:hint="Hinta" android:id="@+id/hinta"></EditText> 
    334     <EditText android:layout_width="fill_parent" android:layout_height="wrap_content"  
    335  
    336 android:hint="Litroja" android:id="@+id/litroja"></EditText> 
    337     <EditText android:layout_width="fill_parent" android:layout_height="wrap_content"  
    338  
    339 android:hint="Kilometrejä" android:id="@+id/kilometreja"></EditText> 
    340     <Button android:layout_width="fill_parent" android:layout_height="wrap_content"  
    341  
    342 android:id="@+id/laske" android:text="Laske"></Button> 
    343     <TextView android:layout_width="fill_parent" android:layout_height="wrap_content"  
    344  
    345 android:id="@+id/kulutus" android:text="-----"></TextView> 
    346     <Button android:layout_width="fill_parent" android:layout_height="wrap_content"  
    347  
    348 android:id="@+id/tallenna" android:text="Tallenna"></Button> 
    349     <TextView android:layout_width="fill_parent" android:layout_height="fill_parent"  
    350  
    351 android:id="@+id/testikentta" android:text="---------"></TextView> 
    352 </LinearLayout> 
    353 }}} 
    354  
    355 [Image(bensalaskuri2.png)]] 
    356  
    357 Layouttia tehdessä kannattaa myös EditTexteihin lisätä Properties kohdasta rajoitus, 
    358 joka estää kirjainten syöttämisen kenttiin. Tätä ei esimerkkitapauksessa ole tehty, 
    359 rajoituksen voi lisätä parametrillä android:inputType="numberDecimal". 
    360  
    361 === 3.3 Pääohjelman aloitus === 
    362 Lähdetään muokkailemaan BensaLaskuri.javaa  
    363  
    364 Ensin täytyy esitellä käytettävät komponentit ja ja yhdistää 
    365 ne toimivaksi kokonaisuudeksi. 
    366  
    367  
    368 {{{ 
    369 public class BensaLaskuri extends Activity { 
    370     //Esitellään tarvittava määrä vekottimia 
    371     Button laske, tallenna; 
    372     TextView textViewKulutus; 
    373     EditText editTextHinta; 
    374     EditText editTextMaara; 
    375     EditText editTextKilometreja; 
    376     TextView output;  
    377     Consumption c; //Kulutusolio 
    378  
    379   @Override 
    380     public void onCreate(Bundle savedInstanceState) { 
    381         super.onCreate(savedInstanceState); 
    382         setContentView(R.layout.main); 
    383          
    384         laske = (Button)findViewById(R.id.laske); 
    385         tallenna = (Button)findViewById(R.id.tallenna); 
    386         textViewKulutus = (TextView)findViewById(R.id.kulutus); 
    387         editTextHinta = (EditText)findViewById(R.id.hinta); 
    388         editTextMaara = (EditText)findViewById(R.id.litroja); 
    389         editTextKilometreja = (EditText)findViewById(R.id.kilometreja);     
    390         tallenna.setEnabled(false); 
    391          
    392         output = (TextView) findViewById(R.id.testikentta); 
    393 } 
    394  
    395 }}} 
    396  
    397 === 3.4 Kulutusolio === 
    398 Lähdetään luomaan kulutusoliota, jota käytetään tiedon säilyttäjänä 
    399 ja keskikulutuksen laskijana. Tätä varten tehdään Consumption.java 
    400  
    401 Kulutusoliolla on muutama tarpeellinen ominaisuus, sen tulee pystyä 
    402 1. tallentamaan hintatieto 
    403 2. tallentamaan litramäärä 
    404 3. tallentamaan ajettu matka 
    405 4. tallentamaan ja laskemaan keskikulutus 
    406  
    407 Tämän jälkeen koodi näyttää tältä: 
    408  
    409 {{{ 
    410  public class Consumption { 
    411         private float price; 
    412         private float amount; 
    413         private float distance; 
    414         private float consumption; 
    415  
    416        public float getConsumption() { 
    417             calculateConsumption(); 
    418             return this.consumption; 
    419         } 
    420  
    421  
    422      private void calculateConsumption() { 
    423             this.consumption = this.amount/(this.distance/100); 
    424             
    425              
    426         } 
    427 } 
    428 }}} 
    429 + get ja set metodit muille. Periaatteessa get-metodia ei tarvitse 
    430 kuin kulutukselle. Syy miksi getConsumption kutsuu calculateConsumption -metodia 
    431 on se, että tällä varmistetaan että keskikulutus on aina laskettu olemassaolevilla 
    432 arvoilla. Jos ohjelman EditText kenttiin on määritelty sallituiksi merkeiksi vain 
    433 numerot, ei ongelmia pitäisi tulla. (XML Atribuutti android:inputType="numberDecimal") 
    434  
    435 === 3.5 Kenttien tarkistukset === 
    436 Palataan takaisin BensaLaskuri.javaan. 
    437  
    438 Ohjelman pitäisi pystyä siis Laske -nappia klikkaamalla hakemaan tiedot tekstikentistä, 
    439 luomaan Consumption olio ja laittamaan olion laskemat tiedot tekstikenttiin. Ennen näiden 
    440 toimintojen mahdollistamista, tulee kuitenkin huolehtia siitä, ettei käyttäjä 
    441 erehdy klikkailemaan Laske namiskaa tyhjillä arvoilla.  
    442  
    443 Tätä varten tehdään kenttien tarkastusmetodi: 
    444  
    445  
    446 {{{ 
    447     private boolean validifyFields() { 
    448         if (editTextHinta.getText().length()<1) { 
    449             Toast.makeText(getBaseContext(), " Invalid input: Price",  
    450  
    451 Toast.LENGTH_SHORT).show();   
    452             return false; 
    453         } 
    454         if (editTextMaara.getText().length()<1) { 
    455             Toast.makeText(getBaseContext(), " Invalid input: Amount",  
    456  
    457 Toast.LENGTH_SHORT).show(); 
    458             return false; 
    459         } 
    460         if (editTextKilometreja.getText().length()<1) { 
    461             Toast.makeText(getBaseContext(), " Invalid input: Distance",  
    462  
    463 Toast.LENGTH_SHORT).show(); 
    464             return false; 
    465         }  
    466 return true; 
    467     } 
    468 }}} 
    469  
    470  
    471 Tämän jälkeen luodaan metodi tiedon parsimiseen: 
    472  
    473  
    474 {{{ 
    475     private void parseValues(Consumption c) { 
    476          
    477         try { 
    478 //Parsitaan arvot 
    479             Float price = Float.parseFloat(editTextHinta.getText().toString()); 
    480             Float amount = Float.parseFloat(editTextMaara.getText().toString()); 
    481             Float distance = Float.parseFloat(editTextKilometreja.getText().toString()); 
    482 //Asetetaan arvot kulutusoliolle 
    483             c.setPrice(price); 
    484             c.setAmount(amount); 
    485             c.setDistance(distance); 
    486  
    487             } catch (NumberFormatException e) { 
    488                 textViewKulutus.setText("Ei ole numero");  //Ei pitäisi olla mahdollinen, jos  
    489  
    490 rajoite annettu XML puolella. 
    491             } 
    492          
    493     } 
    494  
    495 }}} 
    496  
    497 Ja yksinkertainen metodi tiedon tulostamiseen oikeassa muodossa 
    498  
    499  
    500 {{{ 
    501    private void printValues(Consumption c) { 
    502 //Haetaan kulutus 
    503         double consumption = c.getConsumption();   
    504 //Muotoillaan               
    505         DecimalFormat df = new DecimalFormat("#.##");    
    506 //Ja laitetaan kenttään     
    507         textViewKulutus.setText(df.format(consumption).toString() + " l/100km"); 
    508          
    509     } 
    510 }}} 
    511  
    512 === 3.6 Kuuntelijat === 
    513  
    514 Nyt päästään tekemään itse toiminnallisuutta, joka onkin helppo toteuttaa. 
    515 Luodaan laske napille kuuntelija: 
    516  
    517  
    518 {{{ 
    519         laske.setOnClickListener(new View.OnClickListener() { 
    520             @Override 
    521             public void onClick(View v) {           
    522                 if (validifyFields() == true) { //Jos kaikissa kentissä on tieto       
    523                 c = new Consumption(); //Uusi kulutus 
    524                 parseValues(c); //Haetaan arvot 
    525                 printValues(c); //Laitetaan arvot kenttiin 
    526                 tallenna.setEnabled(true); //Tallenna nappi mahdolliseksi 
    527   
    528                 } 
    529         } 
    530     }); 
    531 }}} 
    532  
    533  
    534 Tämän jälkeen ohjelman pitäisi osata laskea kulutus ja pistää se näkyville tekstikenttään. 
    535 Seuraavaksi työskentelemään tietokannan pariin. Kannattaa testata :-) 
    536  
    537 === 3.7 DbAdapter === 
    538  
    539 Tietokantatyöskentelyä helpottamaan on suotavaa tehdä DbAdapter.java. 
    540 Yksinkertaisin tapa tehdä DbAdapter luokka tällaiselle yksinkertaiselle projektille 
    541 on käyttää GitHubista löytyvää Python skriptiä. [https://github.com/fedepaol/Android-sql-lite-helper] 
    542  
    543 Skriptin käyttäminen on helppoa: 
    544   - 1. Varmista että sinulla on Python asennettuna koneellesi. Jos ei ole, hae Python osoitteesta www.python.org ja asenna se ohjeiden mukaan. 
    545   - 2. Lataa ja pura Python skripti koneellesi 
    546   - 3. Avaa notepad tai jokin muu tekstiohjelma, ja luo uusi tiedosto db.txt 
    547   - 4. Kirjoita alla oleva tiedostoon ja tallenna se samaan hakemistoon Python skriptin kanssa. 
    548  
    549 CLASS Event 
    550 Date Time        
    551 Float Price 
    552 Float Amount 
    553 Float Distance 
    554 Float consumption 
    555 ENDCLASS 
    556  
    557 6. Avaa komentotulkki (Windowsissa Command Prompt, Linuxmiehet osaavat tämän jokatapauksessa) 
    558 7. aja Python skripti komennolla: 
    559 pythin sql_lite_helper.py -i db.txt -n DbAdapter -p fi.jyu.mit.android.bensalaskuri 
    560 8. Etsi syntynyt DbAdapter.java ja kopioi se projektiisi. 
    561  
    562 Tämän jälkeen sinulla pitäisi näkyä DbAdapter.java samassa hakemistossa 
    563 kuin BensaLaskuri.java ja Consumption.java ovat. 
    564  
    565 Voit tutkia DbAdapterin toimintaa, ja muokata esimerkiksi tietokannan nimeä jne. Tämä ei 
    566 ole kuitenkaan pakollista toiminnan kannalta. Python skriptin pahin rajoite koskee tietotyyppejä, 
    567 sillä se tukee ainoastaan String, Float, Long ja Date -tyyppejä. 
    568  
    569 === 3.8 Tietokantatoiminnallisuuden lisääminen === 
    570  
    571 Seuraavaksi tehdään metodi, joka lukee kaikki tietokantamerkinnät  
    572  
    573   
    574 {{{ 
    575    /** 
    576      * Reads all DB entries into ArrayList 
    577      * @return Results ArrayList<String> 
    578      */ 
    579     protected ArrayList<String> readAllDbEntries() { 
    580         ArrayList<String> results = new ArrayList<String>(); 
    581         Cursor cu = db.getAllEvent(); 
    582 //Määritellään aloituskohdat, voi toteuttaa nätimminkin 
    583         int timeColumn = cu.getColumnIndex("Time"); 
    584         int priceColumn = cu.getColumnIndex("Price"); 
    585         int amountColumn = cu.getColumnIndex("Amount"); 
    586         int distanceColumn = cu.getColumnIndex("Distance"); 
    587         int consumptionColumn = cu.getColumnIndex("consumption"); 
    588          
    589        //cu.moveToFirst palauttaa false jos palautunut Cursor 
    590 //olio on tyhjä. Siirtää myös osoituksen ensimmäiseen merkintään. 
    591             if (cu.moveToFirst() == true) { 
    592                 int i = 0; 
    593                 do { 
    594                     i++; 
    595 //Haetaan tiedot 
    596                     String time = cu.getString(timeColumn); 
    597                     Float price = cu.getFloat(priceColumn); 
    598                     Float amount = cu.getFloat(amountColumn); 
    599                     Float distance = cu.getFloat(distanceColumn); 
    600                     Float consumption = cu.getFloat(consumptionColumn); 
    601 //Lisätään merkkijonona ArrayListiin. Ratkaisu on ns. quick and dirty 
    602 //mutta helpoin. 
    603                     results.add("" + i + ": "+  
    604                             time + " " +  
    605                             price  + " " +  
    606                             amount + " " + 
    607                             distance  + " " + 
    608                             consumption 
    609                             ); 
    610                 } while (i<cu.getCount()); 
    611                  
    612              
    613         } 
    614             return results;  
    615          
    616     } 
    617 }}} 
    618  
    619  
    620 Tämän jälkeen lisätään tallenna nappiin kuuntelija: 
    621  
    622  
    623 {{{ 
    624             tallenna.setOnClickListener(new View.OnClickListener() { 
    625                  
    626                 @Override 
    627                 public void onClick(View v) { 
    628                     GregorianCalendar cal = new GregorianCalendar(); 
    629                     //Lisää tapahtuman tietokantaan 
    630                     db.addEvent(cal.getTime(), new Float(c.getPrice()), new Float(c.getAmount 
    631  
    632 ()) 
    633                     , new Float(c.getDistance()), new Float(c.getConsumption())); 
    634 //Asettaa napin pois käytöstä ettei vahingossa naputella useita tapahtumia. 
    635                     tallenna.setEnabled(false); 
    636                     
    637                      
    638                 } 
    639  
    640             }); 
    641  
    642 }}} 
    643  
    644 Tämän jälkeen huomaat, että eclipse herjaa ettei db nimistä härveliä ole esitelty. 
    645 Esittele DbAdapter db; luokan alussa.  
    646  
    647 === 3.9 Tietokantayhteyden avaaminen/sulkeminen ja testidatan tulostus === 
    648  
    649 Tietokantayhteys täytyy avata ennen kuin sitä voidaan käyttää. Mene BensaLaskurin 
    650 onCreate metodiin, ja kirjoita seuraavat rivit entisten jatkeeksi: 
    651   
    652 {{{ 
    653   db = new DbAdapter(this); 
    654         db.open(); 
    655 }}} 
    656  
    657  
    658 Tietokantayhteys tulee myös sulkea. Avaamisen ja sulkemisen voi tehdä 
    659 jokaisen luku/kirjoituskerran yhteydessä, tai kerran ohjelman avautuessa ja sulkeutuessa. 
    660 Tässä esimerkissä yhteys avataan ohjelman käynnistyessä ja suljetaan sen sammutuksen yhteydessä. 
    661 Sammutusta varten lisää tiedoston loppuun  
    662  
    663   
    664 {{{ 
    665   @Override 
    666     public void onDestroy() { 
    667       db.close(); 
    668     } 
    669  
    670 }}} 
    671  
    672 '''Tietokantatietojen tulostus output ruutuun''' 
    673 Lisää printValues -metodin viimeiseksi riviksi 
    674  
    675        
    676 {{{ 
    677   output.setText(readAllDbEntries().toString()); 
    678 }}} 
    679  
    680  
    681 Ja nyt jokaisen laskennan yhteydessä alalaitaan ilmestyy aikaisemmat rivit. 
    682 Tulostus on ruma, mutta testikäyttöön riittävä. 
     294== Bensalaskuri - Tiedon tallentaminen tietokantaan Androidissa == 
     295BensaLaskuri 
     296 
    683297 
    684298{{{