Slide 1

Slide 1 text

ANDROID DEVELOPMENT The Right Way

Slide 2

Slide 2 text

JAYSON BASAÑES CTO of Lifebit github.com/shiki

Slide 3

Slide 3 text

http://lifebit.com Available on both iOS and Android LIFEBIT

Slide 4

Slide 4 text

DAVAO CITY CLUBS for iOS and Android

Slide 5

Slide 5 text

Download Lifebit for iOS and Android [email protected] WUT • TOOLS • ESSENTIAL LIBRARIES • BEST PRACTICES

Slide 6

Slide 6 text

Download Lifebit for iOS and Android [email protected] TOOLS

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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' } } }

Slide 9

Slide 9 text

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" } }

Slide 10

Slide 10 text

Download Lifebit for iOS and Android [email protected] GENYMOTION • A lot faster than the Android Emulator • GPS, Battery, Accelerometer • Simpler interface

Slide 11

Slide 11 text

Download Lifebit for iOS and Android [email protected] VERSION CONTROL (GIT) • SourceTree + Bitbucket • History • Collaboration • Multiple build versions • Blame games

Slide 12

Slide 12 text

Download Lifebit for iOS and Android [email protected] CRASHLYTICS • Crash reporting • Logging • Analytics • Distribution

Slide 13

Slide 13 text

Download Lifebit for iOS and Android [email protected] ESSENTIAL LIBRARIES

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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(); }

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

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);

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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);

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

Download Lifebit for iOS and Android [email protected] ROBOLECTRIC • Unit test framework • Runs outside of the emulator robolectric.org

Slide 27

Slide 27 text

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!")); } }

Slide 28

Slide 28 text

Download Lifebit for iOS and Android [email protected] BEST PRACTICES

Slide 29

Slide 29 text

Download Lifebit for iOS and Android [email protected] Aim for the latest Android version

Slide 30

Slide 30 text

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

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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.** *; }

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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.

Slide 35

Slide 35 text

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 bits = service.getBits(); // Do something with bits } }

Slide 36

Slide 36 text

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 bits = getService().getBits(); // Do something with bits } }

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

Download Lifebit for iOS and Android [email protected] Know when to use background threads private class DownloadFilesTask extends AsyncTask { 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);

Slide 39

Slide 39 text

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); } } }

Slide 40

Slide 40 text

Download Lifebit for iOS and Android [email protected] Please do not ignore exceptions! try { List 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()); }

Slide 41

Slide 41 text

Download Lifebit for iOS and Android [email protected]

Slide 42

Slide 42 text

Download Lifebit for iOS and Android [email protected] Please do not ignore exceptions! try { List 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

Slide 43

Slide 43 text

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 bits = service.getBits(); ... }

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

Download Lifebit for iOS and Android [email protected] Please do not ignore exceptions! Log to Crashlytics try { List bits = service.getBits(); ... } catch (APIException e) { Crashlytics.logException(e); ! showDialog(e.getMessage()); }

Slide 46

Slide 46 text

Download Lifebit for iOS and Android [email protected] Enforced Coding Style • Everyone can read everyone’s shit • Unity through uniformity • Automate!

Slide 47

Slide 47 text

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

Slide 48

Slide 48 text

Download Lifebit for iOS and Android [email protected] Find a Mentor • a.k.a. “Gamitan” • Pay it forward

Slide 49

Slide 49 text

Download Lifebit for iOS and Android [email protected] lastly

Slide 50

Slide 50 text

Download Lifebit for iOS and Android [email protected] Don’t believe everything that I just said.

Slide 51

Slide 51 text

Download Lifebit for iOS and Android [email protected]

Slide 52

Slide 52 text

Download Lifebit for iOS and Android [email protected]

Slide 53

Slide 53 text

Download Lifebit for iOS and Android [email protected]

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

Download Lifebit for iOS and Android [email protected] GLHF! Slides will be up at speakerdeck.com/shiki