Live Templates: Logging with Android Studio

Android Studio comes with some pre-packaged Live Templates to make writing code fast. There are some logcat specific live templates that you could use in your classes to quickly write  code for logging. Below are some of the logging methods that I find invaluable.

  1.  logt (create TAG):
    TAG
  2. logm (Log.d  for method call including parameter):logm
  3. loge (Log.e):loge

The same can be done for logi,logv,logr.  I don’t know about you. These have saved me a couple of keystrokes…and extra libraries just for logging.  You can even create your own Live Templates if you want.

Did you know: Reusing native element attributes in Custom Views

It’s interesting some of the little things you could take for granted and figure out while digging in the Android source code.  If you’ve ever created your own custom views in Android you’ll note that sometimes you might require to make your own custom element attributes to style the appearance of your view when its defined in an XML file/element. Did you know though that instead of recreating some common attribute you could reuse the built-in defined element attributes?

Instead of:

<resources>
   <declare-styleable name="MyAwesomeLabelView">
       <attr name="malv_text" format="string|reference"/>
       <attr name="malv_icon" format="reference"/>
   </declare-styleable>
</resources>

you could :

<resources>
   <declare-styleable name="MyAwesomeLabelView">
      <attr name="android:text" />
      <attr name="android:icon" />
   </declare-styleable>
</resources>

Pretty cool huh!?  Just don’t get carried away with this by “overriding” all the native attributes in your custom views styleable declaration.

Did you know: ContextCompat

Lately I’ve been refactoring some old code and one of the common issues I found was about deprecated calls to methods in the Resources class. I use the getDrawable(int) and getColor(int) calls in a lot of places . The suggestion from lint is that I use the matching method calls with an extra Theme parameter for styling purposes.

If you’d rather have the system handle that extra parameters for you, then maybe ContextCompat is for you. ContextCompat will provide a theme styled for the specified Context’s theme.

Instead of:

<activity>.getResources().getColor(R.color.levelColor)

you would:

ContextCompat.getColor(<context>,R.color.levelColor);

The same applies for most of the deprecated methods in Resources like getColorStateList. Check out ContextCompat.

Working with GuidedStepFragments on Android TV

If you want to develop for Android TV and easily adhere to TV UI best practices then the Leanback support library is your best bet.

The recently released support libraries revision 23.2.0 added new functionality to the GuidedStepFragment to further help direct users through a series of decisions in order to accomplish a goal. So what changed ?

Get the sample project on Github from here.

Button actions.

Button actions where added to GuidedActions. The idea is to make it faster to confirm/submit an action without having to scroll down through all the other actions before you can continue with your decision making. The videos below might explain this better.

Before:

Now:

In-order to create a button action , you can overide the onCreateButtonActions method or use GuidedStepFragment.setButtonActions. You can then listen for the selected button by overriding onGuideActionClicked.

 

Editable description fields.

 

It’s now possible to input text in an action. I would not overuse this feature though on TV , ever tried entering your email on TV with a remote ? Use GuidedAction.Builder.descriptionEditable(true) to make your action editable. You can listen for completion on this field via onGuidedActionEditedAndProceed. I saw they also added GuidedAction.Builder.descriptionInputType . I cant seem to make it work with the default TV keyboard on an Android TV emulator though.

Guided Action SubActions

This has the fill of drop down lists to it. So yeah we have these now. All you need to do is use the GuidedAction.Builder.subActions method to add more ‘sub’ actions to your main action. You can listen for a selection on any one of your subactions by overiding GuidedStepFragment.onSubActionClicked.

 

GuidedDatePickerAction

Simply put , this is just a date picker within the action view, yay. Just like editable GuidedActions. You listen for completion from within the onGuidedActionEditedAndProceed method.

As is clearly evident. Theres a lot of  new features within this release. I have made a sample app to show how to implement these new actions within your app. Get the sample project on Github from here.

I’m sure I’ve missed a few. If any let me know in the comments below.

 

Jodatime vs ThreeTenABP (Android Date/Time tool comparison)

Reaching the infamous dex method limit kinda sucks. Which is why I started to trim libraries in my app instead of just going the Multidex route. With the help of this nifty APK method count tool , I’ve been able to identify some libraries I might reconsider using.

Jodatime has 4713 methods and ThreeTenABP has 2827 methods (debug apk)

I’ve been using the Jodatime port  for a while now. It makes dealing with date and time functionality easy. I came across ThreeTenABP which is an Android backport of  Java 8’s JSR310 implementation. The functionality between the 2 seems comparable for what I use Jodatime for in my app. What stood out for me though was the method count.

Comparing Jodatime  (2.9.2) and ThreeTenABP (1.0.3) , the latter has a significantly lower method count. Jodatime has 4713 methods and ThreeTenABP has 2827 methods (debug apk). That difference was big enough for me to consider replacing my implementation and it was not as painful as I anticipated. I went through Jodatime’s quick start guide and tried implementing the same examples using ThreeTenABP.

