Slide 1

Slide 1 text

I do not read..I’ll just ask someone what’s new on Android Android Pitfalls and Anti-patterns Jigar Brahmbhatt I do not read..I’ll just ask someone what’s new on Android I read your blog…it’s fantastic…can you share your source code so I can copy paste ? I don’t know enough Java, but I would love to do Android development Is this already available in Support Library ? Since When? Just making this Context static to get work done! Will remove it later What is AsyncLayoutInflater ? velopment move it later Oh yeah! I know what is abstraction in OOPS! Got full marks in college exam What do you mean by “context is leaking” ? Oh it’s an easy fix! Let me just put a NULL check before it Hey dude, don’t worry about Android lint! bunch of warnings huah! Dead code ! Dead code! Dead code! How to freaking know when my user is online and offline ? PM requirement! android:screenOrientation=“portrait" Yay! doSomething(null, null, true, null, false) Javadoc ? Who’s gonna read? public static String MY_GLOBAL_STRING = “”; ne ? PM requirement! I don’t know enough Java, but I would love to do Android development Is this already available in Support Library ? Since When? Just making this Context static to get work done! Will remove it later Oh yeah! I know what is abstraction in OOPS! Got full marks in college exam What do you mean by “context is leaking” ? Oh it’s an easy fix! Let me just put a NULL check before it Dead code ! Dead code! Dead code! Javadoc ? Who’s gonna read? public static String MY_GLOBAL_STRING = “”; ine ? PM requirement! BOOT_COMPLETED Code reviews ? YAGNI “Don’t Repeat Yourself” What is AsyncLayoutInflater ? d development @jabbar_jigariyo

Slide 2

Slide 2 text

Objective Conferences are not about teaching specifics, but all about inspiring and enlightening At work, one may find a guide or mentor, but at the end everything depends on self-learning 2

Slide 3

Slide 3 text

Kind of pitfalls! 1.Business / Product Notification spamming, tracking user location etc. 3

Slide 4

Slide 4 text

Kind of pitfalls! 1.Business / Product 2.UI / UX No Material design, iOS look-n-feel, not user-friendly etc 4

Slide 5

Slide 5 text

Kind of pitfalls! 1.Business / Product 2.UI / UX 3.Team / Environment No -> code review, continuous integration, code style etc. 5

Slide 6

Slide 6 text

Kind of pitfalls! 1.Business / Product 2.UI / UX 3.Team / Environment 4.Engineer / Developer Let’s talk about them today! 6

Slide 7

Slide 7 text

# 1 Language Problem 7

Slide 8

Slide 8 text

# 1 Language Problem 8 ‣ Android is a framework, not language ‣ Excitement for Android without understanding Java (recent grads) ‣ Knowledge of OOPS, but don’t utilize ‣ Poor or lack of understanding related to design patterns

Slide 9

Slide 9 text

editText.addTextChangedListener(new TextWatcher() {
 @Override
 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 
 }
 
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // process the text, and do something
 }
 
 @Override
 public void afterTextChanged(Editable s) {
 
 }
 }); public abstract class MyBaseTextWatcher implements TextWatcher {
 @Override
 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 // Do nothing
 }
 
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // Do nothing
 }
 
 @Override
 public void afterTextChanged(Editable s) {
 // Do nothing
 }
 } Example: Utilizing OOPS concepts

Slide 10

Slide 10 text

public abstract class MyBaseTextWatcher implements TextWatcher {
 @Override
 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 // Do nothing
 }
 
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // Do nothing
 }
 
 @Override
 public void afterTextChanged(Editable s) {
 // Do nothing
 }
 } editText.addTextChangedListener(new MyBaseTextWatcher() {
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // process the text, and do something
 }
 });

Slide 11

Slide 11 text

public abstract class MyBaseTextWatcher implements TextWatcher {
 @Override
 public void beforeTextChanged(CharSequence s, int start, int count, int after) {
 // Do nothing
 }
 
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // Do nothing
 }
 
 @Override
 public void afterTextChanged(Editable s) {
 // Do nothing
 }
 } editText.addTextChangedListener(new MyBaseTextWatcher() {
 @Override
 public void onTextChanged(CharSequence s, int start, int before, int count) {
 // process the text, and do something
 }
 });

Slide 12

Slide 12 text

Example: Solving a problem with better design pattern public enum PaymentType {
 PAYTM, FREECHARGE
 }
 
 public void pay(PaymentType paymentType, String phone) {
 if(paymentType == PaymentType.PAYTM) {
 // process with paytm using phone
 } else {
 // process with freecharge using phone
 }
 }
 
 // calling method
 paymentHelper.pay(PaymentType.PAYTM, "9999900000");

Slide 13

