Koodin virheiden jäljitys Androidilla

LogCat

Koosta riippumatta koodissa syntyy helposti virheitä ja näiden etsiminen voi olla välillä hankalaa. Java kuitenkin antaa hyvät virheilmoitukset siitä, mikä virheen aiheutti ja millä koodirivillä virhe tapahtuu. Nämä virheet näkee Eclipsessä helposti DDMS-näkymässä LogCat:llä. Voit myös lisätä koodiisi log-merkintöjä.

Vedä suosiolla LogCat aloitusasemastaan Eclipsen alareunasta isoksi, jotta voit paremmin lukea logia. Vasemmalla näkee tietokoneessa kiinni olevat puhelimet ja niissä käynnissä olevat ohjelmat, mikäli puhelin on asetettu debug-tilaan. Vihreällä plus merkillä voi lisätä filttereitä, jotka erottavat puhelimen logista tietyn ohjelman log-tiedot.

Virhelogi esimerkiksi null pointterin sattuessa näkyy samalla tavalla, kuin Javassa komentorivillä. Virheilmoitukset ovat selkeitä ja erottuvat hyvin ilman filtteröntiäkin. Vaikka virheilmoitus antaa pitkän stack tracen löytyvät omat luokat helposti eriävän pakettinimen avulla.
Jos ohjelmistosi kaatuu tulisi LogCatin olla ensimmäinen paikka, mihin mennä.

Debugger

Toinen kätevä työkalu koodin toiminnan seuraamiseen on Androidin Debugger, missä koodin suoritusta pääsee seuraamaan rivikohtaisesti. Projektin voi käynnistää puhelimella tai emulaattorissa “Run as” sijaan “Debug as Android application”. Tämä ei kuitenkaan yksin riitä, vaan ohjelmaan tulee asettaa break pointteja, joissa koodin suorittaminen pysähtyy ja voit edetä koodissa rivi kerrallaan.

Breakpointit saa asetettua koodi näkymässä rivinumeroiden vasemmalla puolella olevaan pieneen tyhjään tilaan joko tuplaklikaamalla tai hiiren oikealla painikkeella ja valitsemalla “Toggle Breakpoint”


Tämän jälkeen ohjelmaa ajettaessa koodin suoritus pysähtyy tälle riville ja Debug-näkymä Eclipsessä aukeaa. Tässä näkymässä näkee kätevästi muuttujien sen hetkiset arvot ja F6-näppäimellä voi edetä koodia rivi kerrallaan. Mikäli suorituksessa haluaa mennä johonkin metodiin sisälle tulee tämän metodin kohdalla painaa “Step into” eli F5-näppäintä. Debug-näkymän oikean ylälaidan ikkunasta löytyvät myös napit koodissa etenemiseen. Breakpointteja pystyy lisäämään ja poistamaan suoritusaikana ja tämä antaa mukavan vapauden katsoa suoritettavan koodin eri kohtia. Tämä auttaa esimerkiksi väärien arvojen syntymisen jäljittämisessä.

UIPickerView UIScrollView:n sisällä

UIPickerView inside UIScorllViewApple tarjoaa kattavan dokumentaation iOS-kehitykseen, mutta osa käytettävistä keinoista on kuitenkin jätetty jostain syystä liian pienelle huomiolle. Yksi esimerkki on heikommasta dokumentoinnista on tilanne, jossa UIScrollView-komponentin sisällä on UIPickerView-komponentti, tälläisessä tapauksessa UIScrollView nappaa kaikki kosketukset, eikä näin ollen UIPickerView ole käytettävissä.

Ratkaisu ongelman on varsin yksinkertainen, tai olisi, jos se kerrottaisiin dokumentaatiossa.

Jotta saat UIPickerView:n toimimaan kuten normaalisti, on sinun luotavat oma kustomoitu versio UIScrollView:stä, joka toteuttaa metodin touchesShouldCancelInContentView.

CustomScrollView.h

#import 
@interface CustomScrollView : UIScrollView {
}
@end

CustomScrollView.m

#import "CustomScrollView.h"
@implementation CustomScrollView
- (BOOL)touchesShouldCancelInContentView:(UIView *)view{
//cancels touches to any UIPickerView
//UIPickerView has class description UIPickerTable
if ([[[view class] description] isEqualToString:@"UIPickerTable"]){
return NO;
}
return YES;
}
@end

