$30 off During Our Annual Pro Sale. View Details »

Android School 06

Android School 06

Adam Jodłowski

April 22, 2013
Tweet

More Decks by Adam Jodłowski

Other Decks in Programming

Transcript

  1. Android School
    Warsztat 06
    Adam Jodłowski

    View Slide

  2. 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)

    View Slide

  3. 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;
    }
    }

    View Slide

  4. 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()

    View Slide

  5. 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();
    }
    }
    }

    View Slide

  6. 6
    Przetestuj działanie usług.

    View Slide

  7. 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

    View Slide

  8. 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.

    View Slide

  9. 9
    Główny układ widoków

    niech aktywność zawiera dwa pionowe fragmenty rozłożone poziomo
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="horizontal" >
    android:layout_weight="0.25"
    android:layout_width="0dp"
    android:layout_height="fill_parent" />
    android:layout_weight="0.75"
    android:layout_width="0dp"
    android:layout_height="fill_parent" />


    layout głównego okna umieszczamy w /res/layout-land/main.xml

    View Slide

  10. 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;
    }
    }

    View Slide

  11. 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

    View Slide

  12. 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

    View Slide

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

    View Slide

  14. 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);
    }
    }
    android:id="@+id/custom_view"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    View Slide

  15. 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

    View Slide

  16. 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();

    View Slide

  17. 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);

    View Slide

  18. 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

    View Slide

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

    View Slide

  20. 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*

    View Slide

  21. 21
    State list

    listy stanów pozwalają na podmianę grafik w zależności
    od stanu widoku, mają postać drawable w pliku XML
    xmlns:android="http://schemas.android.com/apk/re
    s/android">

    android:drawable="@drawable/info" />
    android:drawable="@drawable/info_active" />
    android:drawable="@drawable/info_active" />

    View Slide

  22. 22
    Style i tematy/motywy

    definiujemy je w dowolnym pliku o postaci XML w /res/values


    <br/><item name="android:layout_width">fill_parent</item><br/><item name="android:layout_height">wrap_content</item><br/><item name="android:textColor">#00FF00</item><br/><item name="android:typeface">monospace</item><br/>


    stosujemy je do elementów wizualnych
    android:text="Hello Android!" />

    podobnie aplikujemy motywy graficzne dla całych aplikacji lub aktywności

    .
    .
    .

    View Slide

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

    View Slide

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

    View Slide