Slide 13 text

Example: Solving a problem with better design pattern public enum PaymentType {
 PAYTM, FREECHARGE
 }
 
 public void pay(PaymentType paymentType, String phone) {
 if(paymentType == PaymentType.PAYTM) {
 // process with paytm using phone
 } else {
 // process with freecharge using phone
 }
 }
 
 // calling method
 paymentHelper.pay(PaymentType.PAYTM, "9999900000");

Slide 14

Slide 14 text

// if freecharge, email is required
 public void pay(PaymentType paymentType, String phone, String email) throws IllegalStateException {
 if(paymentType == PaymentType.PAYTM) {
 // process with paytm using phone
 } else if(!TextUtils.isEmpty(email)){
 // process with freecharge using phone and email
 } else {
 // error state because payment type is // freecharge but email is null or empty
 throw new IllegalStateException("blah blah");
 }
 }
 
 // calling method
 try {
 paymentHelper.pay(PaymentType.PAYTM, "9999900000", null);
 } catch(IllegalStateException e) {
 // catch
 } // calling method
 try {
 paymentHelper.pay(PaymentType.FREECHARGE, "9999900000", “[email protected]”);
 } catch(IllegalStateException e) {
 // catch
 }

Slide 15

Slide 15 text

// if freecharge, email is required
 public void pay(PaymentType paymentType, String phone, String email) throws IllegalStateException {
 if(paymentType == PaymentType.PAYTM) {
 // process with paytm using phone
 } else if(!TextUtils.isEmpty(email)){
 // process with freecharge using phone and email
 } else {
 // error state because payment type is // freecharge but email is null or empty
 throw new IllegalStateException("blah blah");
 }
 }
 
 // calling method
 try {
 paymentHelper.pay(PaymentType.PAYTM, "9999900000", null);
 } catch(IllegalStateException e) {
 // catch
 } // calling method
 try {
 paymentHelper.pay(PaymentType.FREECHARGE, "9999900000", “[email protected]”);
 } catch(IllegalStateException e) {
 // catch
 }

Slide 16

Slide 16 text

public enum PaymentType {
 PAYTM, FREECHARGE, BLAH, BLAH2.....
 }
 
 public void pay(PaymentType paymentType, String phone, String email, .......) 
 throws IllegalStateException {
 switch (paymentType) {
 case PAYTM:
 // check for phone number
 break;
 case FREECHARGE:
 // check for phone and email, or fail
 break;
 ..........
 ..........
 }
 }
 
 // calling method
 try {
 paymentHelper.pay(PaymentType.PAYTM, "9999900000", null, ......);
 } catch(IllegalStateException e) {
 // catch
 }

Slide 17

Slide 17 text

public enum PaymentType {
 PAYTM, FREECHARGE, BLAH, BLAH2.....
 }
 
 public void pay(PaymentType paymentType, String phone, String email, .......) 
 throws IllegalStateException {
 switch (paymentType) {
 case PAYTM:
 // check for phone number
 break;
 case FREECHARGE:
 // check for phone and email, or fail
 break;
 ..........
 ..........
 }
 }
 
 // calling method
 try {
 paymentHelper.pay(PaymentType.PAYTM, "9999900000", null, ......);
 } catch(IllegalStateException e) {
 // catch
 }

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Strategy Pattern ??

Slide 20

Slide 20 text

Strategy Pattern ?? public interface PaymentStrategy {
 void pay(int amount);
 } public class PaytmStrategy implements PaymentStrategy {
 
 final String phone;
 
 public PaytmStrategy(String phone) {
 this.phone = phone;
 }
 
 @Override
 public void pay(int amount) {
 // make payment using phone
 }
 }

Slide 21

Slide 21 text

Strategy Pattern ?? public interface PaymentStrategy {
 void pay(int amount);
 } public class PaytmStrategy implements PaymentStrategy {
 
 final String phone;
 
 public PaytmStrategy(String phone) {
 this.phone = phone;
 }
 
 @Override
 public void pay(int amount) {
 // make payment using phone
 }
 }

Slide 22

Slide 22 text

public class FreechargeStrategy implements PaymentStrategy {
 
 final String phone;
 final String email;
 
 public FreechargeStrategy(String phone, String email) {
 this.phone = phone;
 this.email = email;
 }
 
 @Override
 public void pay(int amount) {
 // make payment using phone and email
 }
 } // Calling methods
 new PaytmStrategy("9090909090").pay(125);
 
 new FreechargeStrategy("9090909090", "[email protected]").pay(123);

Slide 23

Slide 23 text

public class FreechargeStrategy implements PaymentStrategy {
 
 final String phone;
 final String email;
 
 public FreechargeStrategy(String phone, String email) {
 this.phone = phone;
 this.email = email;
 }
 
 @Override
 public void pay(int amount) {
 // make payment using phone and email
 }
 } // Calling methods
 new PaytmStrategy("9090909090").pay(125);
 
 new FreechargeStrategy("9090909090", "[email protected]").pay(123);

Slide 24

Slide 24 text

public class FreechargeStrategy implements PaymentStrategy {
 
 final String phone;
 final String email;
 
 public FreechargeStrategy(String phone, String email) {
 this.phone = phone;
 this.email = email;
 }
 
 @Override
 public void pay(int amount) {
 // make payment using phone and email
 }
 } // Calling methods
 new PaytmStrategy("9090909090").pay(125);
 
 new FreechargeStrategy("9090909090", "[email protected]").pay(123);

Slide 25

Slide 25 text

25 # 2 Copying without understanding

Slide 26

Slide 26 text

26 Stack Overflow Tech blogs / Medium Google+ YouTube videos Conferences Github Slack groups # 2 Copying without understanding

Slide 27

Slide 27 text

27 ‣ FragmentTransaction.commitAllowingStateLoss();

Slide 28

Slide 28 text

28 ‣ FragmentTransaction.commitAllowingStateLoss(); This is dangerous because the commit can be lost if the activity needs to later be restored from its state, so this should only be used for cases where it is okay for the UI state to change unexpectedly on the user.

Slide 29

Slide 29 text

29 ‣ android:screenOrientation=“portrait” (anti-pattern)

Slide 30

Slide 30 text

30 ‣ android:screenOrientation=“portrait” (anti-pattern)

Slide 31

Slide 31 text

31 ‣ android.intent.action.BOOT_COMPLETED (anti-pattern)

Slide 32

Slide 32 text

# 3 I don’t read problem!

Slide 33

Slide 33 text

IF YOU’RE NOT READING..WE’RE NOT HIRING YOU!!!!!! @Haptik # 3 I don’t read problem!

Slide 34

Slide 34 text

‣ Old APIs == no bug fixes, no new features IF YOU’RE NOT READING..WE’RE NOT HIRING YOU!!!!!! @Haptik

Slide 35

Slide 35 text

‣ Old APIs == no bug fixes, no new features ‣ Can’t provide useful input if you’re not up-to-date IF YOU’RE NOT READING..WE’RE NOT HIRING YOU!!!!!! @Haptik

Slide 36

Slide 36 text

‣ Old APIs == no bug fixes, no new features ‣ Can’t provide useful input if not up-to-date ‣ Writing unnecessary code because you don’t know what is already available IF YOU’RE NOT READING..WE’RE NOT HIRING YOU!!!!!! @Haptik

Slide 37

Slide 37 text

