Slide 1

Slide 1 text

Life without Fragments Evgeny Shishkin @johnkil

Slide 2

Slide 2 text

Why Fragments?

Slide 3

Slide 3 text

Fragments

Slide 4

Slide 4 text

Single Activity

Slide 5

Slide 5 text

No content

Slide 6

Slide 6 text

FragmentManager + IllegalStateException

Slide 7

Slide 7 text

public empty constructor

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

github.com/JetradarMobile/multibackstack

Slide 10

Slide 10 text

Alternative?

Slide 11

Slide 11 text

Advocating Against Android Fragments by Square

Slide 12

Slide 12 text

View-based App

Slide 13

Slide 13 text

Flow (square) Conductor (bluelinelabs) Scoop (lyft) Pancakes (mattlogan) Pilot (doridori) Triad (nhaarman) Screenplay (weefbellington)

Slide 14

Slide 14 text

Screenplay

Slide 15

Slide 15 text

Screenplay Stage Rigger Component #1 Component #2 Create setUp tearDown Destroy

Slide 16

Slide 16 text

Screenplay class LoginStage(val app: ScreenplayApp) : XmlStage() {
 val rigger by lazy { CrossFadeRigger(app) }
 
 init {
 addComponents(SignInComponent(app))
 }
 
 override fun getLayoutId(): Int {
 return R.layout.stage_login
 }
 
 override fun getRigger(): Stage.Rigger {
 return rigger
 }
 
 private class SignInComponent(val app: ScreenplayApp) : Component {
 override fun afterSetUp(stage: Stage, isInitializing: Boolean) {
 val signInButton = stage.view.findViewById(R.id.sign_in_button)
 signInButton.setOnClickListener { signIn() }
 }
 
 private fun signIn() {
 app.appFlow.set(WelcomeStage(app))
 }
 
 override fun beforeTearDown(stage: Stage, isFinishing: Boolean) {
 }
 }
 }

Slide 17

Slide 17 text

Triad

Slide 18

Slide 18 text

Triad Presenter Container Screen View Create onCreate onAttach Destroy onDetach onDestroy

Slide 19

Slide 19 text

Triad class LoginScreen : Screen() {
 
 override val layoutResId = R.layout.screen_login
 
 override fun createPresenter(viewId: Int) = LoginPresenter(applicationComponent.triad)
 }
 
 interface LoginContainer : Container {
 fun setUpEmail(email: String)
 fun setUpPassword(password: String)
 }
 
 class LoginPresenter(private val triad: Triad) : BasePresenter() {
 
 fun signInButtonClicked() {
 triad.goTo(WelcomeScreen())
 }
 }
 
 class LoginView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
 LinearLayoutContainer(context, attrs,
 defStyle), LoginContainer {
 
 override fun onFinishInflate() {
 super.onFinishInflate()
 signInButton.setOnClickListener { presenter.signInButtonClicked() }
 }
 
 override fun setUpEmail(email: String) {
 emailEdit.setText(email)
 }
 
 override fun setUpPassword(password: String) {
 passwordEdit.setText(password)
 }
 }

Slide 20

Slide 20 text

Pilot

Slide 21

Slide 21 text

Pancakes

Slide 22

Slide 22 text

Pancakes ViewStack UIContainer Previous view Next view LayoutId

Slide 23

Slide 23 text

Pancakes class LoginView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
 
 override fun onFinishInflate() {
 super.onFinishInflate()
 if (isInEditMode) return
 
 val signInButton = findViewById(R.id.sign_in_button)
 signInButton.setOnClickListener { signIn() }
 }
 
 private fun signIn() {
 val viewStack = (context as ViewStackActivity).viewStack()
 viewStack.pushWithAnimation(R.layout.view_welcome, CircularReveal())
 }
 }

Slide 24

Slide 24 text

Scoop

Slide 25

Slide 25 text

Scoop • Screen • Router • ViewController • Layout • Transitions

Slide 26

Slide 26 text

Scoop Router UIContainer Previous view Next view Screen Route change

Slide 27

Slide 27 text

Scoop @EnterTransition(FadeTransition::class)
 @ExitTransition(FadeTransition::class)
 @Controller(LoginController::class)
 class LoginScreen : Screen()
 
 class LoginController : ViewController() {
 override fun layoutId() = R.layout.screen_login
 
 override fun onAttach() {
 val signInButton = view.findViewById(R.id.sign_in_button)
 signInButton.setOnClickListener { signIn() }
 }
 
 private fun signIn() {
 router.goTo(WelcomeScreen())
 }
 }

Slide 28

Slide 28 text

Conductor

Slide 29

Slide 29 text

Conductor

Slide 30

Slide 30 text

Conductor • Controller • Router • RouterTransaction • ControllerChangeHandler

Slide 31

Slide 31 text

Conductor class LoginController : Controller() {
 
 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
 val view = inflater.inflate(R.layout.controller_login, container, false)
 val signInButton = view.findViewById(R.id.sign_in_button)
 signInButton.setOnClickListener { signIn() }
 return view
 }
 
 private fun signIn() {
 router.pushController(RouterTransaction.with(WelcomeController())
 .pushChangeHandler(SimpleSwapChangeHandler())
 .popChangeHandler(SimpleSwapChangeHandler()))
 }
 }

Slide 32

Slide 32 text

Conductor + Mosby

Slide 33

Slide 33 text

Conductor + Mosby class LoginController : MvpController(), LoginView {
 
 override fun createPresenter() = LoginPresenter()
 
 override fun onCreateView(inflater: LayoutInflater, container: ViewGroup): View {
 val view = inflater.inflate(R.layout.controller_login, container, false)
 val signInButton = view.findViewById(R.id.sign_in_button)
 signInButton.setOnClickListener { presenter.signInButtonClicked() }
 return view
 }
 
 override fun showWelcomeScreen() {
 router.pushController(RouterTransaction.with(WelcomeController())
 .pushChangeHandler(SimpleSwapChangeHandler())
 .popChangeHandler(SimpleSwapChangeHandler()))
 }
 }
 
 interface LoginView : MvpView {
 fun showWelcomeScreen()
 }
 
 class LoginPresenter : MvpBasePresenter() {
 
 fun signInButtonClicked() {
 view?.showWelcomeScreen()
 }
 }

Slide 34

Slide 34 text

github.com/johnkil/android-without-fragments

Slide 35

Slide 35 text

Thank You

Slide 36

Slide 36 text

No content

Slide 37

Slide 37 text

Links