czwartek, 20 sierpnia 2020

Android Basics - User Interface

Tego kursu wcześniej nie słuchałam i jak teraz usłyszałam, że to dla kogoś, kto nigdy nie napisał ani jednej linijki kodu, to zaczęłam wątpić...

Ale dobrze, pomyślałam, przekonaj się, że to umiesz, a przy okazji może usłyszysz jakąś informację, o której nie wiesz. I tak dowiedziałam się o:

  • atrybucie android:textAppearance="?android:textAppearanceSmallInverse"  , którego mogę użyć, gdy nie będę wiedzieć jaki rozmiar czcionki wybrać
  • atrybucie layout_weight, który może wystąpić w LinearLayout przy layout_width="0dp", a jego wartość określa jaką częścią całości jest dany element (sumuje się wartości tego atrybutu u wszystkich dzieci rodzica i proporcjonalnie rozdysponowuje się miejsce)
  • RelativeLayout - gdy robiłam kurs mniej podstawowy, ten layout był pominięty, zastąpiony ConstraintLayout, okazuje się, że są bardzo podobne a atrybutem typu android:layout_toLeftOf lub  android:layout_below można ustawiać elementy obok siebie

Tak więc:
  • da się sensownie podzielić ekran bez wartości procentowych Guideline w ConstraintLayout
  • to, co ma być wyświetlane na ekranie nie musi być od razu w całoścu widoczne - mogę użyć ScrollView i wewnątrz niego zaprojektować ciekawy układ elementów

Liczyłam na to, że dowiem się coś ciekawego o projektowaniu ekranów. Początkowo byłam sceptyczna, bo nie jestem aż tak początkująca, ale ogólnie warto było obejrzeć, ponieważ pojawiło się wiele przykładów i często omawiane było, dlaczego warto zastosować takie a nie inne podejście.

Kurs, o którym piszę znajduje się tutaj.

środa, 19 sierpnia 2020

Jak dopasować style tekstu - wnioski z Material Design

Jak się okazuje, AndroidStudio ma zaimplementowane style wg Material Design, tylko nigdy nie dałam sobie czasu na to, żeby się w tym zorientować. To teraz już wiem :)
Planowałam te style przenieść do mojego projektu wpisując wszystkie dane, zgodnie z informacjami, a już nie muszę, bo tam wszystko jest. Tylko kroje czcionek zmieniłam.

I teraz wskazówki z tamtej strony (są tam też ciekawe, dobrze ilustrujące zagadnienia przykłady):

  • Nagłówki 
    • to krótkie, ważne teksty,
    • wyraźne, ciekawe kroje czcionek,
    • mniejsze nagłówki będą lepiej wyglądać w spokojniejszym kroju czcionki.
  • Podtytuły
    • mniejsze od nagłówków,
    • krókie teksty,
    • wyraźne kroje czcionek.
  • Treść
    • długa forma,
    • wyraźne kroje czcionek.
  • Podpisy
    • mogą być pod lub nad,
    • dotyczą tekstu, tytułu lub obrazu,
    • najmniejszy rozmiar czcionki,
    • proste, wyraźne kroje czcionek.
  • Przycisk
    • często allCaps,
    • często sans serif,
    • powinien być wyraźny, widoczny, dawać jasno do zrozumienia co robi.
  • Wyrównanie tekstu
    • Najczęściej do lewej
    • Cytaty wyśrodkowane, nie bardzo długie

O typografii z Material Design jest tutaj.

czwartek, 13 sierpnia 2020

Zmiana myślenia

Choć pozornie nie ma to nic wspólnego z programowaniem, od 4 tygodni realizuję program Droga Artysty. Bardzo polecam, to chyba najlepszy program rozwojowy, w jakim brałam udział. A możę pierwszy, za który wzięłam się na poważnie?

Tak czy inaczej - on oraz mój zespół Mastermind pomogli mi odkryć moją największą blokadę.

Ja NIE MOGĘ być programistą

Taka myśl, za każdym razem w mojej głowie. I nie chodzi o to, że nie będę dobrym programistą, czy idealnym, że nie w jakomś języku. Wcale. Nie mogę i już. Nie moja ścieżka, nie moje miejsce. NIE. Wstęp wzbroniony, możesz sobie siedzieć  IT, zajmować się czymkolwiek, ale tego nie wolno dotknąć. Jak Drzewo Poznania Dobra i Zła. A ja się słuchałam, nie moje, to nie. Czy kusiło? Nie wiem. Lubiłam inne rzeczy, lubiłam to, co robiłam.

