-
Notifications
You must be signed in to change notification settings - Fork 0
MVP Architecture
Thiago Fernando Rech edited this page Jul 6, 2025
·
1 revision
ToneForge has been completely refactored to implement the MVP (Model-View-Presenter) pattern, resulting in a more modular, testable, and maintainable architecture.
- β Monolithic Architecture - Overloaded MainActivity
- β Giant Fragments - Up to 2,590 lines in a single file
- β Strong Coupling - Business logic mixed with UI
- β Hard to Test - Direct dependencies between components
- β Complex Maintenance - Changes affected multiple modules
- β MVP Architecture - Clear separation of responsibilities
- β Focused Fragments - 40% code reduction
- β Low Coupling - Well-defined interfaces
- β Easily Testable - Isolated presenters
- β Simple Maintenance - Localized changes
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β VIEW LAYER β
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
β β HomeFragment β β EffectsFragment β β LooperFragment ββ
β β (UI Logic) β β (UI Logic) β β (UI Logic) ββ
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β PRESENTER LAYER β
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
β β HomePresenter β β EffectsPresenterβ β LooperPresenter ββ
β β (Business Logic)β β(Business Logic) β β(Business Logic) ββ
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β MODEL LAYER β
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
β β AudioRepository β β AudioState β β EffectParametersββ
β β (Data Access) β β (Data Model) β β (Data Model) ββ
β βββββββββββββββββββ βββββββββββββββββββ ββββββββββββββββββββ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
com.thiagofernendorech.toneforge/
βββ ui/
β βββ base/
β β βββ BaseView.java # Common interface for views
β β βββ BasePresenter.java # Base class for presenters
β β βββ BaseFragment.java # Base fragment with MVP
β βββ navigation/
β β βββ NavigationController.java # Decoupled navigation
β βββ fragments/
β βββ home/
β β βββ HomeContract.java # MVP interface
β β βββ HomePresenter.java # Business logic
β β βββ HomeFragmentRefactored.java # Pure UI
β βββ effects/
β β βββ EffectsContract.java
β β βββ EffectsPresenter.java
β β βββ EffectsFragmentRefactored.java
β βββ [7 other fragments...]
βββ data/
β βββ repository/
β βββ AudioRepository.java # Unified data layer
βββ domain/
βββ models/
βββ AudioState.java # Audio state
βββ EffectParameters.java # Effect parameters
Defines the contract between View and Presenter:
public interface HomeContract {
interface View extends BaseView {
void navigateToEffects();
void navigateToLooper();
void updateConnectionStatus(boolean connected);
}
interface Presenter extends BasePresenter<View> {
void onEffectsClicked();
void onLooperClicked();
void onWifiClicked();
}
}Manages business logic and coordinates View and Model:
public class HomePresenter implements HomeContract.Presenter {
private WeakReference<HomeContract.View> viewRef;
private AudioRepository audioRepository;
private NavigationController navigation;
@Override
public void onEffectsClicked() {
ifViewAttached(view -> {
navigation.navigateToEffects();
});
}
@Override
public void onLooperClicked() {
ifViewAttached(view -> {
navigation.navigateToLooper();
});
}
}Only UI logic, no business rules:
public class HomeFragmentRefactored extends BaseFragment<HomeContract.Presenter>
implements HomeContract.View {
@Override
protected HomeContract.Presenter createPresenter() {
return new HomePresenter(
requireContext(),
NavigationController.getInstance(),
AudioRepository.getInstance(requireContext())
);
}
@Override
public void navigateToEffects() {
// Navigation will be handled by NavigationController
}
}Centralizes all navigation between fragments:
public class NavigationController {
private static NavigationController instance;
private WeakReference<MainActivity> mainActivityRef;
public void navigateToHome() {
executeNavigation(activity -> {
activity.loadFragment(new HomeFragmentRefactored());
activity.updateHeaderTitle("ToneForge");
});
}
public void navigateToEffects() {
executeNavigation(activity -> {
activity.loadFragment(new EffectsFragmentRefactored());
activity.updateHeaderTitle("Effects");
});
}
}Unified interface for all audio operations:
public class AudioRepository {
private static AudioRepository instance;
private AudioEngine audioEngine;
private AudioStateManager stateManager;
private PresetManager presetManager;
// Pipeline Operations
public boolean startAudioPipeline() {
return audioEngine.startPipeline();
}
public void pauseAudioPipeline() {
audioEngine.pausePipeline();
}
// Effects Operations
public void applyEffectParameters(EffectParameters params) {
audioEngine.applyEffectParameters(params);
}
// Preset Operations
public void savePreset(String name) {
presetManager.savePreset(name);
}
public AudioState getCurrentAudioState() {
return stateManager.getCurrentState();
}
}- β
HomeFragment β
HomeFragmentRefactored - β
EffectsFragment β
EffectsFragmentRefactored - β
LooperFragment β
LooperFragmentRefactored - β
TunerFragment β
TunerFragmentRefactored - β
MetronomeFragment β
MetronomeFragmentRefactored - β
RecorderFragment β
RecorderFragmentRefactored - β
SettingsFragment β
SettingsFragmentRefactored - β
LoopLibraryFragment β
LoopLibraryFragmentRefactored - β
LearningFragment β
LearningFragmentRefactored
- EffectsFragment: 2,590 β 926 lines (-64%)
- LooperFragment: 1,433 β 850 lines (-40%)
- Total: ~5,000 β ~3,000 lines (-40%)
// Fragment with mixed logic
public class OldHomeFragment extends Fragment {
private void onEffectsClicked() {
// Business logic mixed with UI
if (AudioEngine.getInstance().isRunning()) {
FragmentManager fm = getParentFragmentManager();
FragmentTransaction transaction = fm.beginTransaction();
transaction.replace(R.id.fragment_container, new EffectsFragment());
transaction.commit();
}
}
}// Isolated and testable presenter
@Test
public void testHomePresenter_onEffectsClicked() {
// Arrange
HomePresenter presenter = new HomePresenter(context, navigation, repository);
// Act
presenter.onEffectsClicked();
// Assert
verify(navigation).navigateToEffects();
}- View: Only UI and events
- Presenter: Business logic
- Model: Data and state
- Presenters can be tested in isolation
- Mocks and Stubs easy to implement
- Test coverage significantly improved
- Cleaner code and organized
- Localized changes in each layer
- Easy addition of new features
- Base components reusable
- Consistent patterns throughout the project
- Well-defined interfaces
- Easy addition of new fragments
- Architecture prepared for growth
- Established patterns for development
- Create the Contract:
public interface MyContract {
interface View extends BaseView {
void updateData(String data);
}
interface Presenter extends BasePresenter<View> {
void loadData();
}
}- Implement the Presenter:
public class MyPresenter implements MyContract.Presenter {
// Business logic implementation
}- Create the Fragment:
public class MyFragment extends BaseFragment<MyContract.Presenter>
implements MyContract.View {
// UI implementation
}| Aspect | Before | After |
|---|---|---|
| Architecture | Monolithic | MVP Modular |
| Lines of Code | 5,000+ | 3,000+ |
| Testability | Difficult | Easy |
| Maintainability | Low | High |
| Coupling | High | Low |
| Reusability | None | High |
| Scalability | Limited | Excellent |
The MVP refactoring completely transformed ToneForge, creating a solid foundation for future development. The new architecture offers:
- Cleaner and organized code
- Ease of testing and maintenance
- Scalability for new features
- Consistent patterns throughout the project
- Better experience for developers
For technical implementation details, see Development and Testing Strategy.
Transform your Android into a professional pedalboard with real-time audio processing!
- Documentation: This Wiki
- Issues: GitHub Issues
- Discussions: GitHub Discussions
- Email: [thiagorech.1997@gmail.com]
Built with β€οΈ by Thiago Fernando Rech
- Architecture
- MVP Architecture π
- Testing Strategy π
- Layout Guidelines π
- Development
- Refactoring Summary π
- Documentation Updates
Quick Links: