• Stars
    star
    1,185
  • Rank 38,469 (Top 0.8 %)
  • Language
    Java
  • License
    Apache License 2.0
  • Created over 10 years ago
  • Updated over 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Extras binding and intent builders for Android apps.

Dart Maven Central Android ArsenalBuild Status

This is the README of the version 3 of Dart & Henson has been released. If you are looking for the README page of Dart & Henson 2, please visit this wiki page.

Summary

Extra "binding" & intent builders library for Android. Dart & Henson (DH) uses annotation processing to bind intent's extras to pojo fields, and to generate intent builders via a fluent API.

Description of DH 3

Dart and Henson is a an Android Library that structures the navigation layer of your apps. It helps to create intents and consume them in a structured way. We believe it's the best way to organize your navigation layer, and make it less error-prone and easier to maintain.

It is made of 2 components: Dart and Henson. Both of them use annotated classes (navigation models) that describe the parameters (extras of the intent) of a target activity. DH3 provides a gradle plugin to generate the henson navigator class, and we strongly encourage to use the plugin. See the samples for more details.

Navigation models

A navigation model class is a simple pojo with annotated non private fields. The fields describe an extra passed to the target of an intent:

@DartModel //use this annotation on all your models
public class MyActivityNavigationModel {
  //a simple requested field, it's name is used as the extra key
  @BindExtra String extra1;
  //a named field using an annotation
  @BindExtra(MY_CONSTANT_NAME) String extra2;
  //an optional field
  @BindExtra @Nullable MyParcelableOrSerializable extra3;
}

To setup a navigation model module:

dependencies {
  implementation 'com.f2prateek.dart:dart-annotations:X.Y.Z'
  implementation 'com.f2prateek.dart:dart:X.Y.Z'
  implementation 'com.f2prateek.dart:henson:X.Y.Z'
  annotationProcessor 'com.f2prateek.dart:dart-processor:X.Y.Z'
  annotationProcessor 'com.f2prateek.dart:henson-processor:X.Y.Z'
}

Note that in DH3, navigation models:

  • are mandatory, it's not possible to annotate activities directly.
  • must follow a naming convention: they should have the same fully qualified name as the activity or service they describe the navigation of, plus the suffix: NavigationModel. (e.g.: com.foo.wooper.app.MyActivityNavigationModel).
  • must be placed in their own module. If MyActivity lives in the module module-foo, then you should place your navigation models inside a module named module-foo-navigation. There is no constraint enforcement on the name of this module, but we strongly encourage you to stick to this convention for naming the navigation model.
  • the @DartModel annotation is actually optional if there is at least one field annotated with @BindExtra, but, as a good practice, we recommend to always add it.

Dart

The historical first component of the library is used to map intents to Pojos (navigation models). Typically, a target activity will define a navigation model class, a pojo with annotated fields and will map the intents it receives to an instance of its model:

public class MyActivity extends Activity {

  //the navigation model field must be annotated
  //it's up to developers to initialize it
  @DartModel MyNavigationModel navigationModel;
  
  public void onCreate(Bundle savedInstanceState) {
    Dart.bind(this);
  }
}

Note that in DH3:

  • an activity (or a service) can map the extras of the intent it receives, or a bundle like savedInstanceState. For fragments the bundle of getArguments() will be used;
  • you can also use Dart.bind(this, this) or Dart.bind(this, bundle);
  • the initialization of the navigation model is performed by Dart.
  • you can use the code above in a super class and forget not call bind in subclasses. But subclasses will need to annotate their own navigation model field.
  • in the case of inheritance, the navigation model of the subclasses must extend the navigation model of the super class.
  • in the case of inheritance, bind() will replace the instance of the navigation model of the super classes by an instance of the navigation model of the subclasses. That's a side effect of Dart, it allows for better performances (as it doesn't rebind the model in all classes).

Henson

