Sunday, 3 May 2015

250.000 visits reached!


I have started this blog on 7th April 2010, 5 years ago. In that time, the idea was start something quick and dirty, some kind of notes online to be found later, because at that time I was trying to solve a lot of technical problems but after solving them, I almost forget them immediately. The problem is when I found the same problem later, I was unable to find the same solution.

Since then, I have been posting things I found and it seems people like it. Some posts are just some solutions from StackOverFlow, and some posts are my own research about Android because the official documentation is a bit messy. (Still today they are quite messy, because most of them are just java docs...).

So, thanks everyone who made this possible. I will continue posting things I found and researched.

Correctly implementing OnActivityResult for Android

When the an activity launch another activity and it want to know the result of such activity, the best way to do it is using startActivityForResult and then, override the method onActivityResult to handle the result.

onActivityResult has tree parameters:

  • requestCode: integer. It is the number used to launch the activity. It must be unique inside an activity.
  • resultCode: integer. The result returned by the launched activity. By default the class Activity comes with RESULT_OK, and RESULT_CANCELED. The launched activity could specify any another integer for the result.
  • data: intent. It is optional. It could be empty if the launched activity has not specify any data.
By using the inherence property of Object oriented language that Java is, more and more an activity is inherited by another activity. In this case, both parent and son could override the method onActivityResult. So, there is a chance they share the same requestCode and even handle the same result code.

For this case, here is what I consider correct implementation of onActivityResult:


    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        switch (requestCode) {
            case (REQUEST_CODE_MY_RESULT_ACTIVITY_ID):
                switch (resultCode) {
                    case (RESULT_OK):
                        // Result is ok for the activity.
                        // Do things in accordance
                        break;
                    case (RESULT_CANCELED):
                        // Result has been canceled (the activity could be finished without
                        // passing correctly the data
                        break;
                    case (MyResultActivity.OTHER_POSSIBLE_RESULT):
                        // The activity could set special results that should be public static final
                        // Handle it here
                        break;
                    default:
                        super.onActivityResult(requestCode, resultCode, data);
                        break;
                }
            case (REQUEST_CODE_MY_ANOTHER_ACTIVITY_ID):
                switch (resultCode) {
                    // Here goes the cases for the another activity id
                    default:
                        super.onActivityResult(requestCode, resultCode, data);
                        break;
                }
                break;
            default:
                super.onActivityResult(requestCode, resultCode, data);
                break;
        }
    }

The special thing that it has is by each switch, it implements the default case when it called the onActivityResult of its parent. This is the same way as say if a certain case cannot be managed by the son, ask its parent to manage it.

More information

Monday, 6 April 2015

Android - Some words about the architecture

Here are some adverts that I have to build the architecture for Android:

1. Never use the Android class AsyncTask. You will lost the number of threads executing each time. Instead, use StaticThreadPool and your own implementation of threads in Java. This will improve the performance of the app. Actually I am using StaticThreadPool of 5 threads.

2. Never use an activity as Controller. The reason is in the activity is usually linked with the views. The views will not be destroyed until the activity is destroyed. So, if an activity lives as long as the app it self, it is retaining more resources than the app needs.

3. I have a class called Session which is a singleton. It is used as the general controller. It is the abstract layer that the Activities have to communicate with Backend, the database, etc.

4. There are two main Design patterns for asynchronous task that could be used: Observers and Callbacks. The First one is the one that should be used for the communication between the activities and the Controller. The Callback is the one that should be used for the communication between layers inside the Controller. This is because:

- The async tasks takes time. If the activity uses callback, it could happens that when the callback comes back, the activity has been already destroyed. If that callback is related with any manipulation of the views, it will fails or even crash the app. The use of Observer allow the activity to unregister itself when it has been paused/stopped/destroyed. So, it is saver using Observer.

- The problem with the observer is the class could lose the consistent of the actual state because several methods could expect the same result. Then for the Update method of the observer, when a result comes, it must check which method has done the request. This does not happens with the callbacks, since each callback should be used for only one method.

5. Never abuse the fragments. It is good if you need to implement the view for both Mobile and Tablets, but when there are too much fragments for one activity, it is hard to control the stack of views. Use Activities where it is possible.

6. Avoid the use of Static methods. They are only useful for Utility classes.

7. Don't abuse the use of Singleton. An activity shouldn't be never a singleton.

8. (Personal taste). Use a base Activity where all the activities extends. This will allow the activities have less code and easier to modify.

9. Have a base style for the textView, editText, buttons and so far. The have specific styles for the textView, editText and buttons in each activity. This will maintain the consistency of the app and allow the coder to have a slightly different style per activity without losing the control of the styles. 

10. Have a class Constant is ok. If there this class has a lot of values (more than 500 lines of code), then it is better to have each one of the constants allocated in each one of the classes.

11. Be careful with the loaders. It seems an alternative for AsyncTask that what happens in reality is you lose the control of what's happening after call it in the corresponding activity or fragment. Avoid to use it if possible.

Friday, 13 March 2015

Working with Robolectric on Android - A basic guide

1. Introduction

Few days ago I created a guide which shows how to install Robolectric, Mockito and AssertJ in 
Android Studio.  Now I am going to show how the basic features of Robolectric.

The source code of the project could be find in the branch RobolectricBasicGuide of the project unitTestingWithAndroidStudio in GitHub.

Note that the version of Robolectric that I use is 3.0, which has some syntactical differentiation with 2.X. You can check the differences here:
https://github.com/robolectric/robolectric/wiki/2.4-to-3.0-Upgrade-Guide-(Draft)

2. Test lifecycle and other notations

As all the tests of JUnit, tests on Robolectric has a specific lifecycle. This is, instead of name the method as setUp, teardown, and testX, robolectric has notations as @Before, @After and @Test, respectively.

The advantage of this is we can name the test with more meaningful name.

The another important notation is @RunWith. This notation is placed before the class is created and it specifies the customised runner which should run for the test instead of the default runner. In my case I have created a new Runner called RobolectricGradleTestRunner, by extending the default runner and overriding several methods, so I put the follow sentence before the declaration of the class.

@RunWith(RobolectricGradleTestRunner.class)

Last but not least is the use of the @Config notation. This notation is used in the tests to set a specific environment to run the test, such as Locale setting, the shadow classes or the position of the device (landscape, portrait).

More information about @Config could be found here:

3. Instantiate the activity

The second thing to do with Robolectric is create the activity. Robolectric has the control over all the lifecycle of the activity, such as onCreate, onPause or onStop. You can have more information here:

To create a simple version of the activity, which only the method onCreated is called, do the follow:

private MainActivity mMainActivity;

@Before
public void setup() {
    mMainActivity = Robolectric.buildActivity(MainActivity.class).create().get();
}

There could be activities which requires a specific intent or intents with a specific value to be instantiated. To do so, create a new intent and before invoke the method create(), invoke the method with(myIntent) to start the activity with the specific intent.

private MainActivity mMainActivity;

@Before
public void setup() {
    Intent startMainActivityIntent = new Intent(
            ShadowApplication.getInstance().getApplicationContext(), MainActivity.class);
    // Here you can add any data to the intent

    mMainActivity = Robolectric.buildActivity(MainActivity.class)
            .withIntent(startMainActivityIntent).create().get();
}

4. Check the elements

Once the activity is created as created properly, it is time to create the tests.

The simple test that could be done is check if the activity and all the views related with the activity exists.

To do so, first we check if the activity has been correctly created with the follow sentence:

assertThat(mMainActivity).isNotNull();

Then, per each one of the elements, we do the follow:

EditText mFirstNumberET = (EditText)mMainActivity.findViewById(R.id.first_number_et);
assertThat(mFirstNumberET).isNotNull();

The code above check two things:
1. If the view created could be casted to EditText
2. If the view with such id exists.

Note that I invoke the method findViewById(int) of the instantiated activity. This is because the test is a simple jUnit test and the method findViewById(int) only exists in the Activity class.

5. View change tests

Once the view test has been done, we can do the tests related with the view changes. This is basically after setting some data and/or interact with the views, check the views has been changed correctly.

First of all, a simple initiation check test is needed.

EditText firstNumberET = (EditText)mMainActivity.findViewById(R.id.first_number_et);
assertThat(firstNumberET.getText()).isEqualTo("0");

The code above get the EditText with the id first_number_et, get the text and assert it should be equal to 0.

Once the test is done, a better test could be created. Like the follow one:

/**
 * This test check if the calculator could do the follow operation:
 *     1 + 2 = 3
 */
@Test
public void simpleSumTest() {
    int firstNumber = 1;
    int secondNumber = 2;

    Calculator calculator = new Calculator(firstNumber, secondNumber);
    int result = calculator.sum();

    EditText firstNumberET = (EditText)mMainActivity.findViewById(R.id.first_number_et);
    firstNumberET.setText(String.valueOf(firstNumber));

    EditText secondNumberET = (EditText)mMainActivity.findViewById(R.id.second_number_et);
    secondNumberET.setText(String.valueOf(secondNumber));

    Button calculateBtn = (Button)mMainActivity.findViewById(R.id.calculate_btn);
    calculateBtn.performClick();

    TextView resultTV = (TextView)mMainActivity.findViewById(R.id.result_tv);
    assertThat(resultTV.getText()).isEqualTo(String.valueOf(result));
}

