Android Development: Some useful libraries (part I)

Abderrazak Laanaya
AndroidPub
Published in
8 min readApr 19, 2016

--

Hi there! from my own experience. I came up with this list of libraries that are probably used most often and approved by the community (also official ones from Google). You may not need to include all this libraries for every app, but the idea here is about to pick up the right one.

Here’s the selection:

Supports Libraries

from Google delivers new APIs and stability fixes to older versions of Android. There are several versions that have particular minimum SDK version, some of them can help you find problems and improve your code like android annotations support :

compile 'com.android.support:support-v4:x.y.z'
compile 'com.android.support:appcompat-v7:x.y.z'
compile 'com.android.support:support-v13:x.y.z'
compile 'com.android.support:design:x.y.z'
compile 'com.android.support:support-annotations:x.y.z'
...

Multidex Support Library

If you ever run into Over 65k Methods Error while you build your app, this might be your cure (however this should be a last resort, you should try to strip it down your app first):

compile 'com.android.support:multidex:x.y.z'

Google Play Services

provides various services and APIs from Google, from Google Maps to Android Pay, from Wearables to Ads. It is updated from Google Play Store so it’s Android OS version independent. To include in your project:

compile 'com.google.android.gms:play-services:x.y.z'

If you don’t want to include the whole package (as it is very big and you might run into over 65k method error), you can selectively include modules you want to use like:

compile 'com.google.android.gms:play-services-wearable:x.y.z'
compile 'com.google.android.gms:play-services-maps:x.y.z'
...

Retrofit 2

Retrofit still my favorite library when it comes to implementing REST APIs. From their site: “Retrofit turns your REST API into a Java interface.” It’s an elegant solution for organizing API calls in a project. The request method and relative URL are added with an annotation, which makes code clean and simple. With annotations, you can easily add a request body, manipulate the URL or headers and add query parameters. To include this library add this into your build.gradle file:

compile 'com.squareup.retrofit2:retrofit:2.y.z' 
compile 'com.squareup.retrofit2:converter-gson:2.y.z'
compile 'com.squareup.retrofit2:adapter-rxjava:2.y.z'

Here’s a simple example how you can use Retrofit with RxJava:

public interface RestAPI{@GET(BuildConfig.PATH_TO_MOVIES_SERVICE)
Observable<List<Movie>> loadMovies();
// Helper class that sets up new service
class Factory {
public static RestAPI create() {
Retrofit retrofit =
new Retrofit.Builder()
.baseUrl(BuildConfig.API_BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();

return retrofit.create(RestAPI.class);
}
}

RxJava

is a Java VM implementation of Reactive Extensions, helps you to compose asynchronous, event-based, stream like code and adds functional programming paradigm. this is all you need to include this library:

compile 'io.reactivex:rxjava:x.y.z'

RxAndroid

wraps RxJava library. It adds functionality around Android specific threading. Note RxAndroid automatically includes a version of RxJava. However, because RxAndroid releases are behind it and if you want to use latest RxJava, then include both like:

compile 'io.reactivex:rxandroid:x.y.z'
compile 'io.reactivex:rxjava:x.y.z'

Let’s take an example:

private class SomeWebServiceTask extends  
AsyncTask <String,Result,Void>
{

protected Result doInBackground(String... someData) {
Result result = webService.doSomething(someData);
return result;
}

protected void onPostExecute(Result result) {
if (result.isSuccess() {
resultText.setText("Hello, world!");
}
}

}

or

webService.doSomething(someData)
.observeOn(AndroidSchedulers.mainThread())
.subscribe( result -> resultText.setText("Hello, world!"),
e -> handleError(e));

Yeah! Say goodbye to AsyncTasks.

ButterKnife

In every Android application, you have to use the findViewById() method for each view in the layout that you want to use in your application’s code. But as applications’ designs get more complex layouts, the call to this method becomes repetitive and this is where the ButterKnife library comes in.

this is all you need to include this library:

compile 'com.jakewharton:butterknife:x.y.z'

Let’s take an example. which of these do you like better?

private TextView mFirstNameLabel;
private TextView mLastNameLabel;
private Button mSubmitButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mFirstNameLabel = (TextView) findViewById(R.id.firstnameLabel);
mLastNameLabel = (TextView) findViewById(R.id.lastnameLabel);
mSubmitButton = (Button) findViewById(R.id.submitButton);
mSubmitButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
// TODO call ...
}
});
}

or

@Bind(R.id.firstnameLabel) TextView mFirstNameLabel;
@Bind(R.id.lastnameLabel) TextView mLastNameLabel;
@OnClick(R.id.submitButton) void submit() {
// TODO call ...
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_my);
ButterKnife.bind(this);
}

The second block of code is using the library, which uses annotations to “bind” views by creating boilerplate code for you. ButterKnife is small, simple, and lightweight, and because it makes your life as a developer easier, you should pretty much always use it. It would be great if the Android SDK itself could improve in this manner!

Picasso / Glide

Picasso/Glide. Excellent and efficient image loading libraries from network and more. But, in my opinion, Glide is the best choice for now. It was included at Google I/O 2014 official application. this is all you need to include this libraries:

/** Picasso **/
compile 'com.squareup.picasso:picasso:x.y.z'
/** Glide **/
compile 'com.github.bumptech.glide:glide:x.y.z'

This post explain diffrence between Picasso and Glide.

Here’s a simple example how you can use Picasso to load an image from a URL into ImageView:

@Bind(R.id.image_view) ImageView imageView;Picasso.with(this).load(imageUrl).into(imageView);

Here’s a simple example how you can use Glide to load an image from a URL into ImageView:

@Bind(R.id.image_view) ImageView imageView;Glide.with(this).load(imageUrl).into(imageView);

Timber

is a lightweight library to write logs in different places and control how it’s done in a centralized manner. It’s easy to add it as a dependency of your Android Studio project;

compile 'com.jakewharton.timber:timber:x.y.z'

A typical log goes like this:

public static String TAG = "ClassName";
...
Log.e(TAG, “A message here”);

but with timber, you could use something like this code in your Application creation:

@Override 
public void onCreate() {
super.onCreate();
if
(BuildConfig.DEBUG) {
Timber.plant(new DebugTree());
} else {
Timber.plant(new CrashReportingTree());
}
}
/** A tree which logs important information for crash reporting.

private static class CrashReportingTree extends Timber.HollowTree {
@Override
public void i(String message, Object... args) {
// TODO e.g., Crashlytics.log(String.format(message, args));
}

@Override
public void i(Throwable t, String message, Object... args) {
i(message, args); // Just add to the log.
}

@Override
public void e(String message, Object... args) {
i("ERROR: " + message, args); //Just add to the log.
}

@Override
public void e(Throwable t, String message, Object... args) {
e(message, args);
// TODO e.g., Crashlytics.logException(t);
}
}
//
Timber.i("Message here");

Otto (event bus)

is a library that simplifies communication between different parts of your application. For example, sending something from an Activity to a running Service, or easy interaction between fragments. To include it add this to your gradle:

compile 'com.squareup:otto:x.y.z'

Here is an example we use if the Internet connection is lost, showing how to notify an activity:

public class NetworkStateReceiver extends BroadcastReceiver {

// post event if there is no Internet connection
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if(intent.getExtras()!=null) {
NetworkInfo ni=(NetworkInfo) intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO);
if(ni!=null && ni.getState()==NetworkInfo.State.CONNECTED)
{
// there is Internet connection
}
else if(intent.getBooleanExtra
(ConnectivityManager.EXTRA_NO_CONNECTIVITY, Boolean.FALSE))
{
// no Internet connection,send network state changed
Bus.post(newNetworkStateChanged(false));
}
}

// event
public class NetworkStateChanged {

private mIsInternetConnected;

public NetworkStateChanged(boolean isInternetConnected) {
this.mIsInternetConnected = isInternetConnected;
}

public boolean isInternetConnected() {
return this.mIsInternetConnected;
}
}
public class MainActivity extends Activity {

public
static Bus bus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

bus = new Bus();
bus.register(this); // register Otto event Bus
}

@Override
protected void onDestroy() {
super.onDestroy();
bus.unregister(this); // unregister Otto event Bus
}
//Method that will be called when someone posts an event NetworkStateChanged
public void onEventMainThread(NetworkStateChanged event) {
if (!event.isInternetConnected()) {
Toast.makeText(this, "No Internet connection!", Toast.LENGTH_SHORT).show();
}
}

}

As I said first, Otto(event bus) allows you to connect those classes, directly. You can have an event starting from the class A notifying class B with the only mediator itself. but after adopting RxJava, I think that Rx and event buses are both using the reactive pattern but RxJava does it better. So we can say goodbye to event bus. This is an implementation of RxJava as event bus:

public class RxBus {

private final Subject<Object, Object> bus = new SerializedSubject<>(PublishSubject.create());
public void post(Object o) {
bus.onNext(o);
}
// Subscribe to this Observable. to get it
public Observable<Object> getEvents() {
return bus;
}
}
// Subscribe to the event getEvents().subscribe(new Action1<Object>() {
@Override
public void call(Object o) {
if(o instanceof AnswerEvent){
// TODO
}
}
});

RetroLambda

It’s a way of using Java 8 Lambdas to Java 6/7 (as well as Android). Makes your code much cleaner, combine it with RxJava and you are solid. This is all you need to include it:

classpath 'me.tatarka:gradle-retrolambda:x.y.z'
apply plugin: 'me.tatarka.retrolambda'

Here’s is a simple example how you can use Retrolambda & RxJava

Observable.just("Hello, world!")
.subscribe(s -> System.out.println(s));

Yeah! Clean & concise code.

Dagger 2

Dagger 2 is the successor of the famous Dagger dependency injection library and I highly recommend it. One of the major improvements is using zero reflection in generated injection code, which makes debugging a lot easier.

Dagger creates instances of your classes and satisfies their dependencies. It relies on javax.inject.Inject annotation to identify which constructors or fields should be treated as dependencies. Let’s take this famous CoffeeMaker example:

class Thermosiphon implements Pump {
private final Heater heater;

@Inject
Thermosiphon(Heater heater) {
this.heater = heater;
}

...
}

An example with direct injection into fields:

class CoffeeMaker {
@Inject Heater heater;
@Inject Pump pump;

...
}

Dependencies are provided via modules and @Provides annotation from Dagger:

@Module
class DripCoffeeModule {
@Provides
Heater provideHeater() {
return new ElectricHeater();
}

@Provides
Pump providePump(Thermosiphon pump) {
return pump;
}
}

To use it add this to build.gradle file:

compile 'com.google.dagger:dagger:x.y.z'
compile 'org.glassfish:javax.annotation:10.0-b28'//annotation Dagger compile 'com.google.dagger:dagger-compiler:x.y.z'//Dagger compiler

Realm

is another type of database in Android. But, what is very important, Realm doesn’t use SQLite. If you use ORMLite or ActiveAndroid or any other similar library, your data is stored in SQLite database, because these libraries give us only an overlay on SQLite. With Realm it’s quite different there is no SQLite at all. That’s all you need to use it:

classpath 'io.realm:realm-gradle-plugin:x.y.z'
//
apply plugin: 'realm-android'

Here’s a very simple example how to use it:

public class Book extends RealmObject {

@Required
private String title;

public String getTitle() {
return title;
}

public void setTitle(final String title) {
this.title = title;
}
}
// MAIN_ACTIVITY
public class MainActivity extends Activity {
private Realm mRealm;

@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mRealm = Realm.getInstance(getContext());
}
@Override
public void onDestroy() {
super.onDestroy();
mRealm.close();
}
// Example of add/ remove a book@OnClick(R.id.add)
public void onAddClick() {
mRealm.beginTransaction();
Book book = mRealm.createObject(Book.class);
book.setTitle(getTrimTitle());
mRealm.commitTransaction();
}

@OnClick(R.id.remove)
public void onRemoveClick() {
mRealm.beginTransaction();
RealmResults<MyBook> books = mRealm.where(Book.class)
.equalTo("title",getTrimTitle())
.findAll();
if(!books.isEmpty()) {
for(int i = books.size() - 1; i >= 0; i--) {
books.get(i).removeFromRealm();
}
}
mRealm.commitTransaction();
}

private String getTrimTitle() {
return mEditTitle.getText().toString().trim();
}
}

ViewPropertyAnimator

The ViewPropertyAnimator was introduced at API level 12, allowing you to simply and efficiently perform animated operations (in parallel) on a number of view properties using a single Animator instance. It’s both simple and tidy for us to implement programatically:

// Animate Button
mButton.animate()
.alpha(1f)
.scaleX(1f)
.scaleY(1f)
.translationZ(10f)
.setInterpolator(new FastOutSlowInInterpolator())
.setStartDelay(200)
.setListener(new Animator.AnimatorListener() {
@Override
public void onAnimationStart(Animator animation) { }
@Override
public void onAnimationEnd(Animator animation) { }
@Override
public void onAnimationCancel(Animator animation) { }
@Override
public void onAnimationRepeat(Animator animation) { }
})
.start();

The Transitions Framework

The Android transitions framework allows you to configure the appearance of changes in your app’s user interface. It offers tools to effectively manage and navigate life’s transitions. There’s some limitations of this framework:

  • Animations applied to a SurfaceView may not appear correctly. SurfaceView instances are updated from a non-UI thread, so the updates may be out of sync with the animations of other views.
  • Some specific transition types may not produce the desired animation effect when applied to a TextureView.
  • Classes that extend AdapterView, such as ListView, manage their child views in ways that are incompatible with the transitions framework. If you try to animate a view based on AdapterView, the device display may hang.
  • If you try to resize a TextView with an animation, the text will pop to a new location before the object has completely resized. To avoid this problem, do not animate the resizing of views that contain text.

In the Next Part we are going to talk about unit test/ reporting crashes and other libraries.

Thanks! :)

--

--