incentivelabs.de

Blog about nerd stuff, programming and related tools

Category: Android

Network and Lifecycle

Published / by glethien / Leave a Comment

There are a lot of problems with the activity lifecycle in particular when the following situation occurs

  1. Your activity starts a network request to your backend
  2. The user rotates the device. The activity gets recreated with a different configuration
  3. Your network request is lost. The async task runs in the background but the results get posted to the nowhere

The solution for this is simple and there is no need for additional software. As soon as you open the activity, the network request gets started. As soon as the requests finishes the result will be posted into a cache. The activity now can retrieve the result. Using callbacks you can notify the activity when the request is done, but this is optional as the old activity don’t exist anymore when rotating the device. The new activity will first check the cache before starting a new request.

This way you have separated the network logic from the activity lifecycle and your logic lives longer and outside the lifecycle.

Android UI Tests

Published / by glethien / Leave a Comment

Testing your app before release is a very important part! You don’t want to release a buggy and crashing app to the world! So the question is how to improve the app and find the bugs? For this you can use memory profiler to find memory leaks, but most important you want to test you app with near real-world-situations. Doing this test by hand is very inefficient and time consuming.

Luckily Google have the solution right in your Android SDK: Espresso! Not the coffee but the testing framework. With some short changes in your gradle build file you can integrate Espresso into your project! Just add the following lines to you gradle file.

dependencies {
    // Other dependencies ...
    androidTestCompile 'com.android.support.test.espresso:espresso-core:2.2.2'
}

And you are ready to go! You may have notices that besides you normal package in AndroidStudio there is the same package again but with “androidTesting”. In this package just create an empty class and annotate it with

@RunWith(AndroidJUnit4.class)
public class MyFirstTest {

This will tell expresso that this class is a TestClass which contains serveral other tests (at least you should implement one test).

Before you write the first test you need to add a rule to you test. This rule will be the activity in which your test will start!

@Rule
public ActivityTestRule<MainActivity> mActivityRule = new ActivityTestRule<>(MainActivity.class);

Now it is time for your first test. Add a new method and annotate it using @Test

@Test
    publicvoid changeTextTest(){
        // Type text and then press the button.
        onView(withId(R.id.editText))
                .perform(typeText("Hello World"), closeSoftKeyboard());
        onView(withId(R.id.changeTextBt)).perform(click());

        // Check that the text was changed.
        onView(withId(R.id.editText2))
                .check(matches(withText("Hello World")));
    }

This test is a little bit stupid but I think it will demonstrate how Espresso works. You have a lot of static methods which you can use to implement the test logic. Normally the test should be nearly human understandable. Look a the first line in the test. It tells Espresso to take the view with the Id R.id.editText and perform something. In this case typeText(“Hello World”) and then close the keyboard. Pretty straight forward.

Next line will be much more easier! With the view, which has the ID changeTextBt perform the click. Simple as that.

But keep in mind: you can only check for UI elements which are currently visible. As soon as the matching fails, the test aborts and you will get a failure. This contains that there is no view with the desired id or the texts don’t match. So when you write the UI tests, you should consider that.

Espresso has some backdraws too. You can not call methods from the activity which are not bound to buttons, or views in general. You do not have other information as those the user can see! There are ways to get those but, personally I think, that if you need those, your app or your test has a bad architecture.

For all Espresso checks you can see the cheat sheet here.

 

Espresso compare color values

Published / by glethien / Leave a Comment

I’ve started to write automated UI tests using Espresso. This comes in handy, as you can run them after each commit to the master branch. This can be done using Jenkins.

There are a lot of default matchers but for one case I need to check, I was missing a matcher for the background color of a linear layout. I needed to check if the player has too few gold coins that he can’t buy items in the shop, but on the other hand the items should be displayed anyway. I’ve checked that the layout is not clickable but I wanted to make sure that the the user has a visible notificataion. Therefore I switched a green LinearLayout to a grey background. Now to check this using Espresso I needed a custom matcher which compares the background color of the LinearLayout with the provided color. Here is what the matcher looks like.

public static Matcher<View> withBgColor(final int color) {

    Checks.checkNotNull(color);

    return new BoundedMatcher<View, LinearLayout>(LinearLayout.class) {
        @Override
        public boolean matchesSafely(LinearLayout layout) {
            return color == ((ColorDrawable) layout.getBackground()).getColor();
        }

        @Override
        public void describeTo(Description description) {
            description.appendText("With background color: ");
        }
    };
}

 

This is pretty simple. Just write a static method returning the Matcher<View> In addition check that the color you’ve inserted is not null. Override the two methods of the BoundedMatcher. The first one is the actual comparison/test and the 2nd one appends a short error message if the test fails. No magic!

And this is how you can use the matcher in your test

.check(matches(withBgColor(ContextCompat.getColor(getInstrumentation().getTargetContext(), R.color.grey_300))));

If you ever need such a test, feel free to use this code.

Things every new Android Developer should be aware of

Published / by glethien / Leave a Comment

Walking through the world you can see mobile devices everywhere and if you are a developer or want to become one, you may come to the conclusion that development for mobile devices seems to be a great idea. You are right! But first make sure you know the following things, which I think are essential for every android developer!

 

Basic understanding of Android Architecture

If you start working on a new platform you should at least read one or two articles about the platform. This applies to android too. You can start with this tutorial which will give you a basic understanding. From my point of view this should be more than enough to know. With this knowledge you are able to understand what is happening and why something works as it is. This leads to better source code and more stable apps!

Java

As you will use Java for developing your apps, you will need a good skillset in Java. If you do not feel secure using asynchrous thinks, listener and other basic Java funcionalities, you should read about basic Java topics and gain confidence, so you can focus on the android related things.

Android Studio

You have the possibility to choose between Android Studio and Eclipse as you IDE. I highly recommend using Android Studio! It’s based on IntelliJ and Google implenented a lot of nice features into Android Studio which will make your development much easier and enjoyable. Learn the shortcuts and where to find the important settings, files and make yourself known to the UI tools.

Activity and Fragment Lifecycle

Activites and Fragments will be your be your daily bread. Both of them have a slightly different lifecycle which you should know. The lifecycle is important to know when to load, when to unload or when to cancel open network connection as well as database handler. The official documentation for Android does have a very good description which you can read here. In short: When the system calls the onResume() you should open the database connection and when onPause() is called you should close the connection again (if you haven’t done before). This ensures that there is no leaked connection which can be abused.

Passing data between Fragments

There are a lot of ways to pass data between Fragments and I would say there are a lot of advantages and disadvantages for each method. Here is the one method I am using.

First I create the Fragement and in give it a static method.

public static MyFancyFragment newInstance(final DataModel model) { 
    MyFancyFragment instance = new MyFancyFragment ();
    instance.setArguments(new Bundle());
    instance.getArguments().putSerializable("DataModelField",model); 
    return instance;
 }

The other important part is to parse the serializable back into the DataModel and store it in the fragment.

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View view = super.onCreateView(R.layout.my_fancy_fragment_layout, inflater, container, savedInstanceState);
    dataMode = (DataModel) getArguments().getSerializable("DataModelField");
    return view;
}

That’s it. If you want to create a new instance of the fragment, just call newInstance and pass the DataModel as parameter into the fragment. Your data will be available after onCreateView is called. As this is part of the lifecycle, this method is called for sure! This isn’t the best way or the worst way, it is just one way to do it. I recommend to take a look at other approaches and adapt the one which fits most for you.

dp vs pixels

Pixels are the actual pixel on the screen. Pretty straight forward. Problem is that nearly every device has a different resolution. Using pixel it will be impossible to create a resolution independent layout. Therefore Android introduces dp. dp stands for Density-independent Pixels and is a fictional unit for creating UIs. 1dp is roughly 1px on a 160 dpi screen. For any other screen the actual amout of pixel for 1 dp is calculated by the device.

Debugging your app

Android proves the serveral methods for debugging. You have the full log in AndroidStudio, you get crash reports in you GooglePlay Console after you’ve released you app, but most important is to write your own log outputs. Luckily this is very easy as you just need to call the static method

Log.d(TAG, "onCreate() No saved state available");

You can set a specific TAG, which is maybe something like “network”, “database”, “fancyShit” or everything else. After that just add a filter for the logcat and you will only see messages with the specific tag. In addition AndroidStudio provides methods for CPU usage, GPU usage and finding memory leaks. You should make yourself familiar with those tools! It will save you a lot of time.

Googles Plans

Currently the process in the world of mobility is very fast, so as a professional android developer you should know what the next fancy stuff is and when it will be available, so you can make use of it. For starters you can checkout the android twitter account or the android developers Youtube channel. Once a year Google is host of the Google IO, a annual developer conference with focus on sessions and lesson about developing for mobile and web with Google.

Material Design guidelinbttes

Users expect a specific behaviour of an app and where to find what. Google tried to make a standart for the layout. I advise you to follow those guidelines, as it will improve the user experience. A coworker once said, that you must assume that the human cursor has at least a 1cm diameter. Image having tiny buttons close together… Most likely you will never hit the right one and getting frustrated. You can find the material design guidelines here

Most likely: you wont be successfull

For each of you the most important point: YOU MAY WON’T BE SUCCESSFULL

This sounds harsh but this might be the only truth you will need. Currently there are more than 2 million apps! Don’t expect to publish one or two apps and land the next hit! This CAN happen and I would be very happy for you if it does, but don’t relay on it. Maybe you idea isn’t even new. Just take a look at how many clones of CandyCrush you can find on Google Play Store. With more than 2 million apps available, it’s very hard to find your app! Do it just for you! If you really want to have some more downloads, think about spending money into marketing your app!

Android Splash Screen

Published / by glethien / Leave a Comment

Recently I’ve came across a minior discussion about Splash Screen in Android.

We talked about the usefulness of those splash screens. Some want to use them to display the company logo or app logo, so the user has to stare several seconds on the logo. If the screen stays for 3 secs and the user opens the app 3 times a day, this makes 9 seconds of waiting or 35 secs a week. If you have 1 million users, your users will wait for 35000000 secs or 583333 minutes or  9722 hours A WEEK! Just let this huge numbers sink in…

What a waste of time!

On the other hand Google advocates using splash screens. You can find it here in the material design guidelines. All Google apps like Youtube, Mail or others using splash screens! But they only let the user wait the minimal time necessary for the app to load! Not a second longer.

 

Implement a splash screen

 

So at first you will need a simple layout in xml which defines your splash screen. A minimal one with the app logo centered is enough! This could look like this:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:orientation="vertical"
    tools:context=".SplashActivity"
    android:gravity="center_vertical|center_horizontal">

    <ImageView
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:id="@+id/imageView"
        android:layout_centerHorizontal="true"
        android:layout_alignParentBottom="false"
        android:background="@drawable/logo" />
</LinearLayout>

This will create an layout with a 200dp squared logo centered. Don’t overload the screen with text, logo and other stuff! In the best case this screen will stay less than a second and the user don’t have enough time to read everything!

In Java you just load your app and then proceed to the next activity as soon as possible

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);

        // Here do some bootup stuff, but nothing long loading.
        Intent intent = new Intent(this, MainActivity.class);
        startActivity(intent);
        finish();
}

And that’s it. You may request the permissions before calling the intent, but there is no more magic. With this you have an activity as splash screen which only stays for the minimal needed time and not wasting your users time.