The second component of the library is used to create intents. Based on the navigation model, henson will create an intent builder for the described class (remember the name of the activity / service can be dedudced from the FQN of the model). It creates also some useful wrapper around them, see below.

Generally speaking, Intent Builders generated by Henson are not used directly, but via the HensonNavigator class that is generated for each module. When you want a module M0 to use other module navigation APIs, M0 must use the gradle henson-plugin.

The HensonNavigator Class

Setup of a module using other modules navigation API via HensonNavigator:

apply plugin: 'dart.henson-plugin'

buildscript {
  repositories {
     jcenter()
  }
  dependencies {
    classpath "com.f2prateek.dart:henson-plugin:X.Y.Z"
  }
}

dependencies {
  implementation project(':module1-navigation')
}

henson {
  navigatorPackageName = "com.foo.module0"
}

The plugin scans your dependencies and wraps all the intent builders that are found in the classpath. The HensonNavigator is then generated:

Intent intent = HensonNavigator.gotoMyActivity(context)
 .extra1("foo")
 .extra2(42)
 .extra3(myObj) //optional
 .build();

The intent builders used by a module are detected automatically during the build, based on the dependencies a module uses, and the HensonNavigator is generated accordingly.

What's new in DH3 ?

Briefly:

  • DH2.1 is available to help you migrate to DH3. We will detail this in our migration guide.
  • DH3 classes have been repackaged to allow a smoother migration.
  • DH3 fully supports modularization. It was the main motivation for the version 3, and it requested quite a few changes.
  • DH3 supports navigation cycles between modules. As modules expose their navigation APIs in a different module, we avoid compile time cycles.
  • DH3 offers a gradle plugin. DH3 uses a lot of annotation processing internally, configurations, artifacts, custom tasks. Do not set it up manually unless you know gradle well. Use the plugin.
  • DH3.1+ supports incremental annotation processing when used with gradle 4.7+. All annotation processors are isolating.
  • DH3.1.2+ requires Android Gradle Plugin 3.3.0 as it uses Task Configuration Avoidance.

ProGuard

If ProGuard is enabled be sure to add these rules to your configuration:

-dontwarn dart.internal.**
-keep class **__ExtraBinder { *; }
-keep class **__NavigationModelBinder { *; }
-keepclasseswithmembernames class * {
    @dart.* <fields>;
}
-keep class **Henson { *; }
-keep class **__IntentBuilder { *; }
-keep class **HensonNavigator { *; }

#if you use it
#see Parceler's github page
#for specific proguard instructions

Download

Dart:

implementation 'com.f2prateek.dart:dart:(insert latest version)'
annotationProcessor 'com.f2prateek.dart:dart-processor:(insert latest version)'

Henson :

implementation 'com.f2prateek.dart:henson:(insert latest version)'
annotationProcessor 'com.f2prateek.dart:henson-processor:(insert latest version)'

Henson-plugin :

classpath 'com.f2prateek.dart:henson-plugin:(insert latest version)'
apply plugin: 'dart.henson-plugin'

Kotlin

For all Kotlin enthusiasts, you may wonder how to use this library to configure your intents. This is perfectly compatible, with a bit of understanding of how Kotlin works, especially when it comes to annotation processing.

Assuming that your project is already configured with Kotlin, update your build.gradle file :

apply plugin: 'kotlin-kapt'

dependencies {
  implementation 'com.f2prateek.dart:henson:(insert latest version)'
  kapt 'com.f2prateek.dart:henson-processor:(insert latest version)'
}

Please note that DH3 annotation processors will support incremental annotation processing via the new gradle API. They are also deterministic and kapt tasks can be safely cached.

Now you can use @BindExtra annotation to generate either non-null or nullables properties :

class MyExampleActivityNavigationModel {
  @BindExtra
  lateinit var title: String

  @BindExtra
  var titleDefaultValue: String = "Default Title"

  @Nullable
  @JvmField
  @BindExtra
  var titleNullable: String? = null
}

Note that you still need to use the Java @Nullable annotation otherwise Henson won't interpret your property as nullable and will generate a builder with a mandatory field (even though you declared your property as nullable with the "?" Kotlin marker). Finally, you have to add the @JvmField annotation or your compiler will complain about not having a backing field.

Finally, if you are using Parceler that comes built-in with this library, the syntax does not change from Java, except when dealing with data classes. Because Parceler requires a default constructor with no argument, here is how you need to declare your data class :

@Parcel(Parcel.Serialization.BEAN)
data class ParcelExample @ParcelConstructor constructor(
        val id: Int,
        val name: String,
        ...
}

Talks & Slides

Credits

The original author of the library is Prateek Srivastava who got inspired by the work of Jake Wharton on butter knife.

Later, Daniel Molinero Reguera and Stephane NICOLAS contributed Henson in Dart 2, and rewrote the library for Dart 3.

Logo was designed by Jibbie R. Eguna(jbeguna04)

All the effort on versions 2 and versions 3 have been actively supported by Groupon. Thanks for this awesome OSS commitment !

License

Copyright 2013 Jake Wharton
Copyright 2014 Prateek Srivastava (@f2prateek)

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

More Repositories

1

rx-preferences

Reactive SharedPreferences for Android
Java
1,537
star
2

progressbutton

A custom progress indicator with a tiny footprint.
Java
632
star
3

rx-receivers

Reactive Bindings for BroadcastReceivers — WIP
Java
368
star
4

device-frame-generator

Wrap your app screenshots in real device artwork.
Java
234
star
5

gradle-android-javafmt-plugin

Augomagically format Java files (deprecated)
Groovy
58
star
6

android-bee

Kotlin
45
star
7

android-checkstyle-plugin

Configures the checkstyle plugin for Android projects
Groovy
39
star
8

train

Chainable HTTP client middleware.
Go
31
star
9

bundler

Bundler is small fluent API on top top of android.os.Bundle
Java
20
star
10

cloak

Library to Bootstrap Dagger on Android
Java
16
star
11

android-couchpotato

WIP
Java
9
star
12

clearbit-go

Golang API for the Clearbit API.
Go
8
star
13

android-xkcd

XKCD Comic Viewer
Java
5
star
14

segment-android

Java
4
star
15

hn2instapaper

Save the top articles on Hacker News to your Instapaper account.
Go
3
star
16

shush-wifi

Java
3
star
17

Square-OctoCash

Send cash to developers on Github with Square Cash
JavaScript
3
star
18

ln

[deprecated] Ln, a more natural Log.
Java
3
star
19

go-pointers

Go
3
star
20

pvt

Java
2
star
21

rxjava-reject

Sample reject operator for RxJava
Java
2
star
22

cron

Cron library for Go.
Go
2
star
23

vogar

Unofficial mirror of Vogar from AOSP
Java
2
star
24

Stopwatch

simple android timer
Java
2
star
25

robin

Schedulers with Android specific functionality.
Java
2
star
26

IFTTW

Repo for If This Then What, built at the Startup Edmonton Hackathon
Shell
2
star
27

go-instapaper

Instapaper API Client for Go.
Go
2
star
28

interfeys

Go
1
star
29

DiLaurentis

Pretty print JSON documents.
Go
1
star
30

bee

Print the spelling alphabet of a word.
Go
1
star
31

go-github-utils

Go
1
star
32

DrinkBot

WIP
Java
1
star
33

hickson

Go
1
star
34

DashTimer

Java
1
star
35

polygot

Count your Github activity by language.
Go
1
star
36

go-executor

Go
1
star
37

github-webhook-server

Go
1
star
38

titan

Time Units for Swift
Swift
1
star
39

clock

Go
1
star
40

github-gender-stats

Print gender stats for any github org
Go
1
star
41

palette-previewer

Quickly preview colors generated by Palette
Java
1
star