Dependency Injection Setup
Overview
The **Dependency Injection Setup** module organizes and provides the core components required for media playback, ad integration, and UI control within a scoped lifecycle using Dagger 2. It enables modularity, testability, and clear separation of concerns by defining how key objects — such as the finite state machine (FSM) player, controllers, monitors, and ad interfaces — are instantiated and injected across the application.
This setup is crucial for managing the complex dependencies between playback states, user interface controllers, ad retrieval mechanisms, and VPAID clients, ensuring each part is provided consistently with appropriate lifecycle management.
Core Concepts
Purpose
Centralized Provisioning: Define and provide singleton-like instances scoped to an activity lifecycle, avoiding repeated instantiations and enabling sharing of dependencies.
Lifecycle Scope Management: Use a custom scope annotation (
@ActicityScope) to tie the lifetime of dependencies to UI/activity components, preventing memory leaks and ensuring proper cleanup.Modularity and Testability: Allow swapping modules for different environments (e.g., real playback vs. testing), simplifying testing and future extensions.
Decoupling: Separate object creation logic from usage, so classes like
FsmPlayer,PlayerUIController, orAdRetrieverdo not instantiate their dependencies but receive them injected.
Key Components
1. Custom Scope Annotation: @ActicityScope
Definition:
A custom Dagger scope annotation that marks dependencies to share the same lifecycle bound to an activity or similar UI component.Purpose:
Ensures that all dependencies annotated with@ActicityScopewithin a component remain singletons for that component instance.Code Reference:
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActicityScope { }
2. Dagger Modules
Modules define how to construct and provide dependencies.
a. PlayerModuleDefault
Role:
Provides default implementations for the player FSM, controllers, ad retrieval, monitors, and VPAID client for general or demo use cases.Highlights:
Provides a
FsmPlayerImperialinstance starting inFetchCuePointState.Supplies
PlayerUIControllerandPlayerAdLogicControllerwith default constructors.Returns fake or stub ad data via
AdInterfacefor testing or demo purposes.Supplies
AdPlayingMonitorandCuePointMonitorlinked to the FSM player.Provides a no-op
VpaidClientimplementation.
Example Provision:
@ActicityScope @Provides FsmPlayer provideFsmPlayer(StateFactory factory) { return new FsmPlayerImperial(factory) { @Override public Class initializeState() { return FetchCuePointState.class; } }; }Ad Interface Stub:
Returns immediately available ad media and no cue points.
b. FSMModuleReal
Role:
Provides concrete, real implementations backed by network simulations and real objects such as WebView for VPAID ads.Highlights:
Accepts optional
WebViewandViewto integrate with UI.Provides a
FsmPlayerImperialstarting inFetchCuePointState.Constructs
PlayerUIControllerandPlayerAdLogicControllerwith UI elements injected.Provides ad and cue point retrievers.
Supplies customized monitors (
AdPlayingMonitor,CuePointMonitor) wired to the FSM player.Simulates network delays to fetch ads and cue points asynchronously by posting delayed runnable tasks on the UI thread.
Provides a
TubiVPAIDclient implementation that communicates with the WebView for VPAID ad playback.
Example of Asynchronous Ad Fetching:
@Override public void fetchAd(AdRetriever retriever, final RetrieveAdCallback callback) { new Thread(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { } new Handler(Looper.getMainLooper()).post(() -> callback.onReceiveAd(provideAdMediaModel())); }).start(); }
3. Dagger Components
Components tie modules to injection targets and define the scope of provided dependencies.
a. FsmComonent
Scope:
@ActicityScopeModules: Uses
PlayerModuleDefaultInjection Target:
DoubleViewTubiPlayerActivity- a player activity that uses dual ExoPlayer instances.
Exposure:
Exposes
StateFactoryfor testing.
Purpose:
For default/demo usage, injecting dependencies into the main player activity.
b. FsmComonentReal
Scope:
@ActicityScopeModules: Uses
FSMModuleRealInjection Target:
RealActivity- an activity with real playback and ad integration.
Purpose:
Provides fully featured player dependencies including real ad fetch simulation and VPAID integration.Example:
@ActicityScope @Component(modules = FSMModuleReal.class) public interface FsmComonentReal { void inject(RealActivity activity); }
Dependency Interactions and Workflow
Activity Initialization:
An activity (e.g.,RealActivityorDoubleViewTubiPlayerActivity) requests injection from the Dagger component (FsmComonentRealorFsmComonent).Component Provides Dependencies:
The component creates or returns cached instances according to the@ActicityScopelifecycle, using the bound module to provide each dependency.FSM Player Setup:
TheFsmPlayerImperialinstance is provided with aStateFactorythat creates playback states. It starts in theFetchCuePointStateto retrieve cue points before playback.Controllers Injection:
UI controllers (PlayerUIController,PlayerAdLogicController) are injected, managing the UI and ad playback logic respectively.Ad Retrieval and Cue Points:
TheAdInterfaceprovided by the module fetches ads and cue points asynchronously (real or stubbed), triggering FSM state transitions.Monitors Setup:
AdPlayingMonitorandCuePointMonitorlisten to the FSM player and playback progress, coordinating ad insertion and playback.VPAID Client:
AVpaidClientimplementation (TubiVPAID) is injected to handle VPAID ads via WebView when necessary.
Code Snippets Illustrating Key Concepts
Custom Scope Annotation:
@Scope @Retention(RetentionPolicy.RUNTIME) public @interface ActicityScope { }Module Providing FSM Player with Initial State:
@ActicityScope @Provides FsmPlayer provideFsmPlayer(StateFactory factory) { return new FsmPlayerImperial(factory) { @Override public Class initializeState() { return FetchCuePointState.class; } }; }Component Injection Target Example:
@ActicityScope @Component(modules = FSMModuleReal.class) public interface FsmComonentReal { void inject(RealActivity activity); }Asynchronous Ad Fetching with Simulated Network Delay:
@Override public void fetchAd(AdRetriever retriever, final RetrieveAdCallback callback) { new Thread(() -> { try { Thread.sleep(2000); } catch (InterruptedException e) { } new Handler(Looper.getMainLooper()).post(() -> callback.onReceiveAd(provideAdMediaModel())); }).start(); }
Mermaid Diagram: Dependency Injection Component Structure
classDiagram
class FsmComonent {
+inject(DoubleViewTubiPlayerActivity)
+getStateFactory()
}
class FsmComonentReal {
+inject(RealActivity)
}
class FSMModuleReal {
+provideFsmPlayer()
+provideController()
+provideComponentController()
+provideAdRetriever()
+provideCuePointsRetriever()
+provideAdPlayingMonitor()
+provideCuePointMonitor()
+provideAdInterfaceNoPreroll()
+provideVpaidClient()
}
class PlayerModuleDefault {
+provideFsmPlayer()
+provideController()
+provideComponentController()
+provideAdRetriever()
+provideCuePointsRetriever()
+provideAdPlayingMonitor()
+provideCuePointMonitor()
+provideAdInterfaceNoPreroll()
+provideVpaidClient()
}
class ActicityScope
FsmComonent --> PlayerModuleDefault : uses
FsmComonentReal --> FSMModuleReal : uses
FSMModuleReal ..> ActicityScope : annotates providers
PlayerModuleDefault ..> ActicityScope : annotates providers
Summary of Relationships
@ActicityScopemarks singleton-like lifecycle for dependencies within an activity.PlayerModuleDefaultandFSMModuleRealdefine how dependencies are provided for different scenarios (default/demo vs. real).FsmComonentandFsmComonentRealconnect modules to activities, enabling injection.The FSM player and controllers are created and injected by these modules, ready for playback and ad management.
Ad interfaces and monitors are injected to support asynchronous ad retrieval and cue point handling.
The VPAID client is injected where WebView-based ad playback is required.
This setup ensures that the complex stateful playback system, including ads and UI controls, is managed with clear boundaries and lifecycle control, facilitating maintainability and extensibility of the media player system.