Tämän lisäksi on CustomScorllView:tä käyttävässä luokassa asettava CustomScrollView:lle seuraavat ominaisuudet ja näille arvot.

CustomScrollView.canCancelContentTouches = YES;
CustomScrollView.delaysContentTouches = NO;

Sopiva paikka ominaisuuksien asettamisille on esimerkiksi CustomScrollView:ta käyttävän luokan ViewDidLoad-metodissa.

Omat layout elementit Androidissa

Android tarjoaa runsaan valikoiman erillaisia graafisia elementtejä. Usein tulee kuitenkin vastaan tilanne, jossa näiden valmiiden elementtien toiminnallisuus ei riitä. Java ja Android antavat kuitenkin tehokkaan ja hyvän tavan toteuttaa omia layout luokkia. Graafiset elementit periytyvät aina View tai ViewGroup luokista. Helpoin tapa aloittaa omien näkymien tekemisen on tekemällä yläluokka jo olemassa olevasta layout elementistä, jonka toiminnallisuus on mahdollisimman lähellä haluttua.

Oman näkymäluokan tekeminen antaa tarkan kontrolliin elementin ulkonäköön ja toiminnallisuuteen. Näkymäluokkia on myös mahdollisuus yhdistää ja näin sitoa useiden elementtien välinen toiminnallisuus yhteen. Esimerkiksi listan aktiivihakuun voi yhdistää tekstikentän ja listan samaan elementtin, näin ei aktiivihaun koodia tarvitse tuoda aktiviteetin muun toiminnallisuuden kanssa samaan paikkaan. Useita elementtejä yhdisteltäessä helpoin tapa on määritellä elementit erillisessä xml:ssä ja käyttää LayoutInflateriä luomaan näkymä.

Tässä esimerkissä luodaan aktiivihaun toiminnallisuus oman graafisen elementin sisään. Elementti sisältää EditText kentän ja ListViewn:



haku.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent">
     <EditText
          android:id="@+id/search_field"
          android:layout_height="wrap_content"
          android:layout_width="fill_parent"
          />
     <ListView
     android:id="@+id/search_list"
     android:layout_width="fill_parent"
     android:layout_height="fill_parent"
     />
</LinearLayout>

Aktiivihaku.java:

...
public class Aktiivihaku extends ViewGroup {

View view;

/**
* Luontimetodi aktiivihaku näkymälle. Luo näkymän haku.xml perusteella.
*
* @param context Näkymän yhteys ohjelman yleiseen informaatioon
* @param attrs xml:ssä määritellyt atribuutit
*/
public Aktiivihaku(Context context, AttributeSet attrs) {
super(context, attrs);

LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.haku, this);

list = (ListView) view.findViewById(R.id.search_list);
sortField = (EditText) view.findViewById(R.id.search_field);

adapter = new ListAdapter(getContext(), 0, 0, COUNTRIES);
list.setAdapter(adapter);

sortField.addTextChangedListener(new TextWatcher() {

@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}

@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}

@Override
public void afterTextChanged(Editable s) {
     adapter.getFilter().filter(sortField.getText());
}
});

}

...

Yleisin käyttö omille näkymä luokille on yhden tai muutaman toiminnallisuuden muuttaminen, tämä onnistuu korvaamalla (override) olemassaolevan metodin samannimisellä metodilla, näin voi helposti esimerkiksi poistaa

Hyvä ohjelmointityyli Androidilla on myös pitää aktiviteettiluokan koodi mahdollisimman yksinkertaisena, eikä rasittaa sitä esimerkiksi omien kuuntelijoiden tekemisellä aktiviteettiluokassa ja antamalla niitä xml:ssä määritellyille elementeille.

Itse tehdyn layout elementin voi xml:ssä viitata paketin kokonimellä ja komponentin nimellä. Esimerkiksi fi.androidkehitys.aktiivihaku paketissa olevaan Aktiivihaku.java luokkaan viitataan XML:ssä seuraavasti:

<fi.androidkehitys.aktiivihaku.Aktiivihaku
      android:layout_width="fill_parent"
      android:layout_height="wrap_content"
      />