O slideshow foi denunciado.
Seu SlideShare está sendo baixado. ×

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

Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Anúncio
Carregando em…3
×

Confira estes a seguir

1 de 42 Anúncio

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

Baixar para ler offline

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/

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/

Anúncio
Anúncio

Mais Conteúdo rRelacionado

Diapositivos para si (20)

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

Anúncio

Mais de BeMyApp (20)

Mais recentes (20)

Anúncio

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

  1. 1. New Android build system Flavored with Roboguice and Robolectric Andreas Würl, Thomas Endres Ultracode Meetup, 2013-11-13
  2. 2. Overview A short introduction New Android build system Roboguice Robolectric
  3. 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. 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. 5. Overview A short introduction New Android build system Roboguice Robolectric
  6. 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. 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. 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. 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. 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. 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. 12. Android Studio
  13. 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. 14. Overview A short introduction New Android build system Roboguice Robolectric
  15. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 26. Overview A short introduction New Android build system Roboguice Robolectric
  27. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 37. Thank you! Are there any questions? andreas.wuerl@tngtech.com, thomas.endres@tngtech.com

×