moderne app-entwicklung am beispiel waipu.tv
TRANSCRIPT
![Page 1: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/1.jpg)
Moderne App-Entwicklung am Beispiel waipu.tv
Andreas Bauer Johannes Schamburger10.11.2016
![Page 2: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/2.jpg)
2
Informationen zur inovex GmbH
- IT-Dienstleister in Pforzheim, Karlsruhe, Köln,
München und Hamburg
- Application Development, Datamanagement &
Analytics, Consulting und IT Engineering & Operations
- ca. 250 Mitarbeiter
![Page 3: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/3.jpg)
3
Informationen zu waipu.tv- Projekt der Firma EXARING AG
- Freenet ist Investor - Vermarktung u.a.
in Mobilcom Debitel Läden
- Entwicklung gestartet im letzten Herbst
- Android Entwicklung seit Anfang des Jahres mit einer
Teamgröße von 3-5 Entwicklern
- Launch von waipu.tv zum 1.10.2016
![Page 4: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/4.jpg)
4
Was ist waipu.tv?
- TV Live-Streams
- Aufnehmen von TV-Streams
- Zeitversetzte TV-Streams
- Wiedergabe in der App und auf
dem TV (Chromecast, Amazon Fire TV)
- App als (Next Generation) Fernbedienung
![Page 5: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/5.jpg)
5
Streaming
![Page 6: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/6.jpg)
6
Weitere Funktionen
![Page 7: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/7.jpg)
- Gott-Klassen
- Testbarkeit
- Wartbarkeit
- Abhängigkeit vom Framework / Lifecycle
7
MotivationTypische Probleme in der Android App Architektur
![Page 8: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/8.jpg)
8
Überlegungen
- Welches Architekturmodell?
- Welche Libraries?
- Dependency Injection?
- Reactive Programming?
![Page 9: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/9.jpg)
9
Clean Architecture (Uncle Bob)
http://fernandocejas.com/2014/09/03/architecting-android-the-clean-way/
![Page 10: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/10.jpg)
10
Eigenschaften
Die Architektur ist
- unabhängig von der UI
- unabhängig von der Datenbank
- unabhängig von Frameworks
- testbar
![Page 11: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/11.jpg)
11
Architektur Beispiel EPG Daten
![Page 12: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/12.jpg)
12
Architektur Beispiel EPG Daten
![Page 13: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/13.jpg)
13
MVP - Model View Presenter
![Page 14: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/14.jpg)
14
MVP Beispiel Kanalwechsel
![Page 15: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/15.jpg)
15
MVP Beispiel Kanalwechsel
![Page 16: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/16.jpg)
public interface StreamingPresenter<T> extends BasePresenter<T> { void onStop(); void onDestroy(); void onCastDeviceDisconnected(); void onCastStarted(); void onCastStopped(); void onMuteToggled(boolean muted); void onJumpToStart(); …}
16
Presenter Beispiel
![Page 17: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/17.jpg)
17
View Beispielpublic interface StreamingView<T> extends BaseView<T> { void setPreviewImage(String previewImageHref); void showErrorMessageForStream(); void hideErrorMessageForStream(); void setChannel(Channel channel); void updateCastOverlayMessage(String castDeviceName); void showFullScreenLoadingIndicator(); void hideFullScreenLoadingIndicator(); …}
![Page 18: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/18.jpg)
18
Pros und Cons von MVP+ Separation of Concerns+ Kleinere, übersichtlichere Klassen+ Testbarkeit
- Klassen Overhead- Mehraufwand in der Entwicklung- saubere Umsetzung erzeugt teilweise lange
Callstrecken
![Page 19: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/19.jpg)
19
Beispiel Presenter Unit-Test@Testpublic void select_channel_should_start_stream() throws Exception { String streamUrl = "streamUrl"; doReturn(Observable.just(streamUrl)).when(streamUseCase) .getStreamURL(anyString(), anyString(), anyString(), anyString(), anyString(), anyLong()); presenter.onLocalChannelSelected("ARD"); verify(liveTvView).hideErrorMessageForStream(); verify(liveTvView).setupVideoPlayer(any(VideoPlayer.class), any(EventLogger.class)); verify(liveTvView).setStream(streamUrl, VideoPlayerView.StreamType.TYPE_DASH); verify(liveTvView).startDevicePlayback(); verify(liveTvView).updateCastViewState(); verifyNoMoreInteractions(liveTvView);}
![Page 20: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/20.jpg)
20
Beispiel lange CallstreckeSzenario: Sender wird gewechselt, Sendungsdetails
werden aktualisiert.
Container Fragment -> LiveTvFragment -> LiveTvPresenter
-> LiveTvFragment -> TvDetailsView -> TvDetailsPresenter
-> TvDetailsView
![Page 21: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/21.jpg)
21
Reactive Programming
“In reactive programming the consumer reacts to the data
as it comes in. This is the reason why asynchronous
programming is also called reactive programming. Reactive
programming allows to propagates event changes to
registered observers.” - Lars Vogel
![Page 22: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/22.jpg)
22
RxJava
- Java VM Implementierung der ReactiveExtensions
- Portiert von .NET zu JVM von Netflix 2014
- leichtgewichtig
- Open Source
- Seit 2014 im ReactiveX Repository auf GitHub
![Page 23: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/23.jpg)
23
Einfaches Beispiel ObservableObservable<String> simpleObservable = Observable.create( new Observable.OnSubscribe<String>() { @Override public void call(Subscriber<? super String> subscriber) { subscriber.onNext("Simple Value"); subscriber.onCompleted(); } });
![Page 24: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/24.jpg)
24
Einfaches Beispiel SubscriberSubscriber<String> simpleSubscriber = new Subscriber<String>() { @Override public void onNext(String value) { println(value); } @Override public void onCompleted() {} @Override public void onError(Throwable e) {} };simpleObservable.subscribe(simpleSubscriber);
![Page 25: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/25.jpg)
25
Operatoren manipulieren emittierte ItemsObservable<String> simpleObservable = Observable.just("Simple Value") .map(new Func1<String, String>() { @Override public String call(String value) { return value + " now modified"; } }); simpleObservable.subscribe (new Subscriber<String>() { @Override public void onNext(String value) { println(value); // prints “Simple Value now modified" }… }
![Page 26: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/26.jpg)
26
Rx bei waipu.tvpublic Observable<List<Channel>> getChannels() { Observable<List<Channel>> apiCall = authorization. .getAuthorizationStringAsObservable() .flatMap(new Func1<String, Observable<? extends List<Channel>>>() { @Override public Observable<? extends List<Channel>> call(String auth) { return businessSystemsApi.getChannelData(auth); }
});
return authorization.loginWhenRequired(apiCall).doOnNext(new Action1<List<Channel>>() {
@Overridepublic void call(List<Channel> channels) {
dbHelper.insertChannelList(channels);}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()); }
- Authentifizierung
- BS - Aufruf
- Zusätzlicher Login- Retry- Datenbankoperation
- Thread Handling
![Page 27: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/27.jpg)
27
Rx bei waipu.tvremoteDataSubject.observeOn(AndroidSchedulers.mainThread()) .map(new Func1<Void, Boolean>() { @Override public Boolean call(Void aVoid) { // get Current Remote Program Information // if program is still valid return false // else return true } })
.distinctUntilChanged().observeOn(Schedulers.io()).flatMap(new Func1<Boolean, Observable<List<EPGData>>>() {
@Overridepublic Observable<List<EPGData>> call(Boolean value) {
// Return Observable which emits Program Data for a timespan}
})
![Page 28: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/28.jpg)
28
Rx bei waipu.tv .flatMap(new Func1<List<EPGData>, Observable<ProgramInformation>>() { @Override public Observable<ProgramInformation> call(List<EPGData> epg) { // Get Current Timestamp // return ProgramOverview for channel } })
.retry(new Func2<Integer, Throwable, Boolean>() {@Override public Boolean call(Integer retryCount, Throwable t) {
return retryCount < 3;
}})
.subscribe(new DefaultSubscriber<ProgramInformation>("NotificationModelUpdater") {@Override public void onNext(ProgramInformation programInformation) {
// Update Program Information
}});
![Page 29: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/29.jpg)
29
Problematikenprivate Subscription statusSubscription;private void listenToStatusChanges() { statusSubscription = someObject.listenToStatusChanges() .subscribe(new Subscriber<StatusObject>() { ... @Override public void onNext(StatusObject o) { //do Stuff } });}
private void unsubscribeToStatusChanges() { if(statusSubscription != null && !statusSubscription.isUnsubscribed()) { statusSubscription.unsubscribe(); } }
![Page 30: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/30.jpg)
30
Dependency Injection
- Klassen verwalten ihre Abhängigkeiten nicht selbst
- Single Responsibility
- komfortable Möglichkeit, Singletons zu verwenden
- einfaches Austauschen von konkreten
Implementierungen (z.B. für Tests)
![Page 31: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/31.jpg)
31
Dependency Injection - DaggerInject
@Inject
StreamUseCase streamUseCase;
![Page 32: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/32.jpg)
32
Dependency Injection - DaggerModule, Provides, Singleton
@Module
public class UseCaseModule {
@Provides
@Singleton
public StreamUseCase provideStreamUseCase(BusinessSystemsApi businessSystemsApi, AuthUseCase authUseCase, EPGUseCase epgUseCase) {
return new StreamUseCase(businessSystemsApi, authUseCase, epgUseCase);
}
}
![Page 33: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/33.jpg)
33
Dependency Injection - DaggerComponent
@Component(modules = {AppModule.class, CastModule.class, UseCaseModule.class})
public interface AppComponent {
void inject(WaipuApplication application);
StreamUseCase streamUseCase();
}
![Page 34: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/34.jpg)
34
Dependency Injection - DaggerComponent
@Component(modules = {AppModule.class, CastModule.class, UseCaseModule.class})
public interface AppComponent {
void inject(WaipuApplication application);
StreamUseCase streamUseCase();
}@Component(dependencies = AppComponent.class, modules = {LiveTvModule.class})
public interface LiveTvComponent {
void inject(LiveTvFragment fragment);
void inject(LiveTvPresenterImpl liveTvPresenter);
}
![Page 35: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/35.jpg)
35
Dependency Injection - DaggerInjection
public class LiveTvFragment implements LiveTvView {
@Override
public void onCreate(Bundle savedInstanceState) {
appComponent = WaipuApplication.get(getActivity()).getAppComponent();
liveTvComponent = DaggerLiveTvComponent.builder()
.appComponent(appComponent)
.liveTvModule(new LiveTvModule(this))
.build();
liveTvComponent.inject(this);
}
}
![Page 36: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/36.jpg)
+ Instanziierung und Konfiguration gut nachvollziehbar+ Singletons+ Testing
- Klassen-Overhead- “Boilerplate” Code
36
Pros and Cons
![Page 37: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/37.jpg)
@Injectprotected AudioStateManager audioStateManager;
37
Singletons
AudioStateManager
StreamingPresenter
VideoPlayer
CastManager
VideoPlayerControl...
![Page 38: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/38.jpg)
38
Klassen-Overhead & Boilerplate Code
![Page 39: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/39.jpg)
39
LiveTvComponent:
@FragmentScope@Component(dependencies = AppComponent.class, modules = {LiveTvModule.class})public interface LiveTvComponent { void inject(LiveTvFragment fragment); void inject(LiveTvPresenterImpl liveTvPresenter);}
Klassen-Overhead & Boilerplate Code
![Page 40: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/40.jpg)
40
LiveTvComponent:
@FragmentScope@Component(dependencies = AppComponent.class, modules = {LiveTvModule.class})public interface LiveTvComponent { void inject(LiveTvFragment fragment); void inject(LiveTvPresenterImpl liveTvPresenter);}
Klassen-Overhead & Boilerplate Code
LiveTvFragment:
@Overridepublic void setupComponent(AppComponent appComponent) { liveTvComponent = DaggerLiveTvComponent.builder() .appComponent(appComponent) .liveTvModule(new LiveTvModule(this)) .build(); liveTvComponent.inject(this);}
![Page 41: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/41.jpg)
- Mehraufwand zahlt sich langfristig aus
- Herausforderung: konsequente Umsetzung
- automatisiertes Testen bei Android nach wie vor
umständlich
- RxJava - easy to learn, hard to master
- Gefahr von sehr großen Klassen ist nicht gebannt
41
Fazit und Erkenntnisse
![Page 42: Moderne App-Entwicklung am Beispiel waipu.tv](https://reader031.vdokument.com/reader031/viewer/2022030210/58ae88ab1a28abdf068b4c0f/html5/thumbnails/42.jpg)
Das Bild kann derzeit nicht angezeigt werden.
Vielen Dank
Unser Dank gilt besonders der EXARING AG, die uns diesen Vortrag ermöglicht hat.