A good approach to bind layouts in  MVP/MVVM pattern:


When designing a UI , we first design our layouts and according to design strategy we either adopt ConstrainLayout or traditional layouts (such as LinearLayout, RelativeLayouts,FrameLayouts,...) to be inflated by system.

Whatever the binding tool we are using such as ButterKnife or classic findViewByID() ,in our viewmodel or controllers we useualy define our layout's references this way:

  

  public class MyActivity extends AppCompatActivity{

   LinearLayout lnlInfo;

   onCreate(){

      lnlInfo = (LinearLayout)findViewByID()
   }

  }

  

  

   or by using ButterKnife:

   public class MyActivity extends AppCompatActivity{

   @BindView(R.id.lnl_info)
   LinearLayout lnlInfo;

   onCreate(){

      inject()//butterknife

    }

  }


what is wrong with this approach?

In fact nothing everything is binding and working correctly but think about one day that you have to make some changes to your layouts , for example somewher in your xmls you replace your LinearLayout by a RelativeLayout ? or change your entire lyouts using Constantlayouts? what happens?

you see crash and exceptions everywhere, because all your casting kind of

(LinearLayout)findViewByID() or @BindView LinearLayout, will be NULL!! to fix that you have to make changes to all your java/kotlin ViewModels or View Controllers one by one to replace LinearLayout by RelativeLayout or ConstraintLayout or ...etc , this is horrible especially when you're dealing with many number of layouts , the horrible thing here is that every intervention in UI lauout push you to fix codes as well, there is no abstraction between XML and java codes , they are closely coupled and any change from one side push you to apply change to other side, and yes this is not good at all!



How to avoid such situation and decouple XML from Codes:

  1. First of all , you should make sure that you are not using programmatically any method or property specific to that layout ,for example addRule is a method defined in RelativeLayout but not in LinearLayout so if in your codes you have something like

ViewGroup rl = findViewById()

rl.addRule(RelativeLayout.RIGHT_OF, viewID);

you should explicitly cast it with RelativeLayout  in order to use this method  :

(RelativeLayout)rl.addRule(RelativeLayout.RIGHT_OF, viewID);

So we cannot really decouple and there is no a generic solution for that.

but in practice once developers setup thier xml layouts ,they don't configure it programmatically and they rarely use those specific properties/methods and they interact directly with child views (widgets)  instead.


  1. Instead of using a type specific reference use ViewGroup , because it's the parent for all other layouts including ConstraintLayouts , so  instead of :

LinearLayout lnlInfo; 

use this one:

ViewGroup vgInfo;

so your activity looks like:

 public class MyActivity extends AppCompatActivity{

   ViewGroup vgInfo;

   onCreate(){

      vgInfo = findViewByID()=> in V26 casting not required anymore
   }

  }   

   or if using ButterKnife:

   

   public class MyActivity extends AppCompatActivity{

   @BindView(R.id.lnl_info)
   ViewGroup vgInfo;

   onCreate(){

      inject()//butterknife

    }

  }


There is absolutly no any cost for that because when system inflate your layout , prior to load your layouts , It initialize parent ViewGroup in layout class when calling SUPER for example in LinearLayout,we have:

super((Context)null, (AttributeSet)null, 0, 0);


public LinearLayout(Context context, AttributeSet attrs) {

        super((Context)null, (AttributeSet)null, 0, 0);

        throw new RuntimeException("Stub!");

    }



This way you reboost abstraction and decouple XML from Codes , you can easily change your UI without having to change your codes.This approach let you feel free to redesign your UI without worrying about codes ,another case this abstraction helps you and save your time is when migration to ConstraintLayout which is a task adopted for many developers, in this case your migration will be smooth by just focusing on your xmls.

 © Xosrov 2016