Pages

Saturday, January 18, 2014

Testing 1, 2, 3

Google Play has a built-in ability to do beta testing, without having to make the app available to the public.  From the developer dashboard, you create the app, then select "APK" from the menu at the side.  The screen that comes up has tabs for production, beta, and alpha.  "Production" means available to the public, while the test options will only be available to a selected group of people.  To do beta testing, select the "beta" tab, and follow the instructions to upload the APK.

But there are a few ambiguities that can cause problems:

Google Groups

This could cause trouble, since you may not know what they are.  If you're on Google+, you may mistakenly think they are referring to the "Circles" concept.  But no, "Groups" are another concept, and they are just glorified mailing lists.  That's good, because it means that your testers don't have to join Google+, or any Google services, you just need their e-mail addresses.

So you can create a Group, and populate it with the e-mail addresses of anyone you want to test your app.  You then have to connect the Group with your app: Still in the "APK" section, and on the "Beta" tab, click "manage list of testers".  This brings up a dialog, which asks you to "Add Google Groups or Google+ Communities".  That's misleading, because entering the name of your Group won't work; you need to add the group's e-mail address.  You can find that in the Group's "Settings" screen.  It'll be something@googlegroups.com.

Production vs. Published

"Production" means available to the public.  "Published" means made available to someone.  That is, when you upload your APK, it is not yet "Published", and your testers cannot yet get it. 

Worse, it's not immediately obvious how you Publish it.  However, if you're in the Developer Console, and you have selected your App, in the upper right, you may see a button that asks, "Why can't I publish?"  Clicking on it will tell you the remaining things you have to take care of.  Surprisingly, you have to add a variety of items relating to the App's marketplace appearance, even if you are still in Beta.  These include screenshots, and a description, as well as assurances that you've met Android's guidelines.  Once you've handled all these issues, the button becomes a "Publish" button.  Pressing it will make your App "Published," and thus available for testing.  Now if you press "Manage list of testers," the dialog will give you a URL that you can e-mail to your testers to get the App.  Surprisingly, you have to cut-and-paste this link, rather than it being automatically sent out.

Tuesday, May 22, 2012

Escaping String Resources

I just stumbled on the fact that quotes won't work in Strings in xml resource files (That's single or double quotes.)  More to the point, I stumbled on the fact that the Eclipse resource editor doesn't automatically translate forbidden characters into the desired format, nor does it indicate that the string you have just typed is illegal.  So you could be stuck with the generated resource class (the "R" class) refusing to recompile for no readily apparent reason.  (You'd have to switch to the xml view on the resource editor to see an indication of where the error is.

So how do you get around the problem?  This guide shows how you can either put the entire string in quotes or, as in C, precede the apostrophe/quote with a backslash.  But surprisingly, you can't use HTML-style escape characters (such as ")

Tuesday, March 13, 2012

Moving work off the UI Thread

This is a mistake that I've seen a lot of people make (by which I mean me.)  I can't speak for other platforms, but in both Swing and Android, there is only one thread running the UI.  In other words, while your handler method is running in response to a button press or some other UI action, nothing else is getting done in the interface, including listening for any other input by the user.


That's fine when your handler is only doing small actions in response the user actions.  But if you have to do something that could take several seconds, you should start a new thread to do it so the UI thread can go back to its work.

But where this can really trip you up is an activity that takes an unpredictable amount of time.  Or, more specifically, an activity that usually takes a short time, but could drag on.  Network communications are a place where this can happen: the network may react quickly most of the time, but become congested occasionally.  I imagine many people will be making this mistake in mobile programming.

There are a number of different ways of approaching Threads in Android, which I'll start reviewing in upcoming posts.  The simplest way is to use the traditional Java way: create a class implementing the Runnable interface, then create a Thread object, passing an instance of your Runnable class as a parameter.

You'll find this approach is quite limited because your new thread can't do anything to affect the UI - only the UI's thread can.  So if you want the interface to react to the actions of the background thread, you'll want to try a different approach.

Monday, January 16, 2012

Expiring Debug Certificate

I recently found that the application I was working on was mysteriously not compiling.  Eclipse wasn't pointing out any errors in the code, so it lead to a brief moment of panic/frustration.

It turns out this was just the Android SDK's way of wishing me a happy anniversary as an Android developer:  My signing certificate had expired.

[Aside for anyone who has stayed blissfully ignorant of the signing process]  All Android applications have to be signed with a certificate to identify the creator.  By default, your applications are signed with a special Debug Certificate which can't be used to distribute your application.  This certificate is automatically created when you first compile an application, and it expires after one year.  Once it expires, you need to recreate it. [End of aside]

You can find an explanation of it at the Android Developer site.  I'll save you some trouble and quote the easy fix for the problem here:

To fix this problem, simply delete the debug.keystore file. The default storage location for AVDs is in ~/.android/ on OS X and Linux, in C:\Documents and Settings\<user>\.android\ on Windows XP, and in C:\Users\<user>\.android\ on Windows Vista and Windows 7.

The other problem is you'll have to reinstall apps you installed using the old certificate.  And while you're at it, this would be a good time to read the whole page on signing and familiarise yourself with the concept. You know, just in case you hadn't bothered to learn about it until now.

Tuesday, October 25, 2011

A New TabHost Perspective

I've been trying to use the TabHost.  If you look it up at the Android API Reference, the entry on any of the associated Views (TabHost or TabWidget) send you to this tutorial.  It begins by briefly mentioning that you can use the Tab set up to flip between views, or entire activities.  Having said this, it chooses the latter, and steps you through a process that includes creating separate Activities and layout files for each tab.

Part way through this process, I found myself wondering why it's such an involved process.  With so much Android UI defined by xml files, why do I have to create all these classes and then hook them up programmatically?

So I went looking for another example.  A Google search for tab demos revealed an alternate example.  Especially surprising is that this simpler example is also on the Android Developer site.  In this approach, you lay out all the tab content in one xml file, and don't have to create any activities for each tab.  Though you still have to create the tabs and connect them to their content in code, which seems un-Androidy.  But overall it's a more straightforward approach if your tab set-up is relatively simple.

Really, I don't know why they link you to the more complex tutorial, but now you know there's an alternative.  Also, whichever approach you use, here's some advice: When you put the TabHost and the FrameLayout in a LinearLayout, remember to set the orientation to vertical.  It would be really embarrassing if you got that wrong and then couldn't figure out where the content went.  I'm guessing.

Wednesday, October 12, 2011

Activity Constructor vs. onCreate

This isn't explicitly stated in many tutorials, but something I've learned from experience.  The onCreate method in Activities is called when the Activity starts, and books show all the set-up work being done in that method.  But what about the Activity constructor?  Can you use it for any initialisation work?

No.  In general you should leave it alone, as much of the Android API will not work if called from the Activity constructor.  For instance, trying to inflate a layout will raise an exception.  So restrict your initialisation to onCreate.

Thursday, July 28, 2011

What does "@+id" mean?

One thing I've discovered recently is how the "@+id/" works in the layout files. 

Most tutorials show you adding android:id="@+id/id_name" to the View element in the layout xml file.  Then if you have to refer to the id in another element (say, to position it in a RelativeLayout) you refer to it without the "+" (i.e. android:id=@id/id_name.)  It gives the impression that the rule is you simply use the + when indicating a View's id, but not when you are referring to another View's id.

Actually, that's not how it works.  Really the rule is that you use the + when you are introducing a new id that you have not used before, then leave out the + when referring to a previously used id.  Most often you'll end up using the id for the first time when defining a View's id, so most people can remain oblivious of how it really works.

Why would you refer to a View before creating it?  You might wish to do that with a RelativeLayout, aligning a View with one you will be defining later in the file, as with this example:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:text="blue"
        android:background="#ff0000ff"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:id="@+id/blue"
        android:layout_toLeftOf="@+id/red"
    />
    <TextView
        android:id="@id/red"
        android:layout_width="wrap_content"
        android:layout_height="fill_parent"
        android:text="red"
        android:background="#ffff0000"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
    />
</RelativeLayout>

That will produce the following, in which the "blue" View can be positioned to the left of the "red" View, even though "red" isn't defined until later in the file: