Slide 1

Slide 1 text

Android School Warsztat 06 Adam Jodłowski

Slide 2

Slide 2 text

2 Service ● usługi pracują w tle, mają możliwości takie jak aktywności, ale nie posiadają interfejsu użytkownika, działanie usług odbywa się w wątku UI ● mogą być lokalne dla naszej aplikacji lub zdalne, udostępniając interfejs w formie RPC (za pomocą AIDL) ● metoda kontekstu startService() działa analogicznie do startActivity() – identyfikuje usługę i dostarcza jej parametrów do wykonania startService(new Intent(context, BackgroundService.class)); ● usługa odbierze intencję w metodzie onStartCommand(), która zwraca wartość kluczową dla jej cyklu życia (START_STICKY, START_REDELIVER_INTENT, START_NOT_STICKY) ● możemy zatrzymać usługę jawnie przez analogiczne wywołanie stopSelf() w jej własnym kodzie lub z komponentu wywołującego stopService(new Intent(context, BackgroundService.class)); ● klient może wysyłać pojedyńcze komunikaty do usługi lub podłączyć się do niej na stałe (bind)

Slide 3

Slide 3 text

3 Przykład usługi lokalnej ● deklarujemy usługę w manifeście ● implementujemy usługę public class BackgroundService extends Service { @Override public void onCreate() {...} @Override public void onDestroy() {...} @Override // reakcja na startService() public int onStartCommand(Intent intent, int flags, int startId) { super.onStartCommand(intent, flags, startId); // kod przetwarzania return START_STICKY; } @Override // reakcja na bindService() public IBinder onBind(Intent intent) { return null; } }

Slide 4

Slide 4 text

4 Tworzene usługi zdalnej, AIDL ● stworzenie zdalnej usługi wymaga 1. zdefiniowania interfejsu w pliku .aidl 2. uzyskania interfejsu Javy w wyniku kompilacji (zawiera stub) 3. implementacji w usłudze i zwrócenia interfejsu w onBind() 4. dodania konfiguracji usługi do manifestu ● metody zwracają android.os.RemoteException, powinny być thread-safe ● klient implementuje interfejs ServiceConnection z metodami zwrotnymi oraz podłącza się za pomocą bindService()

Slide 5

Slide 5 text

5 IntentService ● specjalna wersja usługi, kolejkująca intencje z zadaniami i wykonująca je w osobnym wątku* ● możemy przekazać jej obiekt Messenger do komunikacji zwrotnej z handlerem aktywności Intent intent = new Intent(context, Downloader.class); intent.setData(Uri.parse("http://nyan.cat/favicon.ico")); intent.putExtra("MESSENGER", new Messenger(handler)); startService(intent); ● public class Downloader extends IntentService { public Downloader() { super("Downloader"); } @Override protected void onHandleIntent(Intent intent) { String uri = intent.getData().toString(); ... Bundle extras = intent.getExtras(); Messenger messenger = (Messenger) extras.get("MESSENGER"); Message msg = new Message(); try { messenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } }

Slide 6

Slide 6 text

6 Przetestuj działanie usług.

Slide 7

Slide 7 text

7 Support Package/Library ● archiwum .jar z bibliotekami zapewniającymi częściową kompatybilność starszych platform z nowymi wersjami API ● należy dołączyć odpowiedni plik do projektu SDK/extras/android/support/v4/android-support- v4.jar ● do najpopularniejszych komponentów udostępnianych przez bibliotekę należy Fragment, ViewPager, Loader, ShareCompat, NotificationCompat

Slide 8

Slide 8 text

8 Fragmenty ● lekkie aktywności posiadające własny cykl życia, ściśle związane z aktywnością, której są częścią ● używane głównie do tworzenia elastycznych układów interfejsu, dostosowujących się do urządzeń z różnymi rozmiarami ekranów ● pojawiły się w wersji 3.0 Androida (API 11), deklarowane w XML sprawiają pewne kłopoty (węzeł ) ● ich różne wersje to m.in. Fragment, ListFragment, DialogFragment, PreferenceFragment, posiadają dotychczas poznane metody takie jak onCreate(), onPause(), onResume() itd.

Slide 9

Slide 9 text

9 Główny układ widoków ● niech aktywność zawiera dwa pionowe fragmenty rozłożone poziomo ● layout głównego okna umieszczamy w /res/layout-land/main.xml

Slide 10

Slide 10 text

10 Klasa fragmentu ● rozszerzamy klasę Fragment i oprócz standardowych metod aktywności, obowiązkowo implementujemy metodę onCreateView() public class Fragment1 extends Fragment { TextView tv = null; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle b) { View view = inflater.inflate(R.layout.fragment1, container, false); tv = (TextView) view.findViewById(R.id.textView_fragment1); tv.setText("to jest 1 fragment"); ((Button) view.findViewById(R.id.button_fragment1)).setOnClickListener(new OnClickListener() {...}); return view; } }

Slide 11

Slide 11 text

11 FragmentManager, komunikacja fragmentów ● FragmentManager* zarządza fragmentami i dba o transakcje z ich udziałem (dodaje, usuwa, podmienia) oraz przechowuje stos wywołań – BackStack ● aktywność może dynamicznie dodawać fragmenty do swojego layoutu FragmentManager fragMgr = getSupportFragmentManager(); FragmentTransaction trans = fragMgr.beginTransaction(); if (null == fragMgr.findFragmentByTag(FRAGMENT_1_TAG)) { trans.add(R.id.fragment1, new Fragment1(), FRAGMENT_1_TAG); } trans.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); trans.addToBackStack(null); trans.commit(); ● fragmenty otrzymują referencję do aktywności, której są częścią przez metodę getActivity() ● mogą pozyskiwać referencje do innych fragmentów dzięki getFragmentManager().findFragmentByTag(FRAGMENT_TAG); ● aktywność może zaimplementować interfejs komunikacji zwrotnej dostarczony przez fragment zamiast definiować metody pomocnicze

Slide 12

Slide 12 text

12 Adaptatywny interfejs ● tworzymy layout poziomy z dwoma fragmentami ● obsługujemy je z aktywności w sposób tradycyjny ● layout pionowy zawiera tylko pierwszy fragment ● uruchamiając drugi fragment sprawdzamy, czy mamy gdzie go umieścić – jeśli nie, odpalamy osobną aktywność prezentującą tę część interfejsu ● logika fragmentów jest już zaimplementowana, wystarczy stworzyć dodatkowe aktywności i dostosować orientacje layoutów ● PROFIT

Slide 13

Slide 13 text

13 Stwórz aktywność z fragmentami, wyświetlaj je i ukrywaj na skutek określonego zdarzenia.

Slide 14

Slide 14 text

14 Canvas ● dostęp do płótna otrzymujemy implementując własny obiekt widoku i umieszczając go w layoucie public class CustomView extends View { public CustomView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onDraw(Canvas canvas) { int w = this.getWidth(); int h = this.getHeight(); canvas.drawColor(Color.WHITE); Paint paint = new Paint(); // new Paint(Paint.ANTI_ALIAS_FLAG); paint.setColor(Color.BLACK); paint.setStyle(Paint.Style.STROKE); canvas.drawRect(w/2 - w/4, h/2 - h/8, w/2 + w/4, h/2 + h/8, paint); paint = new Paint(); paint.setColor(Color.RED); paint.setStyle(Paint.Style.FILL); canvas.drawRect(w/2 - w/4, h/2, w/2 + w/4, h/2 + h/8, paint); } }

Slide 15

Slide 15 text

15 Praca z płótnem ● nakładanie elementów graficznych Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.pic); canvas.drawBitmap(bitmap, 10, 10, null); ● inne przydatne metody paint.setFlags(Paint.UNDERLINE_TEXT_FLAG); paint.setTextSize(16); canvas.drawText("Tekst", 20, 20, paint); Bitmap.createScaledBitmap(pic, 30, 40, false); ● przekształcenia względem płótna canvas.save(); canvas.rotate(45, 85, 85); canvas.drawBitmap(bitmap, 100, 100, null); canvas.restore(); ● pozostałe dostępne przekształcenia to translate, scale, skew, concat, clipRect, clipPath

Slide 16

Slide 16 text

16 Transformacje macierzowe ● omówione transformacje możemy przeprowadzać wprost za pomocą macierzy Matrix mirrorMatrix = new Matrix(); mirrorMatrix.preScale(-1, 1); Bitmap mirrorBmp = Bitmap.createBitmap(pic, 0, 0, pic.getWidth(), pic.getHeight(), mirrorMatrix, false); Matrix rotateMatrix = new Matrix(); rotateMatrix.preRotate(90); ● pomagajmy zwolnić niepotrzebną pamięć po bitmapach bitmap.recycle();

Slide 17

Slide 17 text

17 Gradienty ● gradient to nic innego jak styl pędzla Paint gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); LinearGradient grad = new LinearGradient(0, 0, 25, 25, Color.RED, Color.BLACK, Shader.TileMode.MIRROR); RadialGradient grad = new RadialGradient(250, 175, 50, Color.GREEN, Color.BLACK, Shader.TileMode.MIRROR); SweepGradient grad = new SweepGradient(canvas.getWidth() - 175, canvas.getHeight() - 175, new int[] { Color.RED, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA }, null); gradientPaint.setShader(grad);

Slide 18

Slide 18 text

18 Kształty ● kształty możemy tworzyć deklaratywnie w XML lub programowo ShapeDrawable sd = new ShapeDrawable(new RoundRectShape(new float[] { 5, 5, 5, 5, 5, 5, 5, 5 }, null, null)); sd.setIntrinsicHeight(80); sd.setIntrinsicWidth(80); sd.getPaint().setColor(Color.LTGRAY); ● podobnie możemy rysować owale i ścieżki, kształty możemy wyświetlać wprost na komponencie ImageView imageView.setImageDrawable(myShapeDrawable); ● definicja elementu w formie XML w celu użycia ich np. jako tła komponentów interfejsu użytkownika, pozwala na określanie właściwości corners, gradient, padding, size, solid, stroke

Slide 19

Slide 19 text

19 Przetestuj możliwości związane z grafiką.

Slide 20

Slide 20 text

20 Niestandardowe czcionki ● przykład zastosowania niestandardowej czcionki z zasobów TextView tv = (TextView) findViewById(R.id.text); Typeface tf = Typeface.createFromAsset(getAssets(), "fonts/learningcurve_ot.otf"); tv.setTypeface(tf); ● niestety nie ma łatwego sposobu na ustawienie czcionki w deklaracji XML*

Slide 21

Slide 21 text

21 State list ● listy stanów pozwalają na podmianę grafik w zależności od stanu widoku, mają postać drawable w pliku XML

Slide 22

Slide 22 text

22 Style i tematy/motywy ● definiujemy je w dowolnym pliku o postaci XML w /res/values <item name="android:layout_width">fill_parent</item> <item name="android:layout_height">wrap_content</item> <item name="android:textColor">#00FF00</item> <item name="android:typeface">monospace</item> ● stosujemy je do elementów wizualnych ● podobnie aplikujemy motywy graficzne dla całych aplikacji lub aktywności . . .

Slide 23

Slide 23 text

23 Przetestuj stosowanie własnych czcionek, list stanów i styli.

Slide 24

Slide 24 text

24 Zadanie domowe: Narysuj kilka znaków drogowych za pomocą płótna.