android tutorijal deo i

12
SPPuRV, Android Tutorijal, Deo I, Str. 1/12 Android Tutorijal Ovo je kratki tutorijal o OS Android, koji se zasniva na knjizi „Android Developer’s Cookbook: Building Applications with the Android SDK“, autora James Steele i Nelson To. U tutorijalu su uključne sledećih pet tema (koje su podeljene u dva dela): 1. Osnovne aplikacije: aktivnosti i namere (deo I) 2. Niti, usluge, prijemnici i alarmi (deo I) 3. Događaji korisničke sprege (deo II) 4. Sprega sa uređajima (deo II) 5. Naprednije tehnike (deo II) 1. Osnovne aplikacije: aktivnosti i namere U ovom odeljku je ukratko obrađeno sledećih pet recepata: 1. Izrada projekta i pokretanje aktivnosti (projekat SimpleActivity) 2. Korišćenje drugih funkcija životnog ciklusa aktivnosti (projekat ActivityLifecycle) 3. Pokretanje druge aktivnosti iz koda za obradu događaja (projekat MenuScreen) 4. Korišćenje implicitnih namera za pokretanje aktivnosti (projekat ListActivityExample) 5. Prosleđivanje primitivnih tipova podataka između aktivnosti (projekat StartScreen) 1.1 Recept: Izrada projekta i pokretanje aktivnosti Ovaj recept ilustruje postupak pravljenja projekta sa jednom aktivnošću, koja ispisuje jednostavnu pozdravnu poruku. Klasa SimpleActivity Ova klasa jednostavno proširuje osnovnu klasu Activity. Metoda onCreate ove klase najpre poziva konstruktor super klase Activity a zatim postavlja sadržaj pogleda pozivajući metodi setContentView(): public class SimpleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } Vrednost parametra koja se prosleđuje metodi je R.layout.main, a ta vrednost odgovara pogledu, koji je definisan u datoteci main.xml: <?xml version="1.0" encoding="utf-8"?>

Upload: loren

Post on 21-Dec-2015

18 views

Category:

Documents


2 download

DESCRIPTION

Android Tutorijal Deo I

TRANSCRIPT

SPPuRV, Android Tutorijal, Deo I, Str. 1/12

Android Tutorijal Ovo je kratki tutorijal o OS Android, koji se zasniva na knjizi „Android Developer’s Cookbook: Building Applications with the Android SDK“, autora James Steele i Nelson To. U tutorijalu su uključne sledećih pet tema (koje su podeljene u dva dela):

1. Osnovne aplikacije: aktivnosti i namere (deo I) 2. Niti, usluge, prijemnici i alarmi (deo I) 3. Događaji korisničke sprege (deo II) 4. Sprega sa uređajima (deo II) 5. Naprednije tehnike (deo II)

1. Osnovne aplikacije: aktivnosti i namere U ovom odeljku je ukratko obrađeno sledećih pet recepata:

1. Izrada projekta i pokretanje aktivnosti (projekat SimpleActivity) 2. Korišćenje drugih funkcija životnog ciklusa aktivnosti (projekat

ActivityLifecycle) 3. Pokretanje druge aktivnosti iz koda za obradu događaja (projekat MenuScreen) 4. Korišćenje implicitnih namera za pokretanje aktivnosti (projekat

ListActivityExample) 5. Prosleđivanje primitivnih tipova podataka između aktivnosti (projekat

StartScreen) 1.1 Recept: Izrada projekta i pokretanje aktivnosti Ovaj recept ilustruje postupak pravljenja projekta sa jednom aktivnošću, koja ispisuje jednostavnu pozdravnu poruku. Klasa SimpleActivity Ova klasa jednostavno proširuje osnovnu klasu Activity. Metoda onCreate ove klase najpre poziva konstruktor super klase Activity a zatim postavlja sadržaj pogleda pozivajući metodi setContentView(): public class SimpleActivity extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } } Vrednost parametra koja se prosleđuje metodi je R.layout.main, a ta vrednost odgovara pogledu, koji je definisan u datoteci main.xml: <?xml version="1.0" encoding="utf-8"?>

SPPuRV, Android Tutorijal, Deo I, Str. 2/12

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <TextView android:layout_width="fill_parent" android:layout_height="wrap_content" android:text="@string/hello" /> </LinearLayout> Unutar tog pogleda, u linearnom rasporedu (eng. Linear layout), nalazi se jedan tekstualni pogled (eng. text view), a u njemu tekst, koga čini string hello. String hello je definisan u datoteci strings.xml: <?xml version="1.0" encoding="utf-8"?> <resources> <string name="hello">Hello World, SimpleActivity!</string> <string name="app_name">SimpleActivity</string> </resources> Iz gornje xml datoteke se vidi da je vrednost stringa hello „Hello World, SimpleActivity!“, i to je upravo pozdravna poruka, koju ispisuje aktivnost u ovom primeru. 1.2 Recept: Korišćenje drugih funkcija životnog ciklusa aktivnosti Ovaj recept ilustruje korišćenje svih funkcija životnog veka aktivnosti:

Životni vek aktivnosti

SPPuRV, Android Tutorijal, Deo I, Str. 3/12

Klasa Lifecycle Ova klasa proširuje klasu Activity i redefiniše sve funkcije životnog veka tako da ispišu svoje ime koristeći metodu makeText klase Toast: public class ActivityLifecycle extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Toast.makeText(this, "onCreate", Toast.LENGTH_SHORT).show(); } @Override protected void onStart() { super.onStart(); Toast.makeText(this, "onStart", Toast.LENGTH_SHORT).show(); } ... 1.3 Recept: Pokretanje druge aktivnosti iz koda za obradu događaja Ovaj recept ilustruje pokretanje nove aktivnosti iz koda za obradu događaja, konkretno u prisluškivaču (eng. listener) događaja pritiska (klik) tastera mišu. Klasa MenuScreen Ova klasa definiše prisluškivača događaja pritiska tastera miša na dugmetu (button) startButton (kom odgovara identifikacija R.id.play_game). Tom dugmetu je pridružen tekst „Play Game?“. Kad se taj događaj desi, OS poziva funkciju onClick prisluškivača, a ova dalje poziva funkciju startGame: public class MenuScreen extends Activity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //setup button listener Button startButton = (Button) findViewById(R.id.play_game); startButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { startGame(); } }); } Funkcija startGame najpre stvara nameru launchGame za pokretanje klase PlayGame, a zatim pokreće aktivnost sa tom namerom (koja izvršava klasu PlayGame):

SPPuRV, Android Tutorijal, Deo I, Str. 4/12

private void startGame() { Intent launchGame = new Intent(this, PlayGame.class); startActivity(launchGame); } Klasa PlayGame Ova klasa izigrava igru koja se pokreće na klik miša. Ona definiše dugme startGame, ali ovaj put to dugme ima pridružen tekst „Done?“. Nakon klika na ovo dugme, aktivnost se završava pozivom funkcije finish: public class PlayGame extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.game); //setup button listener Button startButton = (Button) findViewById(R.id.end_game); startButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view) { finish(); } }); } } 1.4 Recept: Korišćenje implicitnih namera za pokretanje aktivnosti Klasa ListActivityExample Ova klasa proširuje klasu ListActivity. Njena metoda onCreate najpre postavlja adapter liste, koja nudi spisak mogućih izbora, zatim obavlja potrebna podešavanja, i na kraju definiše prisluškivača događa izbora neke od stavki iz ponuđene liste: protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, ACTIVITY_CHOICES)); getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); getListView().setTextFilterEnabled(true); getListView().setOnItemClickListener(new OnItemClickListener() { Nakon što korisnik izabere stavku iz ponuđene liste, prisluškivač tog događa ga obrađuje tako što formira implicitne namere i pokreće odgovarajuće aktivnosti: public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { switch(arg2) { case 0: //opens web browser to given website

SPPuRV, Android Tutorijal, Deo I, Str. 5/12

startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("http://www.android.com/"))); break; case 1: //opens contacts app. to browse all contacts startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("content://contacts/people/"))); break; 1.5 Recept: Prosleđivanje primitivnih tipova podataka između aktivnosti Ovaj recept ilustruje prenos primitivnih tipova podataka između aktivnosti. Klasa StartScreen Ova klasa definiše dugme startButton i prisluškivač klika na njemu. Kad dođe do klika, prisluškivač poziva funkciju startGame, u kojoj najpre stvara nameru za pokretanje druge aktivnosti, a zatim postavlja parametre u nameri, koje treba proslediti drugoj aktivnosti, pomoću funkcije putExtra. Na kraju pokreće drugu aktivnost sa očekivanjem povratnog rezultata, pomoću funkcije startActivityForResult: private void startGame() { Intent launchGame = new Intent(this, PlayGame.class); //passing information to launched activity launchGame.putExtra("meaningOfLife", meaningOfLife); launchGame.putExtra("userName", userName); startActivityForResult(launchGame, PLAY_GAME); } Po prijemu rezultata, funkcija onActivityResult vadi rezultate i ispisuje ih: protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == PLAY_GAME && resultCode == RESULT_OK) { meaningOfLife = data.getExtras().getInt("returnInt"); //userName = data.getExtras().getString("userName"); userName = data.getExtras().getString("returnStr"); //show it has changed tv.setText(userName + ":" + meaningOfLife); } super.onActivityResult(requestCode, resultCode, data); } Klasa PlayGame Ova klasa imitira igru. U metodi onCreate preuzima parametre koji su joj prosleđeni, a zatim menja vrednosti tih parametra i definiše svoje dugme i njegovog prisluškivača: answer = i.getIntExtra("meaningOfLife", -1); //returns [] if not initialized by calling activity author = i.getStringExtra("userName");

SPPuRV, Android Tutorijal, Deo I, Str. 6/12

tv2.setText(author + ":" + answer); //change values for an example of return answer = answer - 41; author = author + " Jr."; Nakon klika na to dugme, poziva se metoda onClick, koja vraća modifikovane parametre: public void onClick(View view) { //return information to calling activity Intent i = getIntent(); i.putExtra("returnInt", answer); i.putExtra("returnStr", author); setResult(RESULT_OK, i); finish(); } } 2. Niti, usluge, prijemnici i alarmi U ovom odeljku je ukratko obrađeno sledećih sedam recepata:

