[Ultracode Munich #4] Short introduction to the new Android build system including Android Studio, Roboguice and Robolectric
Upcoming SlideShare
Loading in...5
×

Like this? Share it with your network

Share

[Ultracode Munich #4] Short introduction to the new Android build system including Android Studio, Roboguice and Robolectric

  • 1,007 views
Uploaded on

By Thomas Endres & Andres Würl both Senior Consultant from TNG Technology Consulting https://www.tngtech.com ...

By Thomas Endres & Andres Würl both Senior Consultant from TNG Technology Consulting https://www.tngtech.com

Join the Ultracode Munich meetup: http://www.meetup.com/Ultracode-Munich/

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,007
On Slideshare
521
From Embeds
486
Number of Embeds
7

Actions

Shares
Downloads
11
Comments
0
Likes
2

Embeds 486

http://lanyrd.com 246
http://blog.bemyapp.com 125
http://www.wearear.de 104
http://plus.url.google.com 5
http://cloud.feedly.com 4
http://www.feedspot.com 1
https://www.google.de 1

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. New Android build system Flavored with Roboguice and Robolectric Andreas Würl, Thomas Endres Ultracode Meetup, 2013-11-13
  • 2. Overview A short introduction New Android build system Roboguice Robolectric
  • 3. The speakers Andreas Würl is an IT consultant for TNG Technology consulting currently working in Unterföhring. In his free time, he is contributing to the Blitzortung app available for Android and in development for iOS. Thomas Endres is also an IT consultant for TNG Technology consulting. In his free time, he is developing software for controlling drones with bare hands, building apps and contributing to HTML5 frameworks.
  • 4. Our apps Blitzortung Simple to use map based application visualizing real time lightning data provided by blitzortung.org. The current thunderstorm situation at your fingertips. Be Quiet - The noise alert Whether you work in an office or in a class room, Be Quiet will help you reduce noise. When the volume is too high, it will blink and play a siren sound.
  • 5. Overview A short introduction New Android build system Roboguice Robolectric
  • 6. Building Android applications Old school Based on Ant No built-in dependency management Quite inflexible Using old built-in library versions No support for real unit tests Test project needed for instrumentation tests
  • 7. The build xml file <target name="compile" depends="-resource-src, -aidl" description="Compiles project's .java files into .class files"> <!-- ... --> <javac encoding="ascii" target="1.5" debug="true" extdirs="" destdir="${out.classes.absolute.dir}" bootclasspathref="android.target.classpath" verbose="${verbose}" classpath="${extensible.classpath}" classpathref="android.libraries.jars"> <src path="${source.absolute.dir}" /> <src path="${gen.absolute.dir}" /> <src refid="android.libraries.src" /> <classpath> <fileset dir="${external.libs.absolute.dir}" includes="*.jar" /> <fileset dir="${extensible.libs.classpath}" includes="*.jar" /> </classpath> </javac> </target> Customization is very difficult
  • 8. Building Android applications The alternative Based on Maven → Maven plugin Allows for dependency management A lot more flexible → But still far from being perfect Real unit tests are possible Still using a test project for instrumentation tests
  • 9. The POM file <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.tngtech.internal.android</groupId> <artifactId>android-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>apk</packaging> <dependencies> <dependency> <groupId>com.google.android</groupId> <artifactId>android</artifactId> <version>${platform.version}</version> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>com.jayway.maven.plugins.android.generation2</groupId> <artifactId>android-maven-plugin</artifactId> <version>3.7.0</version> <configuration> <androidManifestFile>${project.basedir}/AndroidManifest.xml</androidManifestFile> <assetsDirectory>${project.basedir}/assets</assetsDirectory> <resourceDirectory>${project.basedir}/res</resourceDirectory> <sdk><platform>18</platform></sdk> </configuration> </plugin> </plugins> </build> </project>
  • 10. Building Android applications The new way Based on Gradle → Gradle-Plugin Built-in dependency management Using common Java patterns → But flexible enough to change that Real unit tests through plugins Instrumentation tests within the same project
  • 11. The Gradle build file buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' } } apply plugin: 'android' repositories { mavenCentral() } dependencies { // Put all dependencies here } android { compileSdkVersion 18 buildToolsVersion "18.1.1" defaultConfig { minSdkVersion 18 targetSdkVersion 18 } }
  • 12. Android Studio
  • 13. Android Studio The facts Based on IntelliJ Ready to use No additional plugins needed Brings shortcuts for AVD and SDK manager Out of the box support for the new build system Possibility to migrate old projects
  • 14. Overview A short introduction New Android build system Roboguice Robolectric
  • 15. What the heck is Roboguice? A dependency injection container An implementation of JSR 330 A fork of the Guice framework for the JDK Easy to configure and to use
  • 16. Dependency injection Instead of taking public class MainActivity extends Activity{ private LocationManager locationManager; public void onCreate(Bundle savedInstance) { // ... locationManager = (LocationManager) getSystemService(Activity.LOCATION_SERVICE); } } be given public class MainActivity extends RoboActivity{ @Inject private LocationManager locationManager; public void onCreate(Bundle savedInstance) { // ... } }
  • 17. Principles of DI Don't let a class create objects on its own Instead, pass them the objects they need Then you can exchange them for test purposes You can pass in test doubles But you can also exchange the "real" object easily Loose coupling becomes a reality
  • 18. How can you inject objects? Through the constructor: @Inject public MainActivity(LocationManager locationManager) { // ... this.locationManager = locationManager; } Into the field itself: @Inject private LocationManager locationManager; Into a property: @Inject public void setLocationManager(LocationManager locationManager) { this.locationManager = locationManager; }
  • 19. What can be injected? Arbitrary objects with a zero-arg constructor Objects with a constructor managed by Roboguice Views: @InjectView(R.id.specialButton) private Button button; Resources: @InjectResource(R.drawable.specialPicture) private Drawable picture; A lot of standard Android objects: LocationManager, AssetManager, ... AlarmManager, NotificationManager, ... Vibrator
  • 20. Robo* classes For DI to work, you have to extend the robo classes: Use them instead of the standard Android classes RoboActivity instead of Activity RoboListActivity instead of ListActivity RoboService instead of Service RoboFragment instead of Fragment ...
  • 21. Injecting providers: Sometimes, you need more than one object of a class public class SomeObjectProvider implements Provider<SomeObject> { @Inject private SomeOtherObject someOtherObject; @Override public SomeObject get() { return new SomeObject(someOtherObject); } } private class SomeObjectUser { @Inject private Provider<SomeObject> someObjectProvider; private SomeObject getObject() { return someObjectProvider.get(); } }
  • 22. Injecting injectors You can also inject an injector Then, you can get arbitrary objects out of the injector @Inject private Injector injector; public <T> T giveMeAnObjectOf(Class<T> clazz) { return injector.getInstance(clazz); }
  • 23. Configuration By defining a module, you can configure the objects injected public class SomeModule extends AbstractModule { @Override public void configure() { // Bind an interface to a specific class bind(SomeInterface.class).to(SomeImplementation.class); // Bind a standard provider to the class bind(SomeClass.class).toProvider(SomeClassProvider.class); } } Modules are discovered via "roboguice_modules.xml" <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="roboguice_modules"> <item>com.mypackage.SomeModule</item> </string-array> </resources>
  • 24. Integrate Roboguice (1) Add roboguice to the compile dependencies: // build.gradle dependencies { // ... compile 'roboguice:roboguice:2.+' } Extend the Robo* classes in your objects: public class SomeActivity extends RoboActivity { // ... } Inject your dependencies: @Inject private SomeObject someObject;
  • 25. Integrate Roboguice (2) Configure the module: public class SomeModule extends AbstractModule { @Override protected void configure() { bind(SomeClass.class).toProvider(SomeClassProvider.class); // ... } } Register the module: <?xml version="1.0" encoding="utf-8"?> <resources> <string-array name="roboguice_modules"> <item>com.mypackage.SomeModule</item> </string-array> </resources> Write unit tests: public class SomeActivityTest { // How to do that? }
  • 26. Overview A short introduction New Android build system Roboguice Robolectric
  • 27. Android testing in new build system Based on JUnit3 Requires separate test project Requires emulator or device for execution Lacks real mocking But initial support for some frameworks
  • 28. Can I run tests locally? No. It's impossible! Any method of the SDK will throw the following exception when called: java.lang.RuntimeException: Stub! at android.* Why is that? Android SDK jars for development only contain method stubs Is there a solution? Yes! Use Robolectric
  • 29. What the heck is Robolectric? Android SDK wrapper/enabler for local test execution Just another dependency of your project Sometimes dependency order is important Uses some magic to enable use of the stubbed SDK jars Unfortunately not yet complete
  • 30. What do I get? Tests are running on the dev machine Current version of JUnit 4 is used Any Mock- or Match-Framework can be used Can be used in parallel with instrumentation tests
  • 31. How do I enable Robolectric? buildscript { repositories { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.6.+' classpath 'com.squareup.gradle:gradle-android-test-plugin:0.9.+' } } apply plugin: 'android' apply plugin: 'android-test' ...
  • 32. How do I implement a test? Just use the RobolectricTestRunner @RunWith(RobolectricTestRunner.class) class SomeActivityTest { @Before public void setUp() { // Preparation for every test } @Test public void testSomething() { // Your test code belongs here assertThat(1, is(not(2)); } }
  • 33. Basic concepts Shadows TextView textView = (TextView) mainActivity.findViewById(R.id.helloWorld); final ShadowTextView shadowTextView = Robolectric.shadowOf(textView); assertThat(shadowTextView.innerText(), is("Hello World!")); Implementation in Robolectric @Implements(TextView.class) public class ShadowTextView extends ShadowView { @RealObject TextView realTextView; @Override public String innerText() { CharSequence text = realTextView.getText(); return (text == null || realTextView.getVisibility() != View.VISIBLE) ? "" : text.toString(); } @Implementation public void setPaintFlags(int paintFlags) { this.paintFlags = paintFlags; } }
  • 34. Basic concepts Robolectric builds up a full application context Activities can be built activity = Robolectric.buildActivity(MainActivity.class).create().get(); Testing resource access is possible as well Resources resources = Robolectric.application.getResources(); assertThat(resources.getColor(R.color.Red), is(0xffff0000)); Modify preferences for tests SharedPreferences defaultSharedPreferences = ShadowPreferenceManager.getDefaultSharedPreferences( Robolectric.application); defaultSharedPreferences.edit() .putBoolean("test", true).putFloat("limit", 1.0f).apply();
  • 35. But ... Android Studio integration is not yet available Tests can be run via gradle task 'test' > gradle test IDE support only through ugly hacks
  • 36. Summary The new build system is a lot more flexible than the old one Android Studio is a cool new tool for app development It comes bundled with the SDK, you can start development immediately But there are still some issues with it Roboguice makes it possbible to decouple your application Robolectric can be used for local test execution
  • 37. Thank you! Are there any questions? andreas.wuerl@tngtech.com, thomas.endres@tngtech.com