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

Say bye to Fragments with Conductor & Kotlin

Say bye to Fragments with Conductor & Kotlin

Updated slides for DroidKaigi 2018

Miguel Beltran

January 28, 2018
Tweet

More Decks by Miguel Beltran

Other Decks in Technology

Transcript

  1. class MainActivity : AppCompatActivity() { private lateinit var router: Router

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) router = Conductor.attachRouter(this, controller_container, savedInstanceState) } @Miqubel
  2. class MainActivity : AppCompatActivity() { private lateinit var router: Router

    override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) router = Conductor.attachRouter(this, controller_container, savedInstanceState) if (!router.hasRootController()) { router.setRoot(RouterTransaction.with(MainController())) } } @Miqubel
  3. class SimpleController : Controller() { override fun onCreateView(inflater: LayoutInflater, container:

    ViewGroup): View { val view = inflater.inflate(R.layout.controller_simple, container, false) // Do something with the view return view } } @Miqubel
  4. class CustomChangeHandler : AnimatorChangeHandler() { override fun getAnimator( container: ViewGroup,

    from: View?, to: View?, isPush: Boolean, toAddedToContainer: Boolean): Animator { val animator = AnimatorSet() to?.let { animator.play( ObjectAnimator .ofFloat(to, View.SCALE_X, 0f, 1f) ) animator.play( ObjectAnimator .ofFloat(to, View.SCALE_Y, 0f, 1f) ) } return animator } }
  5. override fun getAnimator(…): Animator { val animator = AnimatorSet() to?.let

    { animator.play(…) // The "to" View has a child with id "image" animator.play( ObjectAnimator .ofFloat(to.image, View.ROTATION, -360f, 1f) ) } return animator } @Miqubel
  6. onCreateView onDestroyView Controller is on top Pop from Router Config

    change. etc. New Controller instance @Miqubel
  7. class MyController(val parameter: String) : Controller() { override fun onCreateView(…):

    View { val view = inflater.inflate(…) view.textView.text = "My favorite city is $parameter" return view } } ❌ DON’T! @Miqubel
  8. class MyController(bundle: Bundle) : Controller(bundle) { constructor(parameter: String) : this(Bundle().apply

    { putString(EXTRA_PARAMETER, parameter) }) // Access arguments like class properties private val parameter by lazy { args.getString(EXTRA_PARAMETER) } //… view.textView.text = "My favorite city is $parameter" @Miqubel
  9. fun changeText(text: String) { // access to views with KAE

    view?.run { textView.text = text } } @Miqubel
  10. class MyController : Controller() { // Warning! this will leak

    on onDestroyView lateinit var textView: TextView override fun onCreateView(…): View { val view = inflater.inflate(…) // Store a reference to the textView for later textView = view.textView return view } ❌ DON’T! @Miqubel
  11. model = ViewModelProviders .of(activity as AppCompatActivity) .get(MyViewModel::class.java) model.getLiveData() .observe( activity

    as AppCompatActivity, Observer<String> { // Use the LiveData values } ) ❌ DON’T! @Miqubel
  12. abstract class BaseViewModelController : LifecycleController() { private val viewModelStore =

    ViewModelStore() fun viewModelProvider(factory): ViewModelProvider { return ViewModelProvider(viewModelStore, factory) } } @Miqubel Ref: https://github.com/bluelinelabs/Conductor/pull/405
  13. class MyDaggerController : Controller() { @Inject lateinit var value: String

    override fun onCreateView(…): View { val view = inflater.inflate(…) (activity!!.application as App).component.inject(this) return view } } @Miqubel
  14. @RunWith(AndroidJUnit4::class) class TestableControllerEspressoTest { @get:Rule val activity = ActivityTestRule… val

    controller = TestableController() @Before fun setUp() { activity.runOnUiThread { activity.activity.router.setRoot( RouterTransaction.with(controller) ) } } } @Miqubel
  15. @RunWith(AndroidJUnit4::class) class TestableControllerEspressoTest { //… @Test fun a_click_action() { //

    Call to Controller methods directly activity.runOnUiThread { controller.onClickDoAction() } // Check views onView(withId(R.id.textView)) .check(matches(withText(“Test is running"))) } } @Miqubel
  16. Recap @Miqubel View based apps on Android Manage your view

    stack Nice transition animations Surviving configuration changes
  17. Recap @Miqubel View based apps on Android Manage your view

    stack Nice transition animations Surviving configuration changes Compatible with pres. patterns
  18. Recap @Miqubel View based apps on Android Manage your view

    stack Nice transition animations Surviving configuration changes Compatible with pres. patterns Easy to test with Espresso