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

Android Development, the Right Way

Android Development, the Right Way

Current tools, essential libraries, and some best practices. This talk was for Google Developer Group Davao DevFest 2014.

Jayson Basañes

November 15, 2014
Tweet

More Decks by Jayson Basañes

Other Decks in Programming

Transcript

  1. Download Lifebit for iOS and Android [email protected] ANDROID STUDIO (0.8+)

    • Gradle-based build system • Improved Interface Designer • Better code completion and refactoring • Code analysis • Faster in every aspect
  2. Download Lifebit for iOS and Android [email protected] buildscript { repositories

    { mavenCentral() } dependencies { classpath 'com.android.tools.build:gradle:0.12.+' } } apply plugin: 'com.android.application' dependencies { compile 'com.netflix.rxjava:rxjava-core:0.19.1' compile 'com.netflix.rxjava:rxjava-android:0.19.1' compile 'com.squareup.retrofit:retrofit:1.6.1' compile 'com.squareup.okhttp:okhttp-urlconnection:2.0.0' compile 'com.squareup.okhttp:okhttp:2.0.0' } android { compileSdkVersion 19 buildToolsVersion "20.0.0" defaultConfig { minSdkVersion 15 targetSdkVersion 19 versionCode 1 versionName "1.0" } buildTypes { debug { runProguard false } release { signingConfig signingConfigs.release runProguard true proguardFiles 'proguard-rules.pro' } } }
  3. Download Lifebit for iOS and Android [email protected] Build Variants productFlavors

    { demo { applicationId "com.buildsystemexample.app.demo" versionName "1.0-demo" } full { applicationId "com.buildsystemexample.app.full" versionName "1.0-full" } }
  4. Download Lifebit for iOS and Android [email protected] GENYMOTION • A

    lot faster than the Android Emulator • GPS, Battery, Accelerometer • Simpler interface
  5. Download Lifebit for iOS and Android [email protected] VERSION CONTROL (GIT)

    • SourceTree + Bitbucket • History • Collaboration • Multiple build versions • Blame games
  6. Download Lifebit for iOS and Android [email protected] CRASHLYTICS • Crash

    reporting • Logging • Analytics • Distribution
  7. Download Lifebit for iOS and Android [email protected] RETROFIT • REST

    client for Android and Java • Stupidly easy to use. • Uses Gson for JSON parsing square.github.io/retrofit
  8. Download Lifebit for iOS and Android [email protected] RETROFIT public interface

    LifebitService { @GET("/users/{user}/bits") List<Bit> getUserBits(@Path("user") String user); } RestAdapter restAdapter = new RestAdapter.Builder() .setEndpoint("https://api.lifebit.com") .build(); ! LifebitService service = restAdapter.create(LifebitService.class); List<Bit> bits = service.getUserBits(“shiki"); Profit!
  9. Download Lifebit for iOS and Android [email protected] OKHTTP • Efficient

    HTTP Client. Alternative to Apache's HTTPClient and java.net.HttpUrlConnection. • Can be used with Retrofit. • From their site: Perseveres when the network is troublesome square.github.io/okhttp
  10. Download Lifebit for iOS and Android [email protected] OKHTTP OkHttpClient client

    = new OkHttpClient(); ! String run(String url) throws IOException { Request request = new Request.Builder() .url(url) .build(); ! Response response = client.newCall(request).execute(); return response.body().string(); }
  11. Download Lifebit for iOS and Android [email protected] PICASSO • Image

    downloading and caching library. • Automatic memory and disk caching. • Mostly one-liners to load a remote image into an ImageView. • Supports: resizing, cropping, placeholders. • Can use OkHttp square.github.io/picasso
  12. Download Lifebit for iOS and Android [email protected] PICASSO Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView); Picasso.with(context)

    .load(url) .resize(50, 50) .centerCrop() .into(imageView) Picasso.with(context) .load(url) .placeholder(R.drawable.user_placeholder) .error(R.drawable.user_placeholder_error) .into(imageView);
  13. Download Lifebit for iOS and Android [email protected] EVENTBUS OR OTTO

    • publish-subscribe-style communication between components github.com/greenrobot/EventBus or square.github.io/otto
  14. Download Lifebit for iOS and Android [email protected] EVENTBUS public class

    MessageEvent { /* Additional fields if needed */ } EventBus.getDefault().register(this); ! public void onEvent(MessageEvent event) { /* Do something */ }; MessageEvent event = new MessageEvent(); EventBus.getDefault().post(event);
  15. Download Lifebit for iOS and Android [email protected] BUTTER KNIFE •

    View injection • No more findViewById boilerplate jakewharton.github.io/butterknife
  16. Download Lifebit for iOS and Android [email protected] BUTTER KNIFE class

    ExampleActivity extends Activity { TextView title; TextView subtitle; TextView footer; ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); title = (TextView) findViewById(R.id.title); subtitle = (TextView) findViewById(R.id.subtitle); footer = (TextView) findViewById(R.id.footer); } } The old way
  17. Download Lifebit for iOS and Android [email protected] BUTTER KNIFE class

    ExampleActivity extends Activity { @InjectView(R.id.title) TextView title; @InjectView(R.id.subtitle) TextView subtitle; @InjectView(R.id.footer) TextView footer; ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.simple_activity); ButterKnife.inject(this); } } Using injection
  18. Download Lifebit for iOS and Android [email protected] BUTTER KNIFE Events

    @OnClick(R.id.submit) public void sayHi(Button button) { button.setText("Hello!"); }
  19. Download Lifebit for iOS and Android [email protected] ROBOLECTRIC • Unit

    test framework • Runs outside of the emulator robolectric.org
  20. Download Lifebit for iOS and Android [email protected] ROBOLECTRIC @RunWith(RobolectricTestRunner.class) public

    class MyActivityTest { ! @Test public void clickingButton_shouldChangeResultsViewText() throws Exception { Activity activity = Robolectric.buildActivity(MyActivity.class).create().get(); ! Button pressMeButton = (Button) activity.findViewById(R.id.press_me_button); TextView results = (TextView) activity.findViewById(R.id.results_text_view); ! pressMeButton.performClick(); String resultsText = results.getText().toString(); assertThat(resultsText, equalTo("Testing Android Rocks!")); } }
  21. Download Lifebit for iOS and Android [email protected] Beware of the

    65K DEX methods limit Unable to execute dex: method ID not in [0, 0xffff]: 65536 Conversion to Dalvik format failed: Unable to execute dex: method ID not in [0, 0xffff]: 65536 • Choose third-party libraries wisely • Use Proguard if you can’t avoid it
  22. Download Lifebit for iOS and Android [email protected] Use Proguard for

    release builds buildTypes { debug { runProguard false } release { signingConfig signingConfigs.release runProguard true proguardFiles 'proguard-rules.pro' } } • smaller, optimized, obfuscated builds
  23. Download Lifebit for iOS and Android [email protected] # Obfuscation parameters:

    #-dontobfuscate -useuniqueclassmembernames -keepattributes SourceFile,LineNumberTable -allowaccessmodification # Keep Jackson stuff -keep class org.codehaus.** { *; } -keep class com.fasterxml.jackson.annotation.** { *; } # Keep these for GSON and Jackson -keepattributes Signature -keepattributes *Annotation* -keepattributes EnclosingMethod # Keep Retrofit -keep class retrofit.** { *; } -keepclasseswithmembers class * { @retrofit.** *; } -keepclassmembers class * { @retrofit.** *; } # Keep Picasso -keep class com.squareup.picasso.** { *; } -keepclasseswithmembers class * { @com.squareup.picasso.** *; } -keepclassmembers class * { @com.squareup.picasso.** *; }
  24. Download Lifebit for iOS and Android [email protected] Prefer Maven dependencies

    instead of jar files dependencies { compile 'com.squareup.okio:okio:1.0.+' compile 'com.squareup.okhttp:okhttp:2.0.+' ! compile 'com.squareup.retrofit:retrofit:1.7.0' } • ez
  25. Download Lifebit for iOS and Android [email protected] Not Invented Here

    • yet-another-image-loading library • Unless you can make something better in the little time that you have.
  26. Download Lifebit for iOS and Android [email protected] Load heavy objects

    on demand Not class MyActivity extends Activity { private Service service; @Override public void onCreate(Bundle savedInstanceState) { ... service = restAdapter.create(LifebitService.class); } @OnClick(R.id.submit) public void onButtonClick(Button button) { List<Bit> bits = service.getBits(); // Do something with bits } }
  27. Download Lifebit for iOS and Android [email protected] Load heavy objects

    on demand Not Not class MyActivity extends Activity { private Service service; ! Service getService() { if (service == null) { service = restAdapter.create(LifebitService.class); } return service; } ! @OnClick(R.id.submit) public void onButtonClick(Button button) { List<Bit> bits = getService().getBits(); // Do something with bits } }
  28. Download Lifebit for iOS and Android [email protected] Know when to

    use background threads • API calls • Loading files • Anything that’s gonna take more than a second
  29. Download Lifebit for iOS and Android [email protected] Know when to

    use background threads private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> { protected Long doInBackground(URL... urls) { int count = urls.length; long totalSize = 0; for (int i = 0; i < count; i++) { totalSize += Downloader.downloadFile(urls[i]); publishProgress((int) ((i / (float) count) * 100)); // Escape early if cancel() is called if (isCancelled()) break; } return totalSize; } protected void onProgressUpdate(Integer... progress) { setProgressPercent(progress[0]); } protected void onPostExecute(Long result) { showDialog("Downloaded " + result + " bytes"); } } new DownloadFilesTask().execute(url1, url2, url3);
  30. Download Lifebit for iOS and Android [email protected] View Holder Pattern

    public class MyAdapter extends BaseAdapter { @Override public View getView(int position, View view, ViewGroup parent) { ViewHolder holder; if (view != null) { holder = (ViewHolder) view.getTag(); } else { view = inflater.inflate(R.layout.whatever, parent, false); holder = new ViewHolder(view); view.setTag(holder); } holder.name.setText("John Doe"); // etc... return view; } static class ViewHolder { @InjectView(R.id.title) TextView name; @InjectView(R.id.job_title) TextView jobTitle; public ViewHolder(View view) { ButterKnife.inject(this, view); } } }
  31. Download Lifebit for iOS and Android [email protected] Please do not

    ignore exceptions! try { List<Bit> bits = service.getBits(); ... } catch (APIException e) { // Something terrible has happened // but I am too lazy to handle this exception. // So f*ck you users! ! // Logging is not considered handling an exception! Log.d(getClass().getName(), e.getMessage()); }
  32. Download Lifebit for iOS and Android [email protected] Please do not

    ignore exceptions! try { List<Bit> bits = service.getBits(); ... } catch (APIException e) { // If you are sure that the message is safe for the end user: showDialog(e.getMessage()); } Inform the user
  33. Download Lifebit for iOS and Android [email protected] Please do not

    ignore exceptions! Throw it up the call chain private void loadBits() throws APIException { List<Bit> bits = service.getBits(); ... }
  34. Download Lifebit for iOS and Android [email protected] Please do not

    ignore exceptions! Crash that motherf*cker try { List<Bit> bits = service.getBits(); ... } catch (APIException e) { // I am pretty sure that an exception will never happen, // but just in case: throw new RuntimeException(e); }
  35. Download Lifebit for iOS and Android [email protected] Please do not

    ignore exceptions! Log to Crashlytics try { List<Bit> bits = service.getBits(); ... } catch (APIException e) { Crashlytics.logException(e); ! showDialog(e.getMessage()); }
  36. Download Lifebit for iOS and Android [email protected] Enforced Coding Style

    • Everyone can read everyone’s shit • Unity through uniformity • Automate!
  37. Download Lifebit for iOS and Android [email protected] Automated Tests •

    Robolectric, Robotium, whatever floats your boat • Pays off in the long run • Good luck convincing your boss ^_^x
  38. Download Lifebit for iOS and Android [email protected] Find a Mentor

    • a.k.a. “Gamitan” • Pay it forward
  39. Download Lifebit for iOS and Android [email protected] REFERENCES • androidweekly.net:

    Free weekly newsletter for the latest Android dev news, tutorials, articles, etc. • android-arsenal.com: List of free and paid Android libraries • github.com/futurice/android-best-practices: Android dev best practices