What No One Told You About the Android Support Library

Should I Use the Support Library?

The support library was originally introduced so that the features available in the latest Android SDK could be available in older Android versions. This fact is still perpetuated in the official web page.

image

Continue reading

Advertisements

Running Instrumented Test in Android

An instrumented test is a fancy name for a test that runs within the Android device in the same process space as your app. This lets you test code that relies on Android SDK calls. The official guide is horridly incomplete. Here are a few quick notes.

Package Conflict

Android Studio builds a separate APK just for instrumented test. This runs in the same process space as the APK for the main app. Unfortunately this means both APKs must have no conflicting package dependencies. But the Internet is full of example of conflict with theĀ com.android.support:support-annotations package. You will need to force both APK to use a higher version.

androidTestCompile 'com.android.support.test:runner:0.5'
androidTestCompile 'com.android.support.test:rules:0.5'

//Force same version
androidTestCompile 'com.android.support:support-annotations:23.2.0'
compile 'com.android.support:support-annotations:23.2.0'

This is just an example only. By the time you read this newer versions may be available.

Location of the Test Java File

You have to create the test Java file in theĀ androidTest folder. This way it will get packaged with the test APK.

Annotation

An instrumented test class needs to have @RunWith and @SmallTest annotation.

A sample template class:

import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;

@RunWith(AndroidJUnit4.class)
@SmallTest
public class InstrumentedTests {
 @Test
 public void testCaching() {
   assertNotNull("Hello");
   assertTrue(true);
   assertEquals("One", "One");
 }
}

Custom Theme in Android

Theming is useful when you need to apply a consistent custom look throughout the app. There are two ways you can do this in Android:

  1. Style: Define styles and then apply them to the widgets in layout XML. This can still be a lot of work since you have to apply the styles to each widget.
  2. Theme: Create a theme where you use the styles and then associate a theme at the application level. This will apply the styles throughout the app.

The way you define styles and theme depend on if your project is using the support library. Here I will describe the way things are done using the native SDK (not using support library).

Styles

You can define the styles in res/values/styles.xml. For example:

<resource>
    <style name="labelStyle">
        <item name="android:typeface">monospace</item>
        <item name="android:textColor">#00FF00</item>
    </style>
</resource>

Now, you can use the style with a widget in a layout XML.

<TextView android:text="@string/hello_world" 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    style="@style/labelStyle" />

You can override some of the style attribute at the individual widget level. For example, here we change the text color.

<TextView android:text="@string/hello_world" 
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textColor="#ff43cdff"
    style="@style/labelStyle" />

Theme

A theme applies styles at application level. This way you don’t have to set style for each widget.

You can define a theme in res/values/styles.xml. It’s strongly recommended that you derive your theme from a standard theme. That way you can just override what you need.

The theme below specifies the action bar background, title style and text view (label) style.

    <style name="AppTheme" parent="android:style/Theme.Holo.Light">
        <!-- Customize your theme here. -->
        <item name="android:actionBarStyle">@style/MyActionBar</item>
        <item name="android:windowBackground">@color/background</item>
        <item name="android:textViewStyle">@style/labelStyle</item>
    </style>

    <!-- ActionBar styles -->
    <style name="MyActionBar"
        parent="@android:style/Widget.Holo.Light.ActionBar.Solid.Inverse">
        <item name="android:background">#FF0000</item>
        <item name="android:titleTextStyle">@style/titleStyle</item>
    </style>
    <!-- ActionBar title styles -->
    <style name="titleStyle">
        <item name="android:fontFamily">sans-serif-condensed</item>
        <item name="android:textColor">#FFFFFF</item>
    </style>
    <!-- TextView styles -->
    <style name="labelStyle">
        <item name="android:typeface">monospace</item>
        <item name="android:textColor">#00FF00</item>
    </style>

    <color name="background">#cfcfcf</color>

Then, register your theme at the application level. Open AndroidManifest.xml and set the theme:

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

Individual widgets can override the theme by having their own style or directly setting properties like color and font.

Prevent Touch Event Theft in Android

In Android, touch events bubble up from child to parents as you would expect. However, a parent can choose to intercept all touch events targeted for one of its children and decide to veto dispatch of the event to the child. Widgets that scroll, like ListView or ExpandableListView, routinely do this to implement scrolling. But, this can lead to all kinds of nasty problems when you embed a child that needs touch gesture within such a parent. For example, adding a ViewPager within a ListView will cause the ViewPager to not work all that well.

Continue reading