Author’s highlight

android2ee (Seguy Mathias)
5 min readMar 7, 2017

Mathias thinks you, as Android developer, can be interested by the following article : Rx Android everywhere… why, but why ?

Playing with Gradle series:

Chapter 1: Basics

Chapter 2: Android Tasks Basics

Chapter 3: Flavors, BuildTypes and Variants

Chapter 3 1/4: Flavors And Manifest

Chapter 3 and some few: Understanding the life cycle.

Chapter 3 and some few more: Code Coverage on Android with Jacoco

Chapter 4: Getting real

(Download the ebook: https://android2ee.com/Tutoriaux/Playing-with-Gradle.html for free and without any registration or what ever, it’s a gift to the community).

There is a specific use case I want to talk when playing with flavors.

Imagine you have made 2 flavors WhiteBands and CatBus in the dimension “brand” and your main flavor contains all your architecture code.

That way, setting your architecture in main, you don’t have to copy/paste project to reuse your architecture or create sdk that imprisoned your developers or worst a framework that not even created is already deprecated.

The flavor WhiteBands is the project where you code a sample application that show cases to all the others teams how to use the architecture and how to code most of the use cases.

The flavor CatBus is the final product. The objective is to be able to use your architecture, to reuse the “good pattern” code of WhiteBands and to be free to implement what is needed to be.

And in this configuration, you know that you’ll have several teams playing the game; dog, bird, canary, horse and so on. So they will fork you initial project (with main and WhiteBands) and create their own flavor DogBus and go in the build of their product on safe foundations.

Funny game, isn’t it?

To make the parallel with my tutorial, you can imagine basile is WhiteBands, lila is CatBus and you have your comprehension.

So in this scenario, one main problem that occurs is the initialization of some libraries in the onCreate of your MainApplication object. Because we do a lot in our Application object and we need to define it in main for our architecture. And as you know, if you let a Class in main, you cannot overwrite it in a specific flavor. That works only for resources, not for java code. So you are screwed.

So, how can I initialize my library? I cannot overwrite the code of MainApplication using flavor.

In fact it’s not the right question, the question is:

· how can I create MyLilaApplication object in the flavor lila

· that extends the MainApplication defined in the main flavor and

· explain to android that the Application object of the application is MyLilaApplication ?

If I can do that, I initialize my library in the onCreate of MyLilaApplication object. And such a solution will also work for Services and BroadcastReceivers defined in the main flavor.

So let’s do that.

1 In practice

Ok, so it’s simple until it won’t be.

I create my new MyLilaApplication in the Lila flavor that extends MainApplication defined in the main flavor.

I just overwrite onCreate and do a log, normally, you initialize elements here (like libraries).

public class MyLilaApplication extends MainApplication {

@Override
public void onCreate() {
super.onCreate();
//I do somthing
//like intializing a specific library
Log.e(“MyAppInitializer”,”Second choices, a log is enough to prove the concept: MyLilaApplication”);
}
}

Then the next step is explain to the system that Lila’s flavor application object is implemented by MyLilaApplication.

We do that as usual in the manifest (the one of the flavor Lila):

So I update the manifest like this:

<manifest xmlns:android=”http://schemas.android.com/apk/res/android"
package=”com.android2ee.basile.multiplication”>

<application
android:allowBackup=”true”

android:name=”.MyLilaApplication”

android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:supportsRtl=”true”
android:theme=”@style/AppTheme”>

<activity android:name=”.view.MainActivity”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />
<categoryandroid:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
<activity android:name=”.view.AssessmentActivity”></activity>
</application>

</manifest>

And I run my project. The Gradle build fails with this marvelous error:

Error:Execution failed for task ‘:app:processLilaAdditionDebugManifest’.

> Manifest merger failed : Attribute application@name value=(com.android2ee.basile.multiplication.MyLilaApplication) from AndroidManifest.xml:6:9–38

is also present at AndroidManifest.xml:6:9–38 value=(com.android2ee.basile.multiplication.MainApplication).

Suggestion: add ‘tools:replace=”android:name”’ to <application> element at AndroidManifest.xml:6:5–21:19 to override.

Et voilà, shit happened.

So what is the problem? The problem comes from the merging resources proccess. As it’s simple for the resources itself to be merge (straight overwrite strategy), the manifest is more complex to merge and it cannot be always done in a generic way. And here is the case where generic merging strategy fails.

Is it over? Are we screwed again ?

No, Google provides us tools to explain the merging strategy to adapt with our use case (and also they explain us what to do in the error’s logs).

https://developer.android.com/studio/build/manifest-merge.html

The basic principle is that you can tune the merge of the different manifests. Basically when you have several manifests to merge they inherit from each other’s, you just have to say, in the final merge, how to consider inherited attributes. You can:

· merge

· mergeOnlyAttributes

· remove

· removeAll

· replace

· strict (generate an error when merging conflict and stop)

The explanation page is really clear, just have a look and bookmark it :)

For us, we want to replace the inherited value of android:name by the new one :

<?xml version=”1.0" encoding=”utf-8"?>
<manifest xmlns:android=”http://schemas.android.com/apk/res/android"
package=”com.android2ee.basile.multiplication”

xmlns:tools=”http://schemas.android.com/tools">

<application
android:allowBackup=”true”

tools:replace=”android:name”

android:name=”.MyLilaApplication”
android:icon=”@mipmap/ic_launcher”
android:label=”@string/app_name”
android:supportsRtl=”true”
android:theme=”@style/AppTheme”>
<activity android:name=”.view.MainActivity”>
<intent-filter>
<action android:name=”android.intent.action.MAIN” />

<category android:name=”android.intent.category.LAUNCHER” />
</intent-filter>
</activity>
<activity android:name=”.view.AssessmentActivity”></activity>
</application>

</manifest>

Don’t forget to add the name space of tools in your xml (the xmlns tag at the top).

And that’s enough.

So if we remember the code:

public class MyLilaApplication extends MainApplication {

@Override
public void onCreate() {
super.onCreate();
//I do somthing
//like intializing a specific library
Log.e(“MyAppInitializer”,”Second choices, a log is enough to prove the concept: MyLilaApplication”);
}
}

We can run the application and obtain:

03–07 21:18:23.764 13926–13926/? E/MyAppInitializer: Second choices, a log is enough to prove the concept: MainApplication

03–07 21:18:23.764 13926–13926/? E/MyAppInitializer: Second choices, a log is enough to prove the concept: MyLilaApplication

So the log of the super class MainApplication (the one coded in the flavor main) is done first, because we call super.onCreate first (in MyLilaApplication) and the one of MyLilaApplication is done second, like the code expect.

So we do it, yes.

1.1 The getInstance question

Doing this, a question raised in my mind, I have a singleton pattern set on the MainApplication object. It should work fine, but am I sure?

So here is the pattern I definitely use (abuse) in my application’s architecture?

public class MainApplication extends Application {
/***********************************************************
* Singleton
**********************************************************/
private static MainApplication instance;
public static MainApplication ins(){
return instance;
}
/***********************************************************
* Managing Life Cycle
**********************************************************/
@Override
public void onCreate() {
super.onCreate();
instance=this; //Other code after

I use it a lot in my application for obtaining a context :

MainApplication.ins().getSharedPreferences.

But also for the ServiceManager, the ThreadManager…

Let’s test a stuff, just let’s make some logs

Log.e("Application_whoRU","The instance of MainApplication.ins()=="+MainApplication.ins().getClass().getSimpleName());Log.e("Application_whoRU","The instance of MainApplication.ins()=="+ MyLilaApplication.ins().getClass().getSimpleName());

And it returns:

03–07 21:28:05.821 E/Application_whoRU: The instance of MainApplication.ins()==MyLilaApplication

03–07 21:28:05.821 E/Application_whoRU: The instance of MainApplication.ins()==MyLilaApplication

Ok, it’s cool. And watching the result, it’s clear, we didn’t have to worried, and it was obvious. But stupid question has to be answered, and when in doubt, just test. Having doubts is a good beginning.

So nothing to change, the singleton stays in MainApplication and flavors can use it safely.

--

--

android2ee (Seguy Mathias)

Android2ee alias Mathias Seguy. Android expert gives you some news on the Android world. mathias.seguy@android2ee.com