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

[Droidcon Berlin '17] Things I wish I knew when...

[Droidcon Berlin '17] Things I wish I knew when I started building Android sdk/libraries

As more and more people start building Android Libraries, the whole process of building a better API for developers is getting bloated and everyone is coming up with their own ideas. However, if android library developers follow a certain standard with a rationale they can avoid most of the pitfalls. Building an android library is easy, but building one that keeps in mind developer happiness is rare but definitely not hard. The session would cover how one can build android libraries taking in consideration to exposing more informative API, making sure the best resources are utilized efficiently and that one does not force the app developer with redundant dependencies and complexities.

Animated Gif Version: https://goo.gl/WNeR4A

Video: https://www.youtube.com/watch?v=RAZEIrmtUPo

Link to blog post: https://android.jlelse.eu/things-i-wish-i-knew-when-i-started-building-android-sdk-libraries-dba1a524d619

Sketchnotes by:
Chiu-Ki Chan: https://twitter.com/chiuki/status/905046880723329024
Garima Jain: https://twitter.com/ragdroid/status/905053186318368770
Miriam Busch: https://twitter.com/miphoni/status/905174390312239105

Nishant Srivastava

September 05, 2017
Tweet

More Decks by Nishant Srivastava

Other Decks in Technology

Transcript

  1. Things I wish I knew when I started building android

    SDK/libraries Nishant Srivastava
  2. Android Library is... <secret ingredient> + <secret ingredient> + <secret

    ingredient> = <Android Library> @nisrulz #droidconDE
  3. Android Library is... Java code + <secret ingredient> + <secret

    ingredient> = <Android Library> @nisrulz #droidconDE
  4. Android Library is... Java code + Android resources + <secret

    ingredient> = <Android Library> @nisrulz #droidconDE
  5. Android Library is... Java code + Android resources + Android

    Manifest stub = <Android Library> @nisrulz #droidconDE
  6. Android Library is... Java code + Android resources + Android

    Manifest stub = Android ARchive (AAR) @nisrulz #droidconDE
  7. Why create an Android Library? Short Answer You don’t have

    to… ...unless a solution already exists. Then use that. @nisrulz #droidconDE
  8. Avoid multiple arguments // Do not DO this void init(String

    apikey, int refresh, long interval, String type, String username, String email, String password); @nisrulz #droidconDE
  9. Avoid multiple arguments // Do not DO this void init(String

    apikey, int refresh, long interval, String type, String username, String email, String password); // WHY? void init(“0123456789”,“prod”, 1000, 1, “nishant”, ”1234”, “[email protected]”); // Passing arguments in right order is easy to mess up here :( @nisrulz #droidconDE
  10. Avoid multiple arguments // Do this void init(ApiSecret apisecret); //

    where ApiSecret is public class ApiSecret{ String apikey; int refresh; long interval; String type; String name; String email; String pass; // constructor // validation checks(such as type safety) // setter and getters } @nisrulz #droidconDE
  11. Avoid multiple arguments // Or use Builder Pattern AwesomeLib awesomelib

    = new AwesomeLib.AwesomeLibBuilder() .apisecret(mApisecret).refresh(mRefresh) .interval(mInterval).type(mType) .username(mUsername).email(mEmail).password(mPassword) .build(); } @nisrulz #droidconDE
  12. Minimize Permissions Use intents Reduce req. permissions Check permission, use

    fallbacks public boolean hasPermission(Context context, String permission) { int result = context.checkCallingOrSelfPermission(permission); return result == PackageManager.PERMISSION_GRANTED; } @nisrulz #droidconDE
  13. Minimize Feature Requisite // Do not do this <uses-feature android:name="android.hardware.bluetooth"

    /> // Runtime feature detection String feature = PackageManager.FEATURE_BLUETOOTH; public boolean isFeatureAvailable(Context context, String feature) { return context.getPackageManager().hasSystemFeature(feature); } // Enable/Disable the functionality depending on availability of feature @nisrulz #droidconDE
  14. Support different versions // RULE OF THUMB : Support the

    full spectrum of android versions @nisrulz #droidconDE
  15. Support different versions // RULE OF THUMB : Support the

    full spectrum of android versions android { ... defaultConfig { .. minSdkVersion 9 targetSdkVersion 26 .. } } @nisrulz #droidconDE
  16. Support different versions // How?? : Detect version and Enable/Disable

    features or use // a fallback @nisrulz #droidconDE
  17. Support different versions // How?? : Detect version and Enable/Disable

    features or use // a fallback public boolean isOreoAndAbove(){ return Build.VERSION.SDK_INT>= Build.VERSION_CODES.O; } @nisrulz #droidconDE
  18. Don’t log in production ...but log exceptions/errors Provide flagged logging

    support AwesomeLibrary.init(apisecret,BuildConfig.DEBUG); @nisrulz #droidconDE
  19. Don’t log in production // Provide flexibility to log when

    debug flag is true void init(ApiSecret apisecret,boolean debuggable){ try{ ... } catch(Exception ex){ if (debuggable){ // This is printed only when debuggable is true ex.printStackTrace(); } } } @nisrulz #droidconDE
  20. Don’t log in production // Provide flexibility to log when

    debug flag is true void init(ApiSecret apisecret,boolean debuggable){ try{ ... } catch(Exception ex){ if (debuggable){ // This is printed only when debuggable is true ex.printStackTrace(); } } } @nisrulz #droidconDE
  21. Degrade gracefully on error Do not crash the app Disable

    feature/functionality @nisrulz #droidconDE
  22. Catch specific exception // Do not do this try {

    // ... } catch(Exception e) { // ... } @nisrulz #droidconDE
  23. Catch specific exception // Do this try { // ...

    } catch(IOException e) { // ... } @nisrulz #droidconDE
  24. Handle poor network conditions Acknowledge unreliable network exists Batch network

    calls Prefetch data ahead of time @nisrulz #droidconDE
  25. Handle poor network conditions Acknowledge unreliable network exists Batch network

    calls Prefetch data ahead of time Use better data structures such as flatbuffers @nisrulz #droidconDE
  26. Require min dependencies Let the app developer make the decision

    about inclusion AwesomeLib module: dependencies { // Gradle v2.12 and below provided 'com.squareup.retrofit2:retrofit:2.1.0' // Gradle v2.12+ compileOnly 'com.squareup.retrofit2:retrofit:2.1.0' } @nisrulz #droidconDE
  27. Require min dependencies Let the app developer make the decision

    about inclusion AwesomeLib module: dependencies { // Gradle v2.12 and below provided 'com.squareup.retrofit2:retrofit:2.1.0' // Gradle v2.12+ compileOnly 'com.squareup.retrofit2:retrofit:2.1.0' } @nisrulz #droidconDE
  28. Require min dependencies Let the app developer make the decision

    about inclusion App module: dependencies { // ... implementation 'com.squareup.retrofit2:retrofit:2.1.0' } @nisrulz #droidconDE
  29. Require min dependencies Enable/Disable feature based on availability private boolean

    hasRetrofitOnClasspath() { try { Class.forName("retrofit2.Retrofit"); return true; } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return false; } @nisrulz #droidconDE
  30. Require min dependencies Enable/Disable feature based on availability private boolean

    hasRetrofitOnClasspath() { try { Class.forName("retrofit2.Retrofit"); return true; } catch (ClassNotFoundException ex) { ex.printStackTrace(); } return false; } @nisrulz #droidconDE
  31. Lifecycle Arch Components public class AwesomeLib implements LifecycleObserver{ @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public

    void executeFnOnCreate(){ // do something on create } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void cleanup(){ // do some cleanup tasks } } @nisrulz #droidconDE
  32. Lifecycle Arch Components public class AwesomeLib implements LifecycleObserver{ @OnLifecycleEvent(Lifecycle.Event.ON_CREATE) public

    void executeFnOnCreate(){ // do something on create } @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY) public void cleanup(){ // do some cleanup tasks } } @nisrulz #droidconDE
  33. Lifecycle Arch Components public class MainActivity extends LifecycleActivity { AwesomeLib

    awesomeLib; @Override protected void onCreate(Bundle savedInstanceState) { // .. awesomeLib = new AwesomeLib(); getLifecycle().addObserver(awesomeLib); } @Override protected void onDestroy() { // ... getLifecycle().removeObserver(awesomeLib); } } @nisrulz #droidconDE
  34. Lifecycle Arch Components public class MainActivity extends LifecycleActivity { AwesomeLib

    awesomeLib; @Override protected void onCreate(Bundle savedInstanceState) { // .. awesomeLib = new AwesomeLib(); getLifecycle().addObserver(awesomeLib); } @Override protected void onDestroy() { // ... getLifecycle().removeObserver(awesomeLib); } } @nisrulz #droidconDE
  35. Do not hog the startup You do not need to

    initialize everything, @nisrulz #droidconDE
  36. Do not hog the startup You do not need to

    initialize everything, Try to do lazy initialization @nisrulz #droidconDE
  37. Remove functionality gracefully /** * @deprecated As of release 2.0,

    replaced by {@link #getPreferredSize()} */ @Deprecated public Dimension preferredSize() { return getPreferredSize(); } @nisrulz #droidconDE
  38. Document everything Provide Readme.md Include javadocs in code Bundle a

    sample app Maintain a changelog http://keepachangelog.com @nisrulz #droidconDE
  39. License is Important /* * Copyright (C) 2016 Nishant Srivastava

    * * 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. */ @nisrulz #droidconDE
  40. Versioning Strategy To make 2 versions coexist, release under a

    new group ID i.e 1.x = io.reactivex:rxjava:x.y.z 2.x = io.reactivex.rxjava2:rxjava:2.x.y @nisrulz #droidconDE
  41. Proguard, wait… what? Proguard rules can be shipped in an

    android library android { ... defaultConfig { ... versionName "1.0.0" ... consumerProguardFiles 'consumer-proguard-rules.pro' } } @nisrulz #droidconDE
  42. Things I wish I knew when I started building android

    SDK/libraries twitter.com/ nisrulz github.com/ nisrulz .com