Muni android-18-5-2012

Post on 03-Jul-2015

234 views 5 download

transcript

Android 2Ondra Zahradník

MUNI - 18.5.2012

Tuesday, March 19, 13

Agenda

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula2.BroadcastReceiver

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula2.BroadcastReceiver3.Podpora různých zařízení

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula2.BroadcastReceiver3.Podpora různých zařízení4.Dynamické UI pomocí fragmentů

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula2.BroadcastReceiver3.Podpora různých zařízení4.Dynamické UI pomocí fragmentů5.Přestávka

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula2.BroadcastReceiver3.Podpora různých zařízení4.Dynamické UI pomocí fragmentů5.Přestávka6.Architektura typické aplikace

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

Agenda

1.Rekapitulace z minula2.BroadcastReceiver3.Podpora různých zařízení4.Dynamické UI pomocí fragmentů5.Přestávka6.Architektura typické aplikace7.Otázky a odpovědi

Tuesday, March 19, 13

nejdrive trochu teorie, potom prakticky prikladprvni dva priklady se tykaji UI, druhe dva pak programovanibehem prikladu budu obchazet a pomahat

House-keeping notes

•slajdy - http://goo.gl/QiFDy

•zdroje - http://goo.gl/QH5J7

•vaše otázky

Tuesday, March 19, 13

Rekapitulace z minula

1.Android SDK2.Eclipse + ADT3.Emulátor / device4.Založení nového projektu5.Struktura Android projektu6.Activity, layout, Intent = UI7.Kompilace a spuštění8.Debugging

Tuesday, March 19, 13

Broadcasty

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

•BroadcastReceiver

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

•BroadcastReceiver<receiver android:name=".SMSReceiver">

<intent-filter > <action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter></receiver>

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

•BroadcastReceiver<receiver android:name=".SMSReceiver">

<intent-filter > <action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter></receiver>

public class SMSReceiver extends BroadcastReceiver { @Override public void onReceive(Context ctx, Intent i) { //TODO do something }}

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

•BroadcastReceiver

•Možno definovat vlastní

<receiver android:name=".SMSReceiver"><intent-filter > <action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter></receiver> public class SMSReceiver extends BroadcastReceiver {

@Override public void onReceive(Context ctx, Intent i) { //TODO do something }}

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

•BroadcastReceiver

•Možno definovat vlastní

•globální

<receiver android:name=".SMSReceiver"><intent-filter > <action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter></receiver> public class SMSReceiver extends BroadcastReceiver {

@Override public void onReceive(Context ctx, Intent i) { //TODO do something }}

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Broadcasty

•Aplikace reaguje na důležité události

•Boot, SMS, Call, připojení, čas...

•BroadcastReceiver

•Možno definovat vlastní

•globální•lokální - notifikační systém uvnitř appky,

levné

<receiver android:name=".SMSReceiver"><intent-filter > <action android:name="android.provider.Telephony.SMS_RECEIVED" />

</intent-filter></receiver> public class SMSReceiver extends BroadcastReceiver {

@Override public void onReceive(Context ctx, Intent i) { //TODO do something }}

Tuesday, March 19, 13

aplikaci to i probudívykonat rychlou akci (limit 10s)mozno broadcasty radit i stopnout

Příklad

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

•Toast - http://goo.gl/WoTk

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

•Toast - http://goo.gl/WoTk•Oprávnění android.permission.RECEIVE_SMS

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

•Toast - http://goo.gl/WoTk•Oprávnění android.permission.RECEIVE_SMS•SMS Intent - extra “pdus” seznam smsek

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

•Toast - http://goo.gl/WoTk•Oprávnění android.permission.RECEIVE_SMS•SMS Intent - extra “pdus” seznam smsek•SmsMessage.createFromPdu

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

•Toast - http://goo.gl/WoTk•Oprávnění android.permission.RECEIVE_SMS•SMS Intent - extra “pdus” seznam smsek•SmsMessage.createFromPdu

•SMS lze posílat z DDMS do emulátoru

Tuesday, March 19, 13

Příklad

•Vypište číslo a text příchozí sms v toastu

•Toast - http://goo.gl/WoTk•Oprávnění android.permission.RECEIVE_SMS•SMS Intent - extra “pdus” seznam smsek•SmsMessage.createFromPdu

•SMS lze posílat z DDMS do emulátoru

•zdrojáky - muni-android-hello

Tuesday, March 19, 13

Různá zařízení

Tuesday, March 19, 13

Různá zařízení

•deklarativně podadresáři v /res

Tuesday, March 19, 13

Různá zařízení

•deklarativně podadresáři v /res

•defaultní a alternativní

Tuesday, March 19, 13

Různá zařízení

•deklarativně podadresáři v /res

•defaultní a alternativní

dvě zařízeníjeden layout

Tuesday, March 19, 13

Různá zařízení

•deklarativně podadresáři v /res

•defaultní a alternativní

dvě zařízeníjeden layout

jedno zařízenídva layouty

Tuesday, March 19, 13

Zdroje a kvalifikátory

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

•Kvalifikátory• jazyk (en_rUS, cs, ...)

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

•Kvalifikátory• jazyk (en_rUS, cs, ...)

• nejmenší šířka (sw720dp)

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

•Kvalifikátory• jazyk (en_rUS, cs, ...)

• nejmenší šířka (sw720dp)

• velikost obrazovky (small, normal, large, xlarge)

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

•Kvalifikátory• jazyk (en_rUS, cs, ...)

• nejmenší šířka (sw720dp)

• velikost obrazovky (small, normal, large, xlarge)

• orientace (land, port)

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

•Kvalifikátory• jazyk (en_rUS, cs, ...)

• nejmenší šířka (sw720dp)

• velikost obrazovky (small, normal, large, xlarge)

• orientace (land, port)

• hustota (ldpi, mdpi, hdpi, xhdpi)

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

Tuesday, March 19, 13

Zdroje a kvalifikátory

•Zdroje

•texty, obrázky, layout, barvy,...

•Kvalifikátory• jazyk (en_rUS, cs, ...)

• nejmenší šířka (sw720dp)

• velikost obrazovky (small, normal, large, xlarge)

• orientace (land, port)

• hustota (ldpi, mdpi, hdpi, xhdpi)

• layout, layout-land, layout-land-v13

• drawable, drawable-hdpi, drawable-xhdpi

MyProject/ src/ MyActivity.java res/ drawable/ icon.png layout/ main.xml info.xml values/ strings.xml

res/ drawable/ icon.png background.png drawable-hdpi/ icon.png background.png

Tuesday, March 19, 13

Resource resolving

Tuesday, March 19, 13

Resource resolving

Tuesday, March 19, 13

Resource resolving

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Tuesday, March 19, 13

Resource resolving

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Locale = en-GB Screen orientation = port Screen pixel density = hdpi Touchscreen type = notouch Primary text input method = 12key

Tuesday, March 19, 13

Resource resolving

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Locale = en-GB Screen orientation = port Screen pixel density = hdpi Touchscreen type = notouch Primary text input method = 12key

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Tuesday, March 19, 13

Resource resolving

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Locale = en-GB Screen orientation = port Screen pixel density = hdpi Touchscreen type = notouch Primary text input method = 12key

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

drawable/drawable-en/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Tuesday, March 19, 13

Resource resolving

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

Locale = en-GB Screen orientation = port Screen pixel density = hdpi Touchscreen type = notouch Primary text input method = 12key

drawable/drawable-en/drawable-fr-rCA/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

drawable/drawable-en/drawable-en-port/drawable-en-notouch-12key/drawable-port-ldpi/drawable-port-notouch-12key/

drawable-en/drawable-en-port/drawable-en-notouch-12key/

Tuesday, March 19, 13

Různé obrazovky

Tuesday, March 19, 13

•obrazovky small, normal, large, xlarge

Různé obrazovky

Tuesday, March 19, 13

•obrazovky small, normal, large, xlarge

•wrap_content, match_parent •RelativeLayout

Různé obrazovky

Tuesday, March 19, 13

•obrazovky small, normal, large, xlarge

•wrap_content, match_parent •RelativeLayout•9-patch

Různé obrazovky

Tuesday, March 19, 13

•obrazovky small, normal, large, xlarge

•wrap_content, match_parent •RelativeLayout•9-patch

Různé obrazovky

Tuesday, March 19, 13

•obrazovky small, normal, large, xlarge

•wrap_content, match_parent •RelativeLayout•9-patch

Různé obrazovky

Tuesday, March 19, 13

Různé hustoty

Tuesday, March 19, 13

•hustoty ldpi, mdpi, hdpi, xhdpi

Různé hustoty

Tuesday, March 19, 13

•hustoty ldpi, mdpi, hdpi, xhdpi

Různé hustoty

Tuesday, March 19, 13

•hustoty ldpi, mdpi, hdpi, xhdpi

Různé hustoty

• xhdpi: 2.0• hdpi: 1.5• mdpi: 1.0 (baseline)• ldpi: 0.75

Tuesday, March 19, 13

•hustoty ldpi, mdpi, hdpi, xhdpi

Různé hustoty

• xhdpi: 2.0• hdpi: 1.5• mdpi: 1.0 (baseline)• ldpi: 0.75

MyProject/ res/ drawable-xhdpi/ awesomeimage.png drawable-hdpi/ awesomeimage.png drawable-mdpi/ awesomeimage.png drawable-ldpi/ awesomeimage.png

Tuesday, March 19, 13

•hustoty ldpi, mdpi, hdpi, xhdpi

•dp = density independent pixel

Různé hustoty

• xhdpi: 2.0• hdpi: 1.5• mdpi: 1.0 (baseline)• ldpi: 0.75

MyProject/ res/ drawable-xhdpi/ awesomeimage.png drawable-hdpi/ awesomeimage.png drawable-mdpi/ awesomeimage.png drawable-ldpi/ awesomeimage.png

Tuesday, March 19, 13

Podpora různých verzí

Tuesday, March 19, 13

Podpora různých verzí

•Na trhu Android v2.1 - v4.0.3

Tuesday, March 19, 13

<manifest xmlns:android="http://schemas.android.com/apk/res/android" ... >    <uses-sdk android:minSdkVersion="4" android:targetSdkVersion="15" />    ...</manifest>

Podpora různých verzí

•Na trhu Android v2.1 - v4.0.3

•Nastavit minSdkVersion a targetSdkVersion

Tuesday, March 19, 13

Podpora různých verzí

•Na trhu Android v2.1 - v4.0.3

•Nastavit minSdkVersion a targetSdkVersion

•Kontrolovat verzi APIprivate void setUpActionBar() {    // Make sure we're running on Honeycomb or higher to use ActionBar APIs    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {        ActionBar actionBar = getActionBar();        actionBar.setDisplayHomeAsUpEnabled(true);    }}

Tuesday, March 19, 13

Příklad

•Rozšiřte příklad kalkulačky z minulé přednášky o podporu češtiny a landscape režimu

•zdrojáky, ze kterých lze vyjít

•muni-android-hello

•dokumentace

•http://goo.gl/RKihT

Tuesday, March 19, 13

Dynamické UI pomocí fragmentů

•Fragment je kus funkčního UI

•Aktivita hostí fragmenty

•Jedna aplikace pro telefon i tablet

Tuesday, March 19, 13

Fragment

Tuesday, March 19, 13

Fragment

Tuesday, March 19, 13

Fragment

Fragment a jeho UIpublic class ArticleFragment extends Fragment {    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,         Bundle savedInstanceState) {        // Inflate the layout for this fragment        return inflater.inflate(R.layout.article_view, container, false);    }}

Tuesday, March 19, 13

Fragment

Fragment a jeho UI

Layout

public class ArticleFragment extends Fragment {    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,         Bundle savedInstanceState) {        // Inflate the layout for this fragment        return inflater.inflate(R.layout.article_view, container, false);    }}

<fragment android:name="com.example.android.fragments.ArticleFragment"              android:id="@+id/article_fragment"              android:layout_weight="2"              android:layout_width="0dp"              android:layout_height="match_parent" />

Tuesday, March 19, 13

Fragment

Fragment a jeho UI

Layout

Instance

public class ArticleFragment extends Fragment {    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,         Bundle savedInstanceState) {        // Inflate the layout for this fragment        return inflater.inflate(R.layout.article_view, container, false);    }}

<fragment android:name="com.example.android.fragments.ArticleFragment"              android:id="@+id/article_fragment"              android:layout_weight="2"              android:layout_width="0dp"              android:layout_height="match_parent" />

public class MainActivity extends FragmentActivity {    @Override    public void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.news_articles);    }}

Tuesday, March 19, 13

Fragmenty na telefonu a tabletu

Tuesday, March 19, 13

Fragmenty na telefonu a tabletu

Tuesday, March 19, 13

Fragmenty na telefonu a tabletu

<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  android:orientation="horizontal"  android:layout_width="match_parent"  android:layout_height="match_parent"  android:id="@+id/frags">    <!-- "Fragment A" -->  <fragment class="com.example.android.TitlesFragment"            android:id="@+id/list_frag"            android:layout_width="@dimen/titles_size"            android:layout_height="match_parent"/>    <!-- "Fragment B" -->  <fragment class="com.example.android.DetailsFragment"            android:id="@+id/details_frag"            android:layout_width="match_parent"            android:layout_height="match_parent" /></LinearLayout>

Tuesday, March 19, 13

Fragmenty na telefonu a tabletu

<?xml version="1.0" encoding="utf-8"?><FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="match_parent"    android:layout_height="match_parent">    <!-- "Fragment A" -->    <fragment class="com.example.android.TitlesFragment"              android:id="@+id/list_frag"              android:layout_width="match_parent"              android:layout_height="match_parent"/></FrameLayout>

Tuesday, March 19, 13

Fragmenty na telefonu a tabletu

public class MainActivity extends Activity implements TitlesFragment.OnItemSelectedListener {    public void onItemSelected(int position) {        DisplayFragment displayFrag = (DisplayFragment) getFragmentManager()                                    .findFragmentById(R.id.display_frag);        if (displayFrag == null) {            // DisplayFragment (Fragment B) is not in the layout (handset layout),            // so start DisplayActivity (Activity B)            // and pass it the info about the selected item            Intent intent = new Intent(this, DisplayActivity.class);            intent.putExtra("position", position);            startActivity(intent);        } else {            // DisplayFragment (Fragment B) is in the layout (tablet layout),            // so tell the fragment to update            displayFrag.updateContent(position);        }    }}

Tuesday, March 19, 13

Komunikace mezi fragmenty

Tuesday, March 19, 13

Komunikace mezi fragmenty

Tuesday, March 19, 13

Komunikace mezi fragmenty

•FragmentA definuje Listener interface

Tuesday, March 19, 13

Komunikace mezi fragmenty

•FragmentA definuje Listener interface

•Activity interface implementuje

Tuesday, March 19, 13

Komunikace mezi fragmenty

•FragmentA definuje Listener interface

•Activity interface implementuje

•FragmentA volá callback onItemSelected(...)

Tuesday, March 19, 13

Nové API na starých Androidech

•support lib. zpřístupňuje nové api pro staré devices

•Fragment, Loader

•ViewPager, accessibility, NotificationBuilder,...

•ActionBarSherlock

•Animations

import android.support.v4.app.Fragment;import android.support.v4.app.FragmentManager;...

Tuesday, March 19, 13

Příklad

•do seznamu přidejte možnost změnit položku

•změnu potvrďte FragmentDialogem

•zdrojáky

•http://goo.gl/NmK4o

•dokumentace

•http://goo.gl/tuZwX•http://goo.gl/bK5GQ

Tuesday, March 19, 13

Přestávka

Tuesday, March 19, 13

Architektura typické aplikace 1

•Zobraz seznam položek z databáze

Tuesday, March 19, 13

Architektura typické aplikace 1

•Zobraz seznam položek z databáze

ListFragment

Tuesday, March 19, 13

Architektura typické aplikace 1

•Zobraz seznam položek z databáze

ListFragment DBčte data

Tuesday, March 19, 13

Architektura typické aplikace 1

•Zobraz seznam položek z databáze

ListFragment DBčte data

sql

Tuesday, March 19, 13

Architektura typické aplikace 1

•Zobraz seznam položek z databáze

ListFragment DBčte data

sql

UI

Tuesday, March 19, 13

Architektura typické aplikace 1

•Zobraz seznam položek z databáze

ListFragment DBčte data

sql

UI Model

Tuesday, March 19, 13

Databáze

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze•callbacky pro vytvoření a upgrade

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze•callbacky pro vytvoření a upgrade

• onCreate() a onUpgrade()

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze•callbacky pro vytvoření a upgrade

• onCreate() a onUpgrade()•zpřístupňuje interface databáze

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze•callbacky pro vytvoření a upgrade

• onCreate() a onUpgrade()•zpřístupňuje interface databáze• getWritableDatabase()

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze•callbacky pro vytvoření a upgrade

• onCreate() a onUpgrade()•zpřístupňuje interface databáze• getWritableDatabase()

• db.query(), db.insert (), db.update (), db.delete ()

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Databáze

•SQLite v3 databáze

•SQLiteOpenHelper

•stará se o life-cycle databáze•callbacky pro vytvoření a upgrade

• onCreate() a onUpgrade()•zpřístupňuje interface databáze• getWritableDatabase()

• db.query(), db.insert (), db.update (), db.delete ()

• db.beginTransaction(), db.setTransactionSuccessful(), db.endTransaction()

Tuesday, March 19, 13

nefunguji cizí klíčecasto implementovan jako singleton

Cursor

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb• moveToFirst(), moveToNext(), getCount()

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb• moveToFirst(), moveToNext(), getCount()

•metody pro čtení

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb• moveToFirst(), moveToNext(), getCount()

•metody pro čtení• getColumnIndex(String columnName)

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb• moveToFirst(), moveToNext(), getCount()

•metody pro čtení• getColumnIndex(String columnName)

• getString(int columnIndex), ...

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb• moveToFirst(), moveToNext(), getCount()

•metody pro čtení• getColumnIndex(String columnName)

• getString(int columnIndex), ...

• db.query(table, columns, selection, selectionArgs,........)

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Cursor

•zpřístupňuje řádky výsledku db.query()

•metody pro pohyb• moveToFirst(), moveToNext(), getCount()

•metody pro čtení• getColumnIndex(String columnName)

• getString(int columnIndex), ...

• db.query(table, columns, selection, selectionArgs,........)

• SimpleCursorAdapter, CursorAdapter

Tuesday, March 19, 13

optimalizovane dotazy do databaze

Příklad

1.prozkoumejte DatabaseHelper2.v MainFragment zobrazte seznam knizek v DB

1.hint: použijte Cursor a SimpleCursorAdapter

•zdrojáky

•muni-android-1

•dokumentace

•http://goo.gl/eme2a

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data uri

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

DBčte data

uri

sql

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

DBčte data

uri

sql

UI

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

DBčte data

uri

sql

UI

Model

Tuesday, March 19, 13

Architektura typické aplikace 2

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

DBčte data

uri

sql

UI

Model

Boilerplate

Tuesday, March 19, 13

ContentProvider

Tuesday, March 19, 13

ContentProvider

•Jednotné API pro přístup k modelu

Tuesday, March 19, 13

ContentProvider

•Jednotné API pro přístup k modelu

•Zapouzdřuje CRUD operace nad databází

Tuesday, March 19, 13

ContentProvider

•Jednotné API pro přístup k modelu

•Zapouzdřuje CRUD operace nad databází

•REST-like api a systém URI

Tuesday, March 19, 13

ContentProvider

•Jednotné API pro přístup k modelu

•Zapouzdřuje CRUD operace nad databází

•REST-like api a systém URI

•Řeší synchronizaci

Tuesday, March 19, 13

ContentProvider

•Jednotné API pro přístup k modelu

•Zapouzdřuje CRUD operace nad databází

•REST-like api a systém URI

•Řeší synchronizaci

•Poskytuje data jiným aplikacím

Tuesday, March 19, 13

Příklad

1.prozkoumejte komunikaci provideru a databáze

2.v Provider naimplementujte query operaci3.v MainFragment načtěte data přes provider

•zdrojáky

•muni-android-2

•dokumentace

•http://goo.gl/EFKK7

Tuesday, March 19, 13

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

CursorLoader

načítání dat

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

CursorLoader

načítání dat callbacky

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat

DBčte data

callbacky

uri

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat

DBčte data

callbacky

uri

sql

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat

DBčte data

callbacky

uri

sql

UI

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat

DBčte data

callbacky

uri

sql

UI

Model

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 3

•Zobraz seznam položek z databáze

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat

DBčte data

callbacky

uri

sql

UI

Model

Boilerplate

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Asynchroní operace

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu•Application not responding aka. ANR

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu•Application not responding aka. ANR•UI žije jenom chvíli

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu•Application not responding aka. ANR•UI žije jenom chvíli

•Vše, co může dlouho trvat, mimo ui thread

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu•Application not responding aka. ANR•UI žije jenom chvíli

•Vše, co může dlouho trvat, mimo ui thread•síťová komunikace

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu•Application not responding aka. ANR•UI žije jenom chvíli

•Vše, co může dlouho trvat, mimo ui thread•síťová komunikace•čtení z databáze

Tuesday, March 19, 13

Asynchroní operace

•Omezený programovací model•slabý procesor•multi-tasking•aktualizace UI pouze v ui threadu•Application not responding aka. ANR•UI žije jenom chvíli

•Vše, co může dlouho trvat, mimo ui thread•síťová komunikace•čtení z databáze•čtení z filesystému

Tuesday, March 19, 13

CursorLoader

Tuesday, March 19, 13

CursorLoader

•Čte z ContentProvideru na pozadí

Tuesday, March 19, 13

CursorLoader

•Čte z ContentProvideru na pozadí

•Activity/Fragment notifikováno callbackem• onCreateLoader()

• onLoadFinished()

• onLoadReset()

Tuesday, March 19, 13

CursorLoader

•Čte z ContentProvideru na pozadí

•Activity/Fragment notifikováno callbackem• onCreateLoader()

• onLoadFinished()

• onLoadReset()

•Umí reusovat jednou nahraný Cursor

Tuesday, March 19, 13

CursorLoader

•Čte z ContentProvideru na pozadí

•Activity/Fragment notifikováno callbackem• onCreateLoader()

• onLoadFinished()

• onLoadReset()

•Umí reusovat jednou nahraný Cursor

•Obnoví Cursor při updatu modelu

Tuesday, March 19, 13

CursorLoader

•Čte z ContentProvideru na pozadí

•Activity/Fragment notifikováno callbackem• onCreateLoader()

• onLoadFinished()

• onLoadReset()

•Umí reusovat jednou nahraný Cursor

•Obnoví Cursor při updatu modelu

•Je třeba volat v onActivityCreated() jako getActivity().getSupportLoaderManager().initLoader()

Tuesday, March 19, 13

Příklad

1.nahraďte volání provideru CursorLoaderem1.hint: fragment nechť implementuje

LoaderManager.LoaderCallbacks

2.hint: použijte getActivity().getContentResolver()

•zdrojáky

•muni-android-3

•dokumentace

•http://goo.gl/BBb2N

Tuesday, March 19, 13

Architektura typické aplikace 4

•Aktualizace z internetu

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

UI

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

UI

Model

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

UI

ModelČtení

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

IntentServiceIntent

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

provede síťování

sql, CVzapisuje

IntentServiceIntent

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 4

•Aktualizace z internetu

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

provede síťování

sql, CVzapisuje

IntentServiceIntent

Aktualizace

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

IntentService

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

IntentService

•Implementuje frontu tasků za zpracovaní

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

IntentService

•Implementuje frontu tasků za zpracovaní• onHandleIntent(Intent i)

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

IntentService

•Implementuje frontu tasků za zpracovaní• onHandleIntent(Intent i)

•Impl. pomocí HandlerThread a Handler

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

IntentService

•Implementuje frontu tasků za zpracovaní• onHandleIntent(Intent i)

•Impl. pomocí HandlerThread a Handler

•Třeba definovat v manifestu

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

IntentService

•Implementuje frontu tasků za zpracovaní• onHandleIntent(Intent i)

•Impl. pomocí HandlerThread a Handler

•Třeba definovat v manifestu

•Volání přes Context.startService()

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

IntentService

•Implementuje frontu tasků za zpracovaní• onHandleIntent(Intent i)

•Impl. pomocí HandlerThread a Handler

•Třeba definovat v manifestu

•Volání přes Context.startService()final Intent i = new Intent(getActivity(), MyService.class);getActivity().startService(i);

Tuesday, March 19, 13

parametry mozno predat bundlemkonci, pokud neni co zpracovavat,

Síťování

Tuesday, March 19, 13

Síťování

•Http Client, UrlConnection

Tuesday, March 19, 13

Síťování

•Http Client, UrlConnection try { final URL url = new URL("http://...."); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); if (connection.getResponseCode() == 200) { final InputStream is = connection.getInputStream(); try { //TODO networking } finally { is.close(); } } } catch (IOException e) { // TODO: handle exception }

Tuesday, March 19, 13

Síťování

•Http Client, UrlConnection try { final URL url = new URL("http://...."); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); if (connection.getResponseCode() == 200) { final InputStream is = connection.getInputStream(); try { //TODO networking } finally { is.close(); } } } catch (IOException e) { // TODO: handle exception }

Tuesday, March 19, 13

Síťování

•Http Client, UrlConnection

•Oprávnění

•android.permission.INTERNET

try { final URL url = new URL("http://...."); final HttpURLConnection connection = (HttpURLConnection) url.openConnection(); if (connection.getResponseCode() == 200) { final InputStream is = connection.getInputStream(); try { //TODO networking } finally { is.close(); } } } catch (IOException e) { // TODO: handle exception }

Tuesday, March 19, 13

Parsování a db insert

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

•XML

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

•XML

•android.util.XML

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

•XML

•android.util.XML•android.sax.RootElement

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

•XML

•android.util.XML•android.sax.RootElement

•ContentValues

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

•XML

•android.util.XML•android.sax.RootElement

•ContentValues• db.insert()

Tuesday, March 19, 13

Parsování a db insert

•JSON - JSONObject, JSONArray• getString(), getInt(), getDouble()

•XML

•android.util.XML•android.sax.RootElement

•ContentValues• db.insert()

• getContentResolver.notify(Uri,...)

Tuesday, March 19, 13

Příklad

1.Přes RefreshService aktualizujte tabulku Books

2.http://dl.dropbox.com/u/5296640/books.json

•zdrojáky

•muni-android-4

•dokumentace

•http://goo.gl/3EeeTuesday, March 19, 13

Architektura typické aplikace 5

•Operace create, update, delete

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

UI

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

UI

Model

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

UI

ModelČtení

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

AsyncQueryHandluri,CV

čte data

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

ContentProvider

provede c, u, d uri, CV

AsyncQueryHandluri,CV

čte data

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

ContentProvider

provede c, u, d uri, CV

sql, CVzapisuje

AsyncQueryHandluri,CV

čte data

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

Architektura typické aplikace 5

•Operace create, update, delete

ListFragment

ContentProvider

poskytuje data

CursorLoader

načítání dat callbacky

uri

DBčte data

sql

ContentProvider

provede c, u, d uri, CV

sql, CVzapisuje

AsyncQueryHandluri,CV

čte data

Zápis

Tuesday, March 19, 13

můžeme vyřešit update modeluaktivita je hloupe ui

AsyncQueryHandler

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

•Zpětně notifikuje volajícího

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

•Zpětně notifikuje volajícího

•Problém - volající nemusí již existovat

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

•Zpětně notifikuje volajícího

•Problém - volající nemusí již existovat

•Řešení

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

•Zpětně notifikuje volajícího

•Problém - volající nemusí již existovat

•Řešení•Implementovat jako inner-static nebo top-

level

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

•Zpětně notifikuje volajícího

•Problém - volající nemusí již existovat

•Řešení•Implementovat jako inner-static nebo top-

level•WeakReference pro odkaz na volajícího

Tuesday, March 19, 13

AsyncQueryHandler

•Volá crud operace v threadu na pozadí

•Zpětně notifikuje volajícího

•Problém - volající nemusí již existovat

•Řešení•Implementovat jako inner-static nebo top-

level•WeakReference pro odkaz na volajícíhoprivate class MyQueryHandler extends AsyncQueryHandler {

// Use weak reference to avoid memoey leakprivate WeakReference<MyActivity> mMyActivity;public MyQueryHandler(Context context) {

super(context.getContentResolver()); mMyActivity = new WeakReference<MyActivity>((MyActivity) context); }

protected void onQueryComplete(int token, Object cookie, Cursor cursor) { MyActivity activity = mMyActivity.get();

if (activity != null && !activity.isFinishing()) {...

}}

Tuesday, March 19, 13

Příklad

1.Doplňte c, u, d operace do provideru a fragmentu

•zdrojáky

•muni-android-5

•dokumentace

•http://goo.gl/BS1hr

Tuesday, March 19, 13

Děkuji@ondraz

ukázky kódu a obrázky pocházejí z http://developer.android.com pod licencemi Apache v2.0 a Creative Commons Attribution v2.5

Tuesday, March 19, 13