Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Life without Fragments

Life without Fragments

Google recommends that you use fragments to build a flexible UI. In cases when we need to optimize the UI for tablets or implement ViewPager this is indeed the easiest way.

Anyway, using fragments isn’t that easy. Anyone who’ve ever seen a diagram of their life cycle, understands the statement well :wink: Potential memory leaks, a complex API, and bugs (the number of questions on StackOverflow more than 100 000). And this doesn’t look as a brilliant idea anymore.

But what are the alternatives?

Video: https://www.youtube.com/watch?v=LidlAkrYKGg
Demo: https://github.com/johnkil/android-without-fragments

=====================================
Links:
https://github.com/weefbellington/screenplay
https://github.com/nhaarman/Triad
https://github.com/doridori/Pilot
https://github.com/mattlogan/Pancakes
https://github.com/lyft/scoop
https://github.com/bluelinelabs/Conductor
https://github.com/sockeqwe/mosby-conductor
https://www.reddit.com/r/androiddev/comments/2iodnx/advocating_against_android_fragments/
https://medium.com/square-corner-blog/advocating-against-android-fragments-81fd0b462c97
https://eng.lyft.com/building-single-activity-apps-using-scoop-763d4271b41
https://speakerdeck.com/rock3r/life-without-fragments-with-eugenio-marletti
https://softwaremill.com/finally-getting-rid-of-android-fragments/
https://www.polidea.com/blog/Introduction_To_Single_Activity_Applications/
https://github.com/xxv/android-lifecycle

Evgeny Shishkin

November 22, 2016
Tweet

More Decks by Evgeny Shishkin

Other Decks in Programming

Transcript

  1. 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) {
 }
 }
 }
  2. Triad class LoginScreen : Screen<ApplicationComponent>() {
 
 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<LoginContainer, ActivityComponent>() {
 
 fun signInButtonClicked() {
 triad.goTo(WelcomeScreen())
 }
 }
 
 class LoginView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
 LinearLayoutContainer<LoginPresenter, ActivityComponent>(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)
 }
 }
  3. 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())
 }
 }
  4. 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())
 }
 }
  5. 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()))
 }
 }
  6. Conductor + Mosby class LoginController : MvpController<LoginView, LoginPresenter>(), 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<LoginView>() {
 
 fun signInButtonClicked() {
 view?.showWelcomeScreen()
 }
 }