- 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
poniedziałek, 30 lipca 2018
Release – checklista
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)
- Aplikacja aktualizuje się z poprzedniej wersji do nowej (update)
- Aplikacja w aktualnej wersji może być zainstalowana na "czystym" urządzeniu (na takim, na którym nie jest zainstalowana) (instal)
- Aplikacja po wybraniu ikony włącza się i pokazuje ekran startowy (start)
- Aplikacja po wybraniu przycisku cofinij wyłącza się (end)
- Aplikacja wykonuje podstawową funkcję (work)
- Aplikacja aktualizuje się do poprzedniej wersji (downgrade)
Testy wydania aplikacji - android (dodatkowe)
- Aplikacja działa bez internetu (internet permission)
- brak wyjątków
- informacja o braku połączenia
- niezakłócone działanie
- Aplikacja działa przy obracaniu ekranu (orientation)
- dźwięk
- obraz
- funkcje
- ...
poniedziałek, 23 lipca 2018
Jak dodać odtwarzacz audio?
- Dodaj do pliku build.gradle -> dependencies
compile 'com.google.android.exoplayer:exoplayer:r2.2.0' - Dodaj do swojej aktywności
implements View.OnClickListener, ExoPlayer.EventListener - 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; - Zainicjalizuj wstępnie zmienne
mPlayerView = (SimpleExoPlayerView) findViewById(R.id.playerView);
mPlayerView.setPlayer(mExoPlayer);
initializeMediaSession();
initializePlayer(Uri.parse(audioPath)); - 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); - Zaimplementuj podklasę MySessionCallback
@Override
public void onPlay() {
mExoPlayer.setPlayWhenReady(true);
}
@Override
public void onPause() {
mExoPlayer.setPlayWhenReady(false);
}
@Override
public void onSkipToPrevious() {
mExoPlayer.seekTo(0);
} - 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);
} - Zaimplementuj funkcję zamykania playera
mNotificationManager.cancelAll();
mExoPlayer.stop();
mExoPlayer.release();
mExoPlayer = null; - Dodaj funkcję zamykania playera do odDestroy()
super.onDestroy();
releasePlayer();
mMediaSession.setActive(false); - 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()); - Zaimplementuj MediaReceiver
public static class MediaReceiver extends BroadcastReceiver {
public MediaReceiver() {
}
@Override
public void onReceive(Context context, Intent intent) {
MediaButtonReceiver.handleIntent(mMediaSession, intent);
}
} - 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> - 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
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;
}
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
[ | ||||||||||||||
{ | ||||||||||||||
"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
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
Co się stało?
Próbowałam inicjalizować zmienne String jeszcze przed zaczęciem funkcji, tam gdzie powinna być tylko deklaracja.
Rozwiązanie - na górze tylko geklaracje, inicjalizacja w kodzie funkcji.
Próbowałam inicjalizować zmienne String jeszcze przed zaczęciem funkcji, tam gdzie powinna być tylko deklaracja.
Rozwiązanie - na górze tylko geklaracje, inicjalizacja w kodzie funkcji.
wtorek, 10 lipca 2018
Jak dodać menu do aplikacji?
- Nadaj nazwy swoim opcjom - np. wprowadź je jako wartości w strings.xml
- Utwórz katalog zasobów dla menu:
- Kliknij prawy przyciskiem na katalog res
- Wybierz New Resource Directory
- Zmień Recource Type z value na menu
- Dodaj w katalogu plik menu.xml:
- Kliknij prawy przyciskiem na katalog menu
- Wybierz New -> Menu Resource File
- 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>
- 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); } }
Subskrybuj:
Posty (Atom)