‣ Old APIs == no bug fixes, no new features ‣ Can’t provide useful input if not up-to-date ‣ Writing unnecessary code because you don’t know what is already available if(phone != null && !phone.isEmpty()) { // Do something } IF YOU’RE NOT READING..WE’RE NOT HIRING YOU!!!!!! @Haptik

Slide 38

Slide 38 text

‣ Old APIs == no bug fixes, no new features ‣ Can’t provide useful input if not up-to-date ‣ Writing unnecessary code because you don’t know what is already available if(phone != null && !phone.isEmpty()) {}
 
 // instead of “android.text.TextUtils"
 if(!TextUtils.isEmpty(phone)) { // phone is ready to use } IF YOU’RE NOT READING..WE’RE NOT HIRING YOU!!!!!! @Haptik

Slide 39

Slide 39 text

# 4 I only care about final product problem!

Slide 40

Slide 40 text

‣ If you’re sole developer or early stage startup then, you are suffering from spaghetti code everywhere # 4 I only care about final product problem!

Slide 41

Slide 41 text

// Commented out below method! It’s not working out // // public void thisMethodIsNotWorking(String phone) {
 // this.phone = phone;
 //
 // if(phone != null && !phone.isEmpty()) {
 // Something is not working
 // }
 //
 // // instead of
 // if(!TextUtils.isEmpty(phone)) {
 // probably this is not right
 // }
 // } ‣ If you’re sole developer or early stage startup then, you are suffering from spaghetti code everywhere

Slide 42

Slide 42 text

‣ Too many 3rd party libs! Choose wisely Update cycle

Slide 43

Slide 43 text

‣ Too many 3rd party libs! Choose wisely Update cycle Deprecation issue (Classic example —> UniversalImageLoader)

Slide 44

Slide 44 text

‣ Too many 3rd party libs! Choose wisely Update cycle Deprecation issue Bugs (React Native)

Slide 45

Slide 45 text

‣ Too many 3rd party libs! Choose wisely Update cycle Deprecation issue Bugs (React Native)

Slide 46

Slide 46 text

‣ Too many 3rd party libs! Choose wisely Update cycle Deprecation issue Bugs Too much utility for your own usage

Slide 47

Slide 47 text

‣ Too many 3rd party libs! Choose wisely Update cycle Deprecation issue Bugs Too much utility for your own usage Size impact (Realm)

Slide 48

Slide 48 text

‣ Too many 3rd party libs! Choose wisely Update cycle Deprecation issue Bugs Too much utility for your own usage Size impact (Realm) You MUST understand how it works

Slide 49

Slide 49 text

Otherwise,

Slide 50

Slide 50 text

# 5 Context Leaking “A small leak will sink a great ship.” - Benjamin Franklin

Slide 51

Slide 51 text

# 5 Context Leaking to having static context anywhere! “A small leak will sink a great ship.” - Benjamin Franklin

Slide 52

Slide 52 text

HPROF Viewer and Analyzer (Java Heap) https://developer.android.com/studio/profile/am-hprof.html

Slide 53

Slide 53 text

Leak Canary by square https://github.com/square/leakcanary ‣ 13th most starred Java repo on Github ‣ Have it running in one of your app flavor

Slide 54

Slide 54 text

# 6 Aah! Let me check for NULL problem!

Slide 55

Slide 55 text

# 6 Let me check for NULL problem! QA/Lead: Hey, there is a crash with “Null Pointer Exception” in Crashlytics! You: Aah, should be an easy fix! Give me a sec!

Slide 56

Slide 56 text

QA/Lead: Hey, there is a crash with “Null Pointer Exception” in Crashlytics! You: Aah, should be an easy fix! Give me a sec! if(view != null) {
 view.doSomething();
 }

Slide 57

Slide 57 text

‣ Avoid allowing NULL in your method arguments ‣ Use method overloading make more appropriate methods ‣ Provide factory methods ‣ Use power of annotations! @Nullable @NonNull

Slide 58

Slide 58 text

@Override
 public void onSuccess() {
 if (progressDialog != null) {
 progressDialog.dismiss();
 }
 } @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 progressDialog = new ProgressDialog(this);
 } YOU: WE’RE SAFE! NULL CHECK ADDED One more example!

Slide 59

Slide 59 text

@Override
 public void onSuccess() {
 if (progressDialog != null) {
 progressDialog.dismiss();
 }
 } @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 progressDialog = new ProgressDialog(this);
 } Fatal Exception: java.lang.IllegalArgumentException: View=com.android.internal.policy.PhoneWindow$DecorView{9c3d915 V.E...... R......D 0,0-1026,348} not attached to window manager at android.view.WindowManagerGlobal.findViewLocked(WindowManagerGlobal.jav a:424) at android.view.WindowManagerGlobal.removeView(WindowManagerGlobal.java: 350) at android.view.WindowManagerImpl.removeViewImmediate(WindowManagerImpl.ja va:116) at android.app.Dialog.dismissDialog(Dialog.java:362) at android.app.Dialog.dismiss(Dialog.java:345)

Slide 60

Slide 60 text

# 7 Lint - Ignorance is not bliss!

Slide 61

Slide 61 text

# 7 Lint - Ignorance is not bliss! ‣ Lint is your best friend! (Part QA too) ‣ Tackle literally every lint warning! If you find a false positive, then suppress it!

Slide 62

Slide 62 text

# 8 Dead code problem!

Slide 63

Slide 63 text

# 8 Dead code problem!

Slide 64

Slide 64 text

# 8 Dead code problem!

Slide 65

Slide 65 text

# 9 APK or AAR size ignorance!

Slide 66

Slide 66 text

# 9 APK or AAR size ignorance! ‣ Drawables (most unoptimized and ignored area, but highest impact on size) ‣ Not utilizing proguard ‣ Model classes vs direct JSON

Slide 67

Slide 67 text

# 9 APK or AAR size ignorance! ‣ Model classes vs direct JSON public class UserCreationResponse {
 String userId;
 String username;
 boolean error;
 
 public String getUserId() {
 return userId;
 }
 
 public String getUsername() {
 return username;
 }
 
 public boolean isError() {
 return error;
 }
 }

Slide 68

Slide 68 text

Ending note! ‣ Aim to understand the code you’re adding! ‣ Make sure that it is easy to understand and readable ‣ Take some time, and learn something new every week

Slide 69

Slide 69 text

Thank you Twitter: @jabbar_jigariyo

Slide 70

Slide 70 text

You MUST aim to read 100% of these websites! https://codelabs.developers.google.com https://github.com/googlesamples https://developer.android.com/guide/index.html https://www.youtube.com/user/androiddevelopers/