Aż do środy, 3 tygodnie temu, kiedy uświadomiłam sobie, skąd to się wzięło i dlaczego to jest takie złe.

A zatem się z tego uwalniam, wróciłam do kursu, zaplanowałam kolejne. Wymyśliłam jak wykorzystam wiedzę w praktyce. 

Jest lepiej, serio. Jeśli Cię coś blokuje i nie masz z kim pogadać - napisz do mnie, zrozumiem Cię :)


Zapiszę sobie jeszcze co sobie przypomniałam powtarzając pierwszy moduł kursu (już to umiałam, tylko zapomniałam):

  • Używaj najprostrzego layoutu w kolejności:
    • Frame
    • Linear
    • Constrain
  • Ustawianie tekstu w TextView:
    • setText - wpisuje nową wartość
    • append - dodaje wartość do tego co już było

poniedziałek, 4 maja 2020

Dlaczego nie piszemy wymagań i testów w Wordzie (albo jakimś typowym edytorze tekstu)?

Zarządzanie wymaganiami i przypadkami testowymi zapisanymi w zwykłym pliku tekstowym jest bardzo trudne (wolałabym napisać niemożliwe, ale dla ludzi upartych i zdeterminowanych nie istnieją niemożliwe zadania).

Warto mieć powiązania między wymaganiami, testami, planami i wykonaniami testów, ponieważ:

  • łatwiej jest wszystko edytować w przypadku zmian
  • łatwiej zauważyć błędy i braki w dokumentacji
  • łatwiej przygotować podsumowanie, zobaczyć jak długo znajmuje testowanie, które testy są dla aplikacji problemowe.
Mineło dużo czasu odkąd ostatnio sensownie pracowałam nad testami i wymaganiami. Żałuję - to ważna praca, którą najchętniej odkłada się na kiedyś, a bywa, że "kiedyś" jednak nie nadchodzi. 

Teraz chciałam, żeby dokumentacja była ładna - byłam zachwycona całą ideą identyfikacji wizualnej marki, tak dużo radości dawało mi robienie rzeczy ładych, że dostały zbyt wysoki priorytet i dokumentacj powstała w Wordzie.

Na szczęście projekty są jeszcze małe, mają niewiele funkcji.

Chciałabym, żeby zdumiewały - i projekty, i wszystko co jest obok - dokumentacja też, więc jest ładna. Niemniej zaczęłam poszukiwania odpowiedniego dla mnie teraz narzędzia do zarządzania testaliami.

wtorek, 24 marca 2020

Czego nauczył mnie kompilator cz.1

  1. Gdy łączę tekst w pętli (np. z listy z bazy danych) to zamiast String (+) stosować StringBuilder (.append)
  2. Mogę zwrócić w funkcji wartość pętli if - nie muszę tam zapisywać true i false.

czwartek, 6 lutego 2020

Dobre praktyki - Lekcja 2

1. Commituj gdy kończysz pracę w danym momencie (nawet w wyniku przerwania).
2. Weryfikuj wywołania funkcji - czy na pewno tylko raz (rozsądne logi).
3. Porównuj Stringi przez .equals() a nie przez "=="

środa, 1 stycznia 2020

Jak zrobić aplikację bez górnego paska tytułowego?

W głównym stylu aplikacji należy dodać:

        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>


Plik styles.xml może wtedy wyglądać tak:

<resources>

    <!-- Base application theme. -->
    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <!-- Customize your theme here. -->
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>
        <item name="android:fontFamily">@font/italianno</item>
        <item name="android:textColor">@color/black</item>
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
    </style>

</resources>

wtorek, 5 listopada 2019

Szablon Planu Jakości



Kilka lat temu uczestniczyłam w szkoleniu ISTQB. Uważam, że prezentowana tam wiedza, schematy i procesy są bardzo sensowne - dlatego, że moja mentorka od początku mojej proacy pokazywała mi jak z nich korzystać.
Poniżej znajduje się schemat Planu Testów - my nazwaliśmy go Planem Jakości Projektu. Dopracowaliśmy go, zautomatyzowaliśmy wypełnianie go w naszym systemie Redmine i wielokrotnie szkoliliśmy nasz zespół w sposobie jego wypełniania. Dlaczego wielokrotnie? Plan jest długi i podczas jego wypełniania trzeba przemyśleć wiele aspektów jakości projektu (a nie każdy chce i potrafi to zrobić).
Przemyśleć, sprawdzić, ustalić - to najważniejszy cel wypełniania Planu Jakości.
Manifest Agile (który bardzo cenię) stawia dokumentację i przestrzeganie planu na drugim miejscu - zgadzam się z tym całkowicie - nie wypełniajmy planu dla smego wypełniania i generowania niepotrzebnej dokumentacji. Wypełniamy tyle, ile trzeba, a myślimy o wszystkim bo od nas zależy Jakość w projekcie.

  1. Identyfikator
  2. Wstęp
    1. autoryzacja projektu
    2. plan projektu
    3. plan QA
    4. plan zarządzania konfiguracją
    5. polityka testów
    6. standardy testów
  3. Przedmiot testów
    1. specyfikacja wymagań
    2. specyfikacja projektowania
    3. instrukcja obsługi/instalacji/funkcji
  4. Testowane funkcje
  5. Nietestowane funkcje
  6. Podejście do testów
  7. Kryteria przejścia/niezaliczenia testów
  8. Kryteria zawieszenia/wznowienia testów
  9. Rezultaty testów
    1. plan testów
    2. specyfikacja projektów testowych
    3. specyfikacja przypadków testowych
    4. przekazanie przedmiotu testów
    5. logi z testów
    6. raport incydentu testowego
    7. podsumowanie raportu testów
  10. Testowane zadania
  11. Niezbędne środowisko testowe
  12. Odpowiedzialność
  13. Zapotrzebowanie na personel i szkolenia
  14. Harmonogram
  15. Ryzyka i nieprzewidziane wydatki
  16. Pozwolenia/zatwierdzenia

wtorek, 9 kwietnia 2019

Screen size - czyli jaki rozmiar powinna mieć grafika tła

Przygotowałam moją Bardzo Ważną Aplikację.
Pracowałam nad nią długo, nadszedł dzień premiery i... nie dało się jej otworzyć na niektórych urządzeniach.
Okazało się, że dodane przeze mnie grafiki były za duże - urządzenia nie radziły sobie z ich dopasowaniem.

Podstawa, tak, jednak jakoś przeoczyłam.

Poczytałam trochę, między innymi:
https://vinsol.com/blog/2014/11/20/tips-for-designers-from-a-developer/
https://blog.prototypr.io/designing-for-multiple-screen-densities-on-android-5fba8afe7ead
https://medium.com/@sashaserg/a-mysterious-density-independent-pixel-a-quick-introduction-to-android-design-111d68be7cf5

I od tamtej pory wielkość grafik tła w moich projektach to około:
  • mdpi - 360x480 px
  • hdpi - 480x800 px
  • xhdpi - 720x1280 px
  • xxhdpi - 1080x1920 px
  • xxxhdpi - 1440x2560 px

Zazwyczaj nie mam odzielnych plików dla każdej wielkości ekranu - mam tylko jeden i dodaję go do katalogu, do którego najbardziej pasuje.
Staram się mimo wszystko nie mieć za dużych plików - to zazwyczaj one zwiększają rozmiar aplikacji, więc jeśli grafika nie jest najważniejszym elementem, dbam o oszczędność pamięci użytkownika

czwartek, 28 lutego 2019

Dobre praktyki - Lekcja 1


  1. Testuj małe elementy - im mniej, tym lepiej, nawet jeśli to tylko zmiana koloru - upewnij się, że się zmienił tam gdzie powinien.
  2. Testuj małe elementy - nawet jeśli nie powodują widocznej zmiany wyglądu lub zachowania - sprawdzaj, czy nic nie popsuły.
  3. Czytaj materiały branżowe regularnie - warto się uczyć od innych.
  4. Porządnie planuj - najpierw zgrubnie, później coraz dokładniej, im mniejsze zadania tym łatwiej je wykonać nawet przy zmęczeniu.
  5. Usuwaj logi, których nie potrzebujesz.
  6. Upewnij się, że element, którego używasz !=null

czwartek, 9 sierpnia 2018

Jak ustawić własne czcionki w aplikacji

  1. Pobierz pliki czcionek, których potrzebujesz
  2. Przekonwertuj czcionki do formatu .ttf (jeśli są w innym)
  3. Utwórz katalog czcionek w swoim projekcie (jeśli go nie ma)
    1. Wybierz menu konekstowe z katalogu res
    2. New -> Android Resource Directory
    3. Recource type: font
  4. Dodaj do katalogu font swoje czcionki
  5. Wprowadź swoje czcionki do projektu, np.
    1. Dodaj je do swojego stylu: <item name="android:fontFamily">@font/pt_sans</item> (API >=16)
    2. Dodaj je do swojego obiektu tekstowego w layout: android:fontFamily="@font/pt_sans"
    3. Dodaj je w kodzie swojej aplikacji do obiektu tekstowego

wtorek, 7 sierpnia 2018

Exception - org.json.JSON.typeMismatch

Dlaczego wystąpił?

Myślałam, że parsowany string to JSONObject a to był JSONArray.
Plik .json (a właściwie String) zrobiłam sama, więc wystarczyło usunąć [ ] z początku i końca.

niedziela, 5 sierpnia 2018

Room - kilka słów o przechowywaniu danych

  1. Dodaj odpowiednie zależności do build.gradle(Module: app)
    def room_version = "1.1.1"
    implementation "android.arch.persistence.room:runtime:$room_version"
    annotationProcessor "android.arch.persistence.room:compiler:$room_version"
    testImplementation "android.arch.persistence.room:testing:$room_version"
  2. Zsynchronizuj build.gradle
    1. kliknij prawym przyciskiem na build.gradle
    2. wybierz Synchronize build.gradle
  3. Dodaj klasę obiektu, który będzie reprezentował tabelę
    1. Daj jej annotację @Entity
    2. Dodaj kolumnę @PrimaryKey
    3. Dodaj pozostałe kolumny
    4. Dodaj gettery i settery elementów obiektu (na potrzeby Room)
      @Entity
      public class StoryObject {
          @PrimaryKey
          private int storyId;
          @ColumnInfo(name = "main_text")
          private String mainText;
  4. Stwórz interfejs z metodami dostępu do bazy - DAO
    1. Daj jej annotację @Dao
    2. Dodaj metody dostępu (napisane w SQL)
      @Dao
      public interface StoryDao {
          @Query("SELECT * FROM story")
          List<StoryObject> getAll();
          @Insert
          void insertAll(StoryObject... objects);
          @Delete
          void delete(StoryObject object);
      }
  5. Stwórz klasę (abstract) bazy danych
    1. Dodaj jej annotację @Database i przypisz klasy, które ją reprezentują (entities)
    2. Dodaj metodę (abstract), która zwróci odpowiedni obiekt Dao
      @Database(entities = {StoryObject.class}, version = 1)
      public abstract class StoryDatabase extends RoomDatabase {
          public abstract StoryDao getStoryDao();
      }
  6. W kodzie aplikacji wywołaj budowanie bazy danych
    StoryDatabase db = Room.databaseBuilder(getApplicationContext(),
            StoryDatabase.class, "story_database").build();

poniedziałek, 30 lipca 2018

Release – checklista

  • Change log - powiązanie z zadaniami (historyjkami) - scope of work vs lista commitów
  • Kiedy wypuszczono produkt
  • Jaki jest tag w repozytorium
  • Jakie były testy i gdzie są raporty
  • Gdzie znajduje się backup
  • Dokumentacja i konfiguracja - aktualne wersje

sobota, 28 lipca 2018

Android - testy wydania

Kilka dni temu wysłałam kolejną wersję aplikacji, jeszcze ciągle w wersji próbnej, testowej, w trakcie pracy. Ogólnie wydawałoby się - nic poważnego. Ale jednak wysłałam ją komuś - to jest poważne, powinnam być za to odpowiedzialna. Zrozumiałam, że nie zrobiłam jej wcześniej absolutnie podstawowych testów wydania. Nawet nie mam przygotowanych... Pora to zmienić.

Testy wydania aplikacji - android (ogólne)

  1. Aplikacja aktualizuje się z poprzedniej wersji do nowej (update)
  2. Aplikacja w aktualnej wersji może być zainstalowana na "czystym" urządzeniu (na takim, na którym nie jest zainstalowana) (instal)
  3. Aplikacja po wybraniu ikony włącza się i pokazuje ekran startowy (start)
  4. Aplikacja po wybraniu przycisku cofinij wyłącza się (end)
  5. Aplikacja wykonuje podstawową funkcję (work)
  6. Aplikacja aktualizuje się do poprzedniej wersji (downgrade)

Testy wydania aplikacji - android (dodatkowe)

  1. Aplikacja działa bez internetu (internet permission)
    1. brak wyjątków
    2. informacja o braku połączenia
    3. niezakłócone działanie
  2. Aplikacja działa przy obracaniu ekranu (orientation)
    1. dźwięk
    2. obraz
    3. funkcje
  3. ...

poniedziałek, 23 lipca 2018

Jak dodać odtwarzacz audio?

  1. Dodaj do pliku build.gradle -> dependencies
    compile 'com.google.android.exoplayer:exoplayer:r2.2.0'
  2. Dodaj do swojej aktywności
    implements View.OnClickListener, ExoPlayer.EventListener
  3. Dodaj do swojej aktywności obsługującej audio zmienne ExoPlayer
    private SimpleExoPlayer mExoPlayer;
    private SimpleExoPlayerView mPlayerView;
    private static MediaSessionCompat mMediaSession;
    private PlaybackStateCompat.Builder mStateBuilder;
    private NotificationManager mNotificationManager;
  4. Zainicjalizuj wstępnie zmienne
    mPlayerView = (SimpleExoPlayerView) findViewById(R.id.playerView);
    mPlayerView.setPlayer(mExoPlayer);
    initializeMediaSession();
    initializePlayer(Uri.parse(audioPath));

  5. Zaimplementuj inicjalizację MediaSession
     mMediaSession = new MediaSessionCompat(this, this.getClass().getSimpleName());
    mMediaSession.setFlags(
            MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS |
                    MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
    mMediaSession.setMediaButtonReceiver(null);
    mStateBuilder = new PlaybackStateCompat.Builder()
            .setActions(
                    PlaybackStateCompat.ACTION_PLAY |
                    PlaybackStateCompat.ACTION_PAUSE |
                    PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS |
                    PlaybackStateCompat.ACTION_PLAY_PAUSE);
    mMediaSession.setPlaybackState(mStateBuilder.build());
    mMediaSession.setCallback(new MySessionCallback());
    mMediaSession.setActive(true);
  6. Zaimplementuj podklasę MySessionCallback
            @Override
            public void onPlay() {
                mExoPlayer.setPlayWhenReady(true);
            }

            @Override
            public void onPause() {
                mExoPlayer.setPlayWhenReady(false);
            }

            @Override
            public void onSkipToPrevious() {
                mExoPlayer.seekTo(0);
            }
  7. Zaimplementuj inicjalizację playera
    if (mExoPlayer == null) {
        // Create an instance of the ExoPlayer.
        TrackSelector trackSelector = new DefaultTrackSelector();
        LoadControl loadControl = new DefaultLoadControl();
        mExoPlayer = ExoPlayerFactory.newSimpleInstance(this, trackSelector, loadControl);
        mPlayerView.setPlayer(mExoPlayer);

        // Set the ExoPlayer.EventListener to this activity.
        mExoPlayer.addListener(this);
       
        // Prepare the MediaSource.
        String userAgent = Util.getUserAgent(this, "ClassicalMusicQuiz");
        MediaSource mediaSource = new ExtractorMediaSource(mediaUri, new DefaultDataSourceFactory(
                this, userAgent), new DefaultExtractorsFactory(), null, null);
        mExoPlayer.prepare(mediaSource);
        mExoPlayer.setPlayWhenReady(true);
    }
  8. Zaimplementuj funkcję zamykania playera
    mNotificationManager.cancelAll();
    mExoPlayer.stop();
    mExoPlayer.release();
    mExoPlayer = null;
  9. Dodaj funkcję zamykania playera do odDestroy()
        super.onDestroy();
        releasePlayer();
        mMediaSession.setActive(false);
  10. Zaimplementuj funkcję onPlayerStateChanged()
    if((playbackState == ExoPlayer.STATE_READY) && playWhenReady){
        mStateBuilder.setState(PlaybackStateCompat.STATE_PLAYING,
                mExoPlayer.getCurrentPosition(), 1f);
    } else if((playbackState == ExoPlayer.STATE_READY)){
        mStateBuilder.setState(PlaybackStateCompat.STATE_PAUSED,
                mExoPlayer.getCurrentPosition(), 1f);
    }
    mMediaSession.setPlaybackState(mStateBuilder.build());
    showNotification(mStateBuilder.build());
  11. Zaimplementuj MediaReceiver
    public static class MediaReceiver extends BroadcastReceiver {
        public MediaReceiver() {
        }

        @Override
        public void onReceive(Context context, Intent intent) {
            MediaButtonReceiver.handleIntent(mMediaSession, intent);
        }
    }
  12. Dodaj do manifestu aktywność obsługującą odtwarzacz
    <activity android:name=".QuizActivity"
        android:launchMode="singleTop"/>
    <receiver android:name=".QuizActivity$MediaReceiver">
        <intent-filter>
            <action android:name="android.intent.action.MEDIA_BUTTON" />
        </intent-filter>
    </receiver>
  13. Przygotuj layout uwzględniający SimpleExoPlayerView
     <com.google.android.exoplayer2.ui.SimpleExoPlayerView
            android:id="@+id/playerView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="0dp"
            android:layout_marginRight="0dp"
            android:layout_marginBottom="0dp"
            android:layout_marginLeft="0dp"/>

niedziela, 22 lipca 2018

Jak przechowywać dane - json

Jedną z możliwości przechowywania danych jest plik w formacie .json (JavaScript Object Notation).

Cechy w porównaniu z XML i JAML
  • dostęp do danych w formacie JSON jest bardziej naturalny z poziomu języka JavaScript niż dostęp do tych samych danych w formacie XML
  • nie jest już jednak tak naturalny dla Javy i wymaga stosowania specjalnych bibliotek
  • w nowszych wersjach standardów dopuszczana jest wymiana danych za pomocą JSON-a (np. w REST)
  • w praktyce zajmuje znacząco mniej miejsca niż analogiczny obiekt przesyłany za pomocą formatu XLM.
  • JSON jest łatwiejszy do analizowania składni niż jego nadzbiór YAML
Przykład (kurs android - udacity)

[

{

"name": "Toccata and Fugue in D minor",

"id": 0,

"uri": "asset:///toccata_fugue.mp3",

"composer": "Johann Sebastian Bach",

"albumArtID": "bach"

},

{

"name": "Fur Elise",

"id": 1,

"uri": "asset:///fur_elise.mp3",

"composer": "Ludwig van Beethoven",

"albumArtID": "beethoven"

}
]














Jak zastosować?

Stworzyć obiekt .java, który będzie odczytywał dane, np.:

private Sample(int sampleID, String composer, String title, String uri, String albumArtID) {
        mSampleID = sampleID;
        mComposer = composer;
        mTitle = title;
        mUri = uri;
        mAlbumArtID = albumArtID;
    }


środa, 11 lipca 2018

wtorek, 10 lipca 2018

Jak dodać menu do aplikacji?

  1. Nadaj nazwy swoim opcjom - np. wprowadź je jako wartości w strings.xml
  2. Utwórz katalog zasobów dla menu:
    1. Kliknij prawy przyciskiem na katalog res
    2. Wybierz New Resource Directory
    3. Zmień Recource Type z value na menu
  3.  Dodaj w katalogu plik menu.xml:
    1. Kliknij prawy przyciskiem na katalog menu
    2. Wybierz New -> Menu Resource File
  4. Wprowadź ustawienia opcji menu, np.:
    <?xml version="1.0" encoding="utf-8"?>
    <menu xmlns:android="http://schemas.android.com/apk/res/android" 
     xmlns:app="http://schemas.android.com/apk/res-auto"> 
          <item android:id="@+id/menu_day1" 
                android:orderInCategory="1"         
                app:showAsAction="never" 
                android:title="@string/menu_d1" />
    </menu> 
  5. Zaimplementuj w aktywności, która udostępnia menu funkcje onCreateOptionsMenu i onOptionsItemSelected, np.:
    @Overridepublic boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.menu, menu);    return true;}
    
    @Overridepublic boolean onOptionsItemSelected(MenuItem item) {
        return selectItem(item);}
    
    public boolean selectItem(MenuItem item) {
        switch (item.getItemId()) {
            case R.id.menu_day1:
                return true;        case R.id.menu_day2:
                return true;        case R.id.menu_day3:
                return true;        case R.id.menu_day4:
                return true;        case R.id.menu_day5:
                return true;        default:
                return super.onOptionsItemSelected(item);    }
    }