Mobius는 Android UI 및 RxJava Observable에 연결하기 위한 추가 기능이 포함된 상태 변화 및 부작용을 관리하기 위한 기능적 반응 프레임워크입니다. 이는 우려 사항 분리, 테스트 가능성 및 코드의 상태 저장 부분 격리를 강조합니다.
자세한 내용을 보려면 웹사이트를 방문하여 사용 설명서를 확인하세요. Mobius가 실제로 작동하는 모습을 보려면 Android Architecture Blueprints의 앱을 기반으로 하는 샘플 TODO 앱을 확인하세요. Mobius를 소개하는 Android @Scale의 강연도 시청하실 수 있습니다.
Mobius는 프로덕션 상태입니다. 즉, Spotify Android 애플리케이션의 프로덕션에 사용되며 API가 안정적이고 구현에 버그가 없다고 간주합니다. 우리는 이전 버전과의 호환성을 깨뜨리는 변경을 하지 않을 것입니다.
Mobius는 현재 Java 7용으로 제작되었습니다(Java 8은 모든 Android 버전에서 완전히 지원되지 않기 때문입니다). 따라서 java.util.function
에 정의된 일부 개념이 중복됩니다( com.spotify.mobius.functions
참조).
Mobius를 사용할 때 주로 향상된 유형 추론과 람다를 사용하면 코드의 가독성과 간결성이 크게 향상되므로 Kotlin 또는 Java 8 이상을 사용하는 것이 좋습니다.
Mobius의 최신 버전은 Maven Central을 통해 제공됩니다(아래 LATEST_RELEASE는 ).
implementation ' com.spotify.mobius:mobius-core:LATEST_RELEASE '
testImplementation ' com.spotify.mobius:mobius-test:LATEST_RELEASE '
implementation ' com.spotify.mobius:mobius-rx:LATEST_RELEASE ' // only for RxJava 1 support
implementation ' com.spotify.mobius:mobius-rx2:LATEST_RELEASE ' // only for RxJava 2 support
implementation ' com.spotify.mobius:mobius-rx3:LATEST_RELEASE ' // only for RxJava 3 support
implementation ' com.spotify.mobius:mobius-android:LATEST_RELEASE ' // only for Android support
implementation ' com.spotify.mobius:mobius-extras:LATEST_RELEASE ' // utilities for common patterns
이것이 다른 모든 모듈이 의존하는 Mobius의 핵심입니다. 이는 완전히 독립적인 순수 Java 라이브러리입니다. 이것은 Mobius를 사용할 때 필요한 유일한 모듈입니다. 다른 모듈은 코어에 대한 선택적 확장이기 때문입니다.
테스트 모듈에는 Mobius 애플리케이션에 대한 테스트를 작성하는 데 도움이 되는 유틸리티가 포함되어 있습니다. 테스트 종속성으로만 사용해야 합니다.
rx 모듈에는 RxJava용 확장이 포함되어 있습니다. 효과 핸들러와 이벤트 소스 생성을 단순화하므로 Mobius 애플리케이션에서 그 중 하나를 사용해야 합니다. 두 RxJava 모듈 모두 동일한 API를 공유하며, 유일한 차이점은 하나는 RxJava 1.x용으로, 다른 하나는 RxJava 2.x용으로 빌드된다는 것입니다.
android 모듈에는 주로 MobiusLoop를 Android에 연결하기 위한 클래스가 포함되어 있습니다.
extras 모듈에는 일부 고급 사용 패턴(예: 중첩 업데이트 기능)에 대한 상용구를 줄이는 데 도움이 되는 유틸리티와 클래스가 포함되어 있습니다.
Mobius의 목표는 애플리케이션 상태를 더 잘 제어할 수 있도록 하는 것입니다. 상태를 애플리케이션에 있는 변수의 모든 현재 값에 대한 스냅샷으로 생각할 수 있습니다. Mobius에서는 모델 이라고 부르는 데이터 구조에 모든 상태를 캡슐화합니다.
모델은 원하는 유형으로 표현될 수 있습니다. 이 예에서는 간단한 카운터를 작성하므로 모든 상태가 Integer
에 포함될 수 있습니다.
Mobius에서는 상태를 직접 조작할 수 없습니다. 상태를 변경하려면 수행하려는 작업을 설명하는 프레임워크 메시지를 보내야 합니다. 우리는 이러한 메시지를 이벤트라고 부릅니다. 우리의 경우에는 카운터를 늘리거나 줄이려고 합니다. enum
사용하여 이러한 경우를 정의해 보겠습니다.
enum CounterEvent {
INCREMENT ,
DECREMENT ,
}
이제 Model 과 일부 Event 가 있으므로 Mobius가 우리를 대신하여 상태를 업데이트하는 데 사용할 수 있는 일련의 규칙을 제공해야 합니다. 다음 Model을 생성하기 위해 들어오는 모든 Event 와 최신 Model 과 함께 순차적으로 호출될 함수를 프레임워크에 제공하여 이를 수행합니다.
class CounterLogic {
static Integer update ( Integer model , CounterEvent event ) {
switch ( event ) {
case INCREMENT : return model + 1 ;
case DECREMENT : return model - 1 ;
}
}
}
이러한 구성 요소를 사용하면 애플리케이션을 이벤트에 대한 응답으로 개별 상태 간 전환으로 생각할 수 있습니다. 그러나 우리는 퍼즐에서 아직 한 가지가 빠져 있다고 믿습니다. 즉, 상태 간 이동과 관련된 부작용입니다. 예를 들어, "새로 고침" 버튼을 누르면 애플리케이션이 "로드 중" 상태가 될 수 있으며, 백엔드에서 최신 데이터를 가져오는 부작용도 있습니다.
Mobius에서는 이러한 부작용을 Effect s라고 적절하게 부릅니다. 카운터의 경우 사용자가 0 미만으로 감소하려고 하면 대신 음향 효과를 재생한다고 가정해 보겠습니다. 가능한 모든 효과를 나타내는 enum
만들어 보겠습니다(이 경우에는 하나뿐입니다).
enum CounterEffect {
PLAY_SOUND ,
}
이제 특정 상태 전환과 관련된 효과 세트도 반환하도록 update
기능을 강화해야 합니다. 이를 위해 다음과 같이 Update
인터페이스를 구현합니다.
class CounterLogic implements Update < Integer , CounterEvent , CounterEffect > {
public Next < Integer , CounterEffect > update ( Integer model , CounterEvent event ) {
switch ( event ) {
case INCREMENT :
return next ( model + 1 );
case DECREMENT :
if ( model == 0 ) {
Set < CounterEffect > soundEffect = effects ( CounterEffect . PLAY_SOUND );
return dispatch ( soundEffect );
}
return next ( model - 1 );
}
throw new IllegalStateException ( "Unhandled event: " + event );
}
}
Mobius는 상태 전환에서 반환한 각 효과를 효과 처리기(Effect Handler) 라고 하는 것으로 보냅니다. 이제 Connectable
인터페이스를 구현하여 그 중 하나를 만들어 보겠습니다.
class CounterEffectHandler implements Connectable < CounterEffect , CounterEvent > {
public Connection < CounterEffect > connect ( Consumer < CounterEvent > output ) {
return new Connection < CounterEffect >() {
@ Override
public void accept ( CounterEffect effect ) {
if ( effect == CounterEffect . PLAY_SOUND ) {
Toolkit . getDefaultToolkit (). beep ();
}
}
@ Override
public void dispose () {}
};
}
}
이제 모든 조각이 준비되었으므로 하나로 묶어 보겠습니다.
public static void main ( String [] args ) {
// Let's make a Mobius Loop
MobiusLoop < Integer , CounterEvent , CounterEffect > loop = Mobius
. loop ( new CounterLogic (), new CounterEffectHandler ())
. startFrom ( 0 );
// And start using our loop
loop . dispatchEvent ( CounterEvent . INCREMENT ); // Model is now 1
loop . dispatchEvent ( CounterEvent . DECREMENT ); // Model is now 0
loop . dispatchEvent ( CounterEvent . DECREMENT ); // Sound effect plays! Model is still 0
}
뫼비우스의 기본을 다루고 있습니다. 자세한 내용을 알아보려면 당사 웹사이트를 방문하세요.
우리는 Google의 자동 포맷터를 사용하여 코드 형식을 지정하고 있습니다. 빌드 파이프라인은 형식이 올바르지 않은 빌드에 실패하도록 설정되어 있습니다. 올바른 형식을 보장하려면 다음을 실행하세요.
./gradlew format
이 프로젝트는 공개 행동 강령을 준수합니다. 참여함으로써 귀하는 이 코드를 준수해야 합니다.