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

Functional Views on Android

Fede
November 07, 2015

Functional Views on Android

The reactive and functional programming is making his way in Android development. Alternatives like Rx provide some features in this paradigm but they don’t allow to take advantage the real potential of the functional programming.

In this talk, we’ll discover a new way to manage our UI through the functional programming. An approach to transform, compose and slay Android UI Views.

Fede

November 07, 2015
Tweet

More Decks by Fede

Other Decks in Programming

Transcript

  1. WHO ARE WE? Fede Fernández Scala Software Engineer at 47

    Degrees @fede_fdz Javi Pacheco Scala Software Engineer at 47 Degrees @javielinux
  2. WHAT’S FUNCTIONAL PROGRAMMING? Expression evaluation VS Statement execution Functions are

    first class High-order functions Purity: Immutable data Referential transparency Lazy evaluation Purity and effects
  3. OUR PROGRAM class MainActivity extends AppCompatActivity with TypedFindView with MainPresentationLogic

    with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  4. TRAITS class MainActivity extends AppCompatActivity with TypedFindView with MainPresentationLogic with

    MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  5. What’s Traits? Fundamental unit of code reuse in Scala Method

    and field definitions A class can mix in any number Order matters Thin versus rich interfaces
  6. LAZY VALS AND OPTIONS class MainActivity extends AppCompatActivity with TypedFindView

    with MainPresentationLogic with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  7. LAZY VALS AND OPTIONS class MainActivity extends AppCompatActivity with TypedFindView

    with MainPresentationLogic with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  8. Butter Knife VS lazy vals @Bind(R.id.textView) TextView textView; @Override public

    void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.my_activity); ButterKnife.bind(this); textView.setText(“Hi!”) }
  9. Butter Knife VS lazy vals lazy val textView: TextView =

    findView(TR.textView) override def onCreate(bundle: Bundle) = { super.onCreate(bundle) setContentView(R.layout.my_activity) textView.setText("Hi!") }
  10. WORKING WITH OPTIONS class MainActivity extends AppCompatActivity with TypedFindView with

    MainPresentationLogic with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  11. WORKING WITH OPTIONS class MainActivity extends AppCompatActivity with TypedFindView with

    MainPresentationLogic with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  12. Build Options val option1: Option[String] = Option(“my_string”) val option2: Option[String]

    = None val option3: Option[String] = Option(null) Some(“my_string”) None None
  13. IMPLICITS class MainActivity extends AppCompatActivity with TypedFindView with MainPresentationLogic with

    MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  14. IMPLICITS class MainActivity extends AppCompatActivity with TypedFindView with MainPresentationLogic with

    MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  15. class MyActivity extends BaseActivity { @Override void onCreate(Bundle bundle) {

    ... ToastOps.showMessage(this, "Implicits are awesome!") } } class ToastOps { static void showMessage(Context context, String msg) { Toast.makeText(context, msg, Toast.LENG_SHORT).show() } } Java - Contexts are the Devil
  16. class MyActivity extends AppCompatActivity with Contexts[Activity] { implicit context: ImplicitContext

    = ??? override def onCreate(bundle: Bundle) = { ToastOps.showMessage("Implicits are awesome!") } } object ToastOps { def showMessage(msg: String)(implicit c: ImplicitContext) = Toast.makeText(c.bestAvailable, msg, Toast.LENG_SHORT).show() } Using implicits
  17. PRESENTATION LOGIC class MainActivity extends AppCompatActivity with TypedFindView with MainPresentationLogic

    with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  18. PRESENTATION LOGIC class MainActivity extends AppCompatActivity with TypedFindView with MainPresentationLogic

    with MainBusinessLogic with Contexts[Activity] { lazy val recycler = Option(findView(TR.recycler)) lazy val fabActionButton = Option(findView(TR.fab_action_button)) override def onCreate(state:Bundle) = { super.onCreate(savedInstanceState) setContentView(R.layout.main_activity) val maybeToolBar = Option(findView(TR.toolbar)) maybeToolBar map { toolbar => setSupportActionBar(toolbar) } fetchAsyncData map { data => runUi(initUi(data)) } } }
  19. class MainActivity extends BaseActivity { RecyclerView recycler FloatingActionButton fabActionButton @Override

    void onCreate(Bundle bundle) { ... recycler = (RecyclerView) findViewById(...) fabActionButton = (FloatingActionButton) findViewById (...) initUi(this, items); } } Ui Action in Java void initUi(Context context, List<Item> items) { initRecycler(context, items); initFab(context); } void initRecycler(Context context, List<Item> items) { recycler.setAdapter(new MyAdapter(items)); recycler.setHasFixedSize(true); recycler.setLayoutManager( new GridLayoutManager(context, 2)); }
  20. Presentation Logic: The functional way Init Recycler Create UI Actions

    Compose them Execute them UI Action Side effects! Init FAB
  21. The presentation logic trait MainPresentationLogic { val recycler: Option[RecyclerView] val

    fabActionButton: Option[FloatingActionButton] def initRecycler(seq: Seq[Item])(implicit c: ImplicitContext): Ui[_] = ??? def initFAB()(implicit c: ImplicitContext): Ui[_] = ??? def initUi(items: Seq[Item])(implicit c: ImplicitContext): Ui[_] = ??? }
  22. def recyclerTweak(items: Seq[Item])(implicit c: ImplicitContext) = Tweak[RecyclerView] { rv =>

    rv.setAdapter(new MyAdapter(items, clickListener)) rv.setHasFixedSize(true) rv.setLayoutManager( new GridLayoutManager(c.bestAvailable, 2)) } Macroid FTW!
  23. def recyclerTweak(items: Seq[Item])(implicit c: ImplicitContext) = Tweak[RecyclerView] { rv =>

    rv.setAdapter(new MyAdapter(items, clickListener)) rv.setHasFixedSize(true) rv.setLayoutManager( new GridLayoutManager(c.bestAvailable, 2)) } Macroid FTW!
  24. def initRecycler(items: Seq[Item])(implicit c: ImplicitContext): Ui[_] = recycler <~ recyclerTweak(items)

    def initUi(items: Seq[Item])(implicit c: ImplicitContext): Ui[_] = initRecycler(items) ~ initFAB Macroid FTW!
  25. NO