The test above assigns 1 to firstNumberET, assigns 2 to secondNumberET, press the calculateBtn button and then, check if the result set on resultTV is the same as if we use the class Calculator for it.

6. Checking the intents

The another interesting thing to test is testing if a certain intent has been triggered. This is done by getting the component from the intent as below:

@Test
public void checkIntentLaunched() {
    Button mLaunchCalculatorBtn = (Button) mLaunchActivity.findViewById(R.id.launch_calculator_btn);
    mLaunchCalculatorBtn.performClick();

    ShadowActivity shadowActivity = Shadows.shadowOf(mLaunchActivity);
    Intent startedIntent = shadowActivity.getNextStartedActivity();
    ShadowIntent shadowIntent = Shadows.shadowOf(startedIntent);

    assertThat(shadowIntent.getComponent())
            .isEqualTo(new ComponentName(mLaunchActivity, MainActivity.class));
}

The test press on the launch calculator button and then, check that the component of the intent which should start the next activity is the one which starts the Main activity.

7. Conclusions

Robolectric is a nice way to deal with unit testing in Android, since is shorts a lot the time needed to run the tests. If the lack of documentation is not a problem for you and you can deal with the time delay between when Google launch a new OS and Robolectric could "shadow" it, definitively it is a great tool to maintain the quality of the product.

Tuesday, 10 March 2015

Unit testing with Robolectric, Mockito and AssertJ on Android Studio

Introduction

Unit testing is an important task for any project, specially now with the grow number of Startups, where the projects should pivot very fast ensuring the existence feature remains usable at the same time.

In this post I will try to explain how to integrate Robolectric with Mockito and AssertJ as help, from the first step and with the sample project stored on GitHub.

To do so, I start with a simple app which calculates the sum of two numbers. You can find it in this branch:

https://github.com/jiahaoliuliu/unitTestingWithAndroidStudio/tree/creatingApp

Installation

We start with the installation of Robolectric, followed by Mockito and then, finally, with AssertJ. To make the code much more cleaner, it is good idea to create first a separated module.

1 Creating separated module

1.1 Click on File -> New module
1.2 Select Java Library and click on Next
1.3 Call it "app-test" and click on Finish

Android studio will take a while to recompile the project and then, a new project called app-test will be created with the follow structure:


The new module comes with the space for the source code but not for the test code. So, we must create one manually.

1.4 Right click on the src folder and create a new directory called test
1.5 Right click on the new folder and create a new directory called java.
1.6 Right click on the java folder and create a new package called "com.jiahaoliuliu.unittestingwithandroidstudio".

This is the final structure:



Note that the name of the package matches with the name of the package on the app module. This will save many imports.

1.7 Open the build.gradle file in the new module and add the follow code to it, at the top, before apply the plugin of java

evaluationDependsOn(":app")

You can see the code on the branch separatedModule:
https://github.com/jiahaoliuliu/unitTestingWithAndroidStudio/tree/separatedModule

1.8 (optional)
The folder lib is not going to be used, so it can be removed also.
Once it is done, the sentence on build.gradle related with this folder could also be removed.

This is how it is going to be look like:

evaluationDependsOn(":app")

apply plugin: 'java'

dependencies {
}

2 Integrating Robolectric

The next step is integrate Robolectric. At the time of writing, Robolectric 2.4 is stable, but 3.0-Snapshot seems to have less errors, so we are going to use robolectric 3.0.

2.1 On the build.gradle of the general project, add the follow line on both build script and all projects, just under jcenter():

maven { url "https://oss.sonatype.org/content/repositories/snapshots" }

2.2 Sync the project
2.3 At the build.gradle of the new module, add dependencies and extra task configuration related with Robolectric inside of the dependencies block:

dependencies {
    def androidModule = project(':app')
    compile project(path: ':app', configuration: 'debugCompile')

    def debugVariant = androidModule.android.applicationVariants.find({it.name == 'debug'})
    compile debugVariant.javaCompile.classpath
    compile debugVariant.javaCompile.outputs.files
    compile files(androidModule.plugins.findPlugin("com.android.application").getBootClasspath())

    compile 'org.robolectric:robolectric:3.0-SNAPSHOT'
    compile 'junit:junit:4.11'
}

tasks.withType(Test) {
    scanForTestClasses = false
    include "**/*Should.class"
    include "**/*Test.class"
    include "**/*Tests.class"
    exclude "**/*IT.class"

}

2.4 Sync the project.

The actual configuration works with the version 1.0.0 of gradle as android tools. If you see the follow error after sync:

Error:(12, 0) No signature of method: com.android.build.gradle.AppPlugin.getBootClasspath() is applicable for argument types: () values: []

Check on the version of gradle used on the main build.gradle file. It should be as follow:

classpath 'com.android.tools.build:gradle:1.0.0'


2.5 Override your own test runner
2.5.1 Go to the src/main/java folder of the new module and remove the class MyClass if exits.
2.5.2 Right click on the package and select New -> Java class. Name it as RobolectricGradleTestRunner.
2.5.3 Copy the code in this branch:
https://github.com/jiahaoliuliu/unitTestingWithAndroidStudio/blob/robolectricIntegration/app-test/src/main/java/com/jiahaoliuliu/unittestingwithandroidstudio/RobolectricGradleTestRunner.java



2.6 Create new test module to check it works.
2.6.1 Go to the folder test/java of the new module and right click on the package.
2.6.2 Select New -> Java class
2.6.3 Rename it as MainActivityTest
2.6.4 The first thing to do is set that it should run with the customised test runner instead of the official one. To do so, add the follow line between the import statement and the declaration of the class:

@RunWith(RobolectricGradleTestRunner.class)

2.6.5 Once it is done, copy the follow code in the test.

The above code could be find here:
https://github.com/jiahaoliuliu/unitTestingWithAndroidStudio/blob/robolectricIntegration/app-test/src/test/java/com/jiahaoliuliu/unittestingwithandroidstudio/MainActivityTest.java

The code of this step could be find in the branch robolectricIntegration of the testing project:
https://github.com/jiahaoliuliu/unitTestingWithAndroidStudio/tree/robolectricIntegration

2.7 (Just in case) Remove old test data
By default, when Android studio creates a new project, it also created a folder called "androidTest" with a class called ApplicationTest in it. This class will require the emulator or the physical device connected to the computer to be run, which is totally against the purpose of using Robolectric.

The easiest way to fix this problem is removing it totally.

3. Integrating Mockito

Once Robolectric is integrated, it is easy to integrate Mockito.
3.1 Goes to the build.gradle file of the module app-test and add the follow line in the dependencies block, just below to the junit test line:

testCompile "org.mockito:mockito-core:1.+"

3.2 Goes to the new module and right click on the package of test/java, select New -> Java class.
3.3 Name it as calculatorTest and copy and paste the follow code:



Which could be find here:

The source code of this branch could be found in the branch mockitoIntegration of the project:

4. AssertJ integration

AssertJ is a tool provided by Square which make the tests a bit more beautiful. To integrate it to the project, do the follow:
4.1 On the build.gradle of the "app" project, add the follow line in the block of dependencies. Repeat, in the module "app", not "app-test"

compile 'com.squareup.assertj:assertj-android:1.0.0'

4.2 Sync

To test it, go to the test MainActivityTest and put the follow line on the simpleTest:

assertThat(mMainActivity).isNotNull();

You must put the follow import to make it works:

import static org.assertj.core.api.Assertions.assertThat;

There are much more things that assertJ could help. Check its official web page:

The code of this step could be find in the branch assertJIntegration of the project:

Conclusion

So far seems easy to integrate Robolectric, Mockito and AssertJ into the Android Studio. Now it is when the fun begins with the unit tests.





Thursday, 26 February 2015

Monkey Talk integration with Android Studio

Monkey talk is an excellent tool to run feature tests, which simulates the interaction of the user with the application.

Unfortunately it does not has good integration with Android Studio, which reduces the among of users. In this tutorial I am going to show how to do it on more manual way, with a simple project.

1. Add the AspectJ plugin
1.1 Go to the main build.gradle file and add the follow one, inside the dependencies, like this.

classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.5'


1.2 In the build.gradle file of the module "app" add the follow line at the top, like this:

apply plugin: 'android-aspectj'


2. Add Monkey talk library
2.1 Download the latest version of MonkeyTalk Agent from their web page. It is contained inside the IDEs.
2.2 Inside of the module app, create a new folder called monkey-libs and paste the Monkey Talk jar library inside.
2.3 Open the build.gradle file of the app and paste the follow lines.
2.3.1 Paste the follow code inside of the buildTypes:

        monkeytalk.initWith(buildTypes.debug)
        monkeytalk {
            applicationIdSuffix ".monkey"
        }

2.3.2 Paste the follow code inside of the dependencies:

monkeytalkCompile fileTree(dir: 'monkey-libs', include: ['*.jar'])

Here is the example:

3. Include the permissions
Just in case you have not added them, add the required permissions to the Manifest file.
3.1 Open the Android Manifest file.
3.2 Copy the follow line into the manifest file. This will adds the Get task and internet permissions.

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_TASKS" />


4. Run the app
4.1 To run the app, open the Terminal or the console and type the follow:

./gradlew clean installMonkeytalk

This command will compile the app and install it into the existence device connected.

Note1: The method above does not works with the version 1.1.0 of the android gradle tool, but the version 1.0.0.

Note2: I have tested the method above with simple projects but with big projects actually it fails. So, good luck!

Source code:

Source: