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);    }
    }