Jodatime:


DateTime dt = DateTime.now();
int jd = dt.getDayOfMonth();
int jm = dt.getMonthOfYear();
int jy = dt.getYear();
Log.d(TAG,"Joda : "+ dt.toString());
Log.d(TAG,"Joda : [day: "+jd+"] [month: "+jm+"] [year: "+jy+"]");
Log.d(TAG,"Joda : [day: "+dt.dayOfWeek().getAsText()+"] [month: "+dt.monthOfYear().getAsText()+"] [year: "+dt.year().getAsText()+"]");
dt.withYear(2000);
dt.plusHours(2);
Log.d(TAG,"Joda : "+dt.toString());
String frenchShortName = dt.monthOfYear().getAsShortText(Locale.FRENCH);
boolean isLeapYear = dt.year().isLeap();
DateTime rounded = dt.dayOfMonth().roundFloorCopy();
Log.d(TAG,"Joda : [french Short: "+frenchShortName+"] [leapyear: "+isLeapYear+"] [rounded: "+rounded+"]");
dt = new DateTime(2005, 3, 26, 12, 0, 0, 0);
Log.d(TAG,"Joda : "+ dt.toString());
DateTime plusPeriod = dt.plus(Period.days(1));
Log.d(TAG,"Joda : +1day "+ plusPeriod.toString());
DateTime plusDuration = dt.plus(new Duration(24L*60L*60L*1000L));
Log.d(TAG,"Joda : +24h "+ plusDuration.toString());
DateTime today = DateTime.now();
DateTime yesterday = today.minusDays(1);
Hours diff = Hours.hoursBetween(today,yesterday);
Log.d(TAG,"Joda : hours between "+ diff.getHours());

ThreeTenABP:


LocalDateTime ldt = LocalDateTime.now();
int ld = ldt.getDayOfMonth();
int lm = ldt.getMonthValue();
int ly = ldt.getYear();
Log.d(TAG,"3ten : "+ldt.toString());
Log.d(TAG,"3ten : [day: "+ld+"] [month: "+lm+"] [year: "+ly+"]");
Log.d(TAG,"3ten : [day: "+ldt.getDayOfWeek().name()+"] [month: "+ldt.getMonth().name()+"] [year: "+ldt.getYear()+"]");
ldt.withYear(2000);
ldt.plusHours(2);
Log.d(TAG,"3ten : " +ldt.toString());
String frenchShortName = ldt.getMonth().getDisplayName(TextStyle.SHORT,Locale.FRENCH);
boolean isLeapYear = false; // could not find a matching function
LocalDateTime rounded = ldt.truncatedTo(ChronoUnit.DAYS);
Log.d(TAG,"3ten : [french Short: "+frenchShortName+"] [leapyear: "+isLeapYear+"] [rounded: "+rounded+"]");
ldt = LocalDateTime.of(2005, 3, 26, 12, 0, 0, 0);
Log.d(TAG,"3ten : "+ ldt.toString());
LocalDateTime plusPeriod = ldt.plusDays(1);
Log.d(TAG,"3ten : +1day: "+ plusPeriod.toString());
LocalDateTime plusDuration = ldt.plus(24,ChronoUnit.HOURS);
Log.d(TAG,"3ten : +24h : "+ plusDuration.toString());
LocalDateTime today = LocalDateTime.now();
LocalDateTime yesterday = today.minusDays(1);
org.threeten.bp.Duration diff = org.threeten.bp.Duration.between(today,yesterday);
Log.d(TAG,"3ten : hours between "+ diff.toHours());

You can get most of the functionality provided by Jodatime from ThreeTenABP. I also noticed that Jodatime now seems to have the JSR-310 implementations as well. The only reason I ended up changing was because of the method count. Your use case might vary to mine.

365BW : Version 3.2.6

So I finally managed to finish the sync across device functionality. You will be able to sync once cloud_syncyou login with your Google/Amazon credentials. On phone you can manually invoke sync from the action menus. Sync though happens
automatically every-time you create a custom workout or when you complete a workout session.

Get the new version now live on the PlayStore.

Random Android Tip: ADB (Android Debug Bridge)

The Android Debug Bridge (adb) is a powerful tool that allows you to communicate with a connected device. One of my favorite features is the ability to start an Activity , BroadcastReceivers or Service while passing intent parameters to it, all from command line.
e.g starting an activity takes the form:

adb shell am start  -n “[your package name here]/[your activity path here]”

Take a look at the attached gist to see how you can do this.

[1] https://gist.github.com/ckurtm/ea4ba85c1dfc7be4a43b
[2] http://developer.android.com/tools/help/shell.html

Marking your Activities,Services and Receivers as exported in your app manifest might not be something you want to do in a production app as it might be a security risk if you do not wish to share you app info with any other app.