1. Pokretanje sekundarne niti (ilustruje rad sa nitima; projekat LaunchThread) 2. Periodično raspoređivanje zadatka tipa Runnable iz glavne niti (ilustruje razmenu

poruka između niti; projekat BackgroundTimer) 3. Korišćenje vremenske kontrole za odbrojavanje naniže do nule (ilustruje razmenu

poruka između niti; Projekat CountdownTimer) 4. Obrada dugotrajnog inicijalizovanja (ilustruje razmenu poruka između niti;

Projekat HandleMessage) 5. Pravljenje samostalne usluge (ilustruje usluge; projekat SimpleService) 6. Pokretanje usluge pritiskom dugmeta za kameru (ilustruje korišćenje prijemnika

poruka poslatih svima; projekat SimpleBroadcastReceiver) 7. Prikazivanje obaveštenja na šipki stanja (ilustruje alarme; projekat

ShowNotification) 2.1 Recept: Pokretanje sekundarne niti U ovom receptu, nakon pritiska na dugme, glavna nit pokreće drugu (sekundarnu) nit, koja zatim reprodukuje zvuk zvonjave telefona. Klasa PressAndPlay Ova klasa definiše prisluškivača događaja pritiska tastera miša na dugmetu startButton (kom odgovara identifikacija R.id.trigger). Tom dugmetu je pridružen tekst „Press me“. Kad se taj događaj desi, OS poziva funkciju onClick prisluškivača, a ova dalje stvara objekat tipa Runnable, redefiniše njegovu metodu run tako da ona pozove metodu play_music, pravi nit initBkgdThread i pokreće je pozivom metode start nad njom: Thread initBkgdThread = new Thread(new Runnable() { public void run() {

SPPuRV, Android Tutorijal, Deo I, Str. 7/12

play_music(); } }); initBkgdThread.start(); Pod uslovom da glavna nit nije pauzirana (kada Bulova promenljiva paused ima vrednost false), metoda play_music tri puta, u petlji, reprodukuje četiri note definisane u nizu notes, svaku notu po 400 ms. U cilju reprodukcije note, metoda play_music stvara objekat tipa MediaPlayer, pokreće njegovo izvršenje pozivajući metodu start nad njime, i na kraju se suspenduje na 400 ms pozivajući metodu sleep klase Thread: private void play_music() { for(int ii=0; ii<12; ii++) { //check to ensure main activity not paused if(!paused) { if(m_mediaPlayer != null) {m_mediaPlayer.release();} m_mediaPlayer = MediaPlayer.create(this, notes[ii%4]); m_mediaPlayer.start(); try { Thread.sleep(NOTE_DURATION); } catch (InterruptedException e) { e.printStackTrace(); } } } } Note su definisane u jeziku RTTL (Ringtone Text Transfer Language). Četiri note su definisane u četiri zasebne datoteke u direktorijumu res/raw/. 2.2 Recept: Periodično raspoređivanje zadatka tipa Runnable iz glavne niti Ovaj recept ilustruje korišćenje vremenske kontrole (eng. timer) radi periodičnog raspoređivanja zadatka. Klasa BackgroundTimer Za komunikaciju, tj. razmenu poruka, između glavne niti i vremenske kontrole stvara se instanca rukovaoca porukama: private Handler mHandler = new Handler(); Funkcija onClick inicijalno (kada je vrednost mStartTime 0) očitava početno vreme u ms pozivajući funkciju uptimeMillis klase SystemClock, uklanja sve povratne pozive za zadatak mUpdateTimeTask pozivajući funkciju removeCallbacks rukovaoca mHandler, i na kraju šalje signal, sa kašnjenjem od 100 ms, zadatku mUpdateTimeTask pozivajući funkciju postDelayed rukovaoca mHandler: if (mStartTime == 0L) { mStartTime = SystemClock.uptimeMillis(); mHandler.removeCallbacks(mUpdateTimeTask);

SPPuRV, Android Tutorijal, Deo I, Str. 8/12

mHandler.postDelayed(mUpdateTimeTask, 100); } Iza toga, funkcija onClick definiše prisluškivača dugmeta, u kom na svaki pritisak miša ispisuje tekst, koji sadrži ukupan broj pritisaka miša. To radi glavna nit aktivnosti. Periodično raspoređivan zadatak, u svojoj funkciji run, izračuna vreme koje je proteklo od pokretanja aktivnosti, ispisuje ga na labeli mTimeLabel i raspoređuje se sa kašnjenjem od 200 ms: private Runnable mUpdateTimeTask = new Runnable() { public void run() { final long start = mStartTime; long millis = SystemClock.uptimeMillis() - start; int seconds = (int) (millis / 1000); int minutes = seconds / 60; seconds = seconds % 60; mTimeLabel.setText("" + minutes + ":" + String.format("%02d",seconds)); mHandler.postDelayed(this, 200); } }; 2.3 Recept: Korišćenje vremenske kontrole za odbrojavanje naniže do nule Ovaj recept ilustruje korišćenje vremenske kontrole (eng. timer) za odbrojavanje datog vremenskog intervala sa zadatim korakom. Pri svakom otkucaju vremenske kontrole vrednost datog intervala se umanjuje za dati korak, sve dok ne padne na nulu. Klasa CountDownTimerExample Ova klasa konstruiše instancu ugrađene klase CountDownTimer tako što konstruktoru ove klase prosledi vrednosti vremenskog intervala i koraka, u ms. Prilikom konstruisanja te instance redefiniše se funkcija onTick, tako da prikaže proteklo vreme (dakle vrlo slična funkcionalnost kao u prethodnom primeru, ali jednostavnije realizovana): new CountDownTimer(30000, 1000) { public void onTick(long millisUntilFinished) { mTimeLabel.setText("seconds remaining: " + millisUntilFinished / 1000); } public void onFinish() { mTimeLabel.setText("done!"); } }.start(); 2.4 Recept: Obrada dugotrajnog inicijalizovanja Ovaj recept ilustruje postupak koji se koristi kada inicijalizacija aplikacije dugo traje. Uobičajeno je da se najpre prikaže neko obaveštenje, npr. tekst „Loading...“, zatim se pokrene sekundarna nit koja obavi inicijalizaciju i nakon toga pošalje poruku glavnoj niti da je završila.

SPPuRV, Android Tutorijal, Deo I, Str. 9/12

Klasa HandleMessage U funkciji onCreate stvara i pokreće sekundarnu nit, koja u funkciji run najpre poziva funkciju initializeArrays za dugotrajnu inicijalizaciju, a zatim šalje praznu poruku glavnoj niti, koja označava da je inicijalizacija gotova: public void run(){ initializeArrays(); mHandler.sendEmptyMessage(0); } Tu poruku prima rukovalac poruka mHandler tako što OS pozove njegovu funkciju handleMessage, u kojoj se postavlja glavni pogled sa pozdravnom porukom: private Handler mHandler = new Handler() { public void handleMessage(Message msg) { setContentView(R.layout.main); } }; 2.5 Recept: Pravljenje samostalne usluge Ovaj recept ilustruje način pravljenja usluge. Usluga je komponenta koja radi u pozadini bez interakcije sa korisnikom, a pokreće je i zaustavlja bilo koja druga komponenta, a i sama usluga može sebe zaustaviti. Dok radi, sa uslugom se može povezati svaka druga komponenta. Životni vek usluge je prikazan na sledećoj slici (levo je prikazan slučaj kad se usluga pokreće funkcijom startService, a desno kada se pokreće funkcijom bindService):

Životni vek usluge

SPPuRV, Android Tutorijal, Deo I, Str. 10/12

Koraci za izradu samostalne usluge:

1. Definisati klasu koja proširuje ugrađenu klasu Service, npr. SimpleService 2. Deklarisati uslugu u datoteci AndroidManifest.xml, npr. <service

android:name=“.myService“></service> 3. Redefinisati funkcije onCreate i onDistroy u cilju odgovarajućeg pokretanja i

zaustavljanja usluge 4. Redefinisati funkciju onBind radi povezivanja sa komponentom, koja želi da se

poveže sa uslugom 5. Aktiviranje usluge pomoću nekog spoljašnjeg okidača, pošto usluga ne može

sama sebe da pokrene U primeru koji sledi klasa SimpleService predstavlja samostalnu uslugu, dok klasa SimpleActivity formira korisničku spregu sa dva dugmeta – jedno služi za pokretanje usluge, a drugo za njeno zaustavljanje. Klasa SimpleService Funkcija onBind jeste redefinisana, ali se efektivno ne koristi. Funkcija onCreate najpre ispisuje obaveštenje da je usluga pokrenuta, a zatim pokreće sekundarnu nit, koja reprodukuje zvuk zvonjave telefona, kao u receptu Pokretanje sekundarne niti: public void onCreate() { super.onCreate(); Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show(); paused = false; Thread initBkgdThread = new Thread(new Runnable() { public void run() { play_music(); } }); initBkgdThread.start(); } Funkcija onDestroy ispisuje obaveštenje da je usluga uništena i postavlja indikator paused da bi prestala reprodukcija zvuka: public void onDestroy() { super.onDestroy(); Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show(); paused = true; } Klasa SimpleActivity Funkcija onCreate najpre formira korisničku spregu. Zatim pronalazi dugme startButton i dodaje mu prisluškivača, čiju funkciju onClick redefiniše tako da

SPPuRV, Android Tutorijal, Deo I, Str. 11/12

pokrene uslugu pozivajući funkciju startService. Na kraju pronalazi dugme stopButton i dodaje mu prisluškivača, čiju funkciju onClick redefiniše tako da zaustavi uslugu pozivajući funkciju stopService: Button startButton = (Button) findViewById(R.id.Button01); startButton.setOnClickListener(new View.OnClickListener() { public void onClick(View view){ startService(new Intent(SimpleActivity.this, SimpleService.class)); } }); Button stopButton = (Button)findViewById(R.id.Button02); stopButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v){ stopService(new Intent(SimpleActivity.this,SimpleService.class)); } }); 2.6 Recept: Pokretanje usluge pritiskom dugmeta za kameru Ovaj recept ilustruje pokretanje usluge na osnovu događaja prijema poruke poslate svima (eng. broadcast), koja se na primer dobija kada korisnik pritisne dugme kamere. U primeru koji ilustruje ovaj recept koriste se tri klase:

- SimpleActivity, koja instancira i registruje prijemnik poruka poslatih svima - SimpleBroadcastReceiver, koja prima poruku pritiska dugmeta kamere i

pokreće uslugu tipa SimpleService2 - SimpleService2, to je usluga koju pokreće prijemnik poruka poslatih svima

Napomena: ukoliko dugme kamere nije aktivno na emulatoru, primer se može preraditi da koristi neki drugi događaj, npr. događaj „airplane mode changed“. Klasa SimpleActivity Za potrebe prijema poruke poslate svima stvara se odgovarajući prijemnik: SimpleBroadcastReceiver intentReceiver = new SimpleBroadcastReceiver(); U funkciji onClick se najpre definiše potreban filtar namere, a zatim se registruje prijemnik poruke pozivanjem funkcije registerReceiver: IntentFilter intentFilter = new IntentFilter(Intent.ACTION_CAMERA_BUTTON); intentFilter.addAction(Intent.ACTION_PACKAGE_ADDED); registerReceiver(intentReceiver, intentFilter); U funkciji onDestroy se odjavljuje prijemnik poruka pozivom funkcije unregisterReceiver.

SPPuRV, Android Tutorijal, Deo I, Str. 12/12

Klasa SimpleBroadcastReceiver U funkciji onReceive se najpre pribavlja akcija pozivanjem funkcije getAction primljene namere rcvIntent, zatim se proverava da li je u pitanju akcija pritiska dugmeta kamere, i ako jeste, pokreće se usluga tipa SimpleService2 pozivanjem funkcije startService nad primljenim kontekstom: public void onReceive(Context rcvContext, Intent rcvIntent) { String action = rcvIntent.getAction(); if (action.equals(Intent.ACTION_CAMERA_BUTTON)) { rcvContext.startService(new Intent(rcvContext, SimpleService2.class)); } Klasa SimpleService2 U funkciji onCreate se ispisuje obaveštenje da je usluga pokrenuta: public void onCreate() { super.onCreate(); Toast.makeText(this,"Service created ...", Toast.LENGTH_LONG).show(); } U funkciji onDestroy se na sličan način ispisuje obaveštenje da je usluga zaustavljena. Funkcija onBind jeste redefinisana, ali se ne koristi. 2.7 Recept: Prikazivanje obaveštenja na šipki stanja Ovaj recept ilustruje način prikazivanja obaveštenja na šipki stanja uređaja. Klasa ShowNotification Najpre se deklariše instanca rukovaoca obaveštenjima i ID obaveštenja: private NotificationManager mNManager; private static final int NOTIFY_ID=1100; U funkciji onCreate se najpre pribavlja rukovalac i definiše se obaveštenje: String ns = Context.NOTIFICATION_SERVICE; mNManager = (NotificationManager) getSystemService(ns); final Notification msg = new Notification(R.drawable.icon, "New event of importance", System.currentTimeMillis()); Zatim se pribavljaju dugmad start i cancel, kojima se pridružuju odgovarajući prisluškivači. U funkciji prisluškivača dugmeta start se formira i prikazuje obaveštenje, dok se u funkciji prisluškivača dugmeta cancel to obaveštenje otkazuje.