Tuesday, 7 October 2014

Building multiple APKs inside Android Studio


Build variants are a huge feature for Android development. The use cases for such a feature are many. It can be as simple as having a free version of your app and a paid version. Or maybe you are making generic software that can be sold to many companies that all want they're own branding.

Whatever your use case may be, Gradle comes to the rescue. Not only can you configure your variants but you can also select which ones actually get built. You are probably already aware of the standard way to do this in Android Studio which is to use the "Build Variants" tool window and select the variant that you want to build.


This builds one variant at a time and is very practical while you are developing as it allows you to quickly switch from one variant to the another.

Once development is done, you will want to build all of your release variants for final testing and distribution. You can do this in Android Studio as well. Simply open the "Gradle Tasks" tool window, which is usually on the right. You will see many tasks that start with 'assemble', double click on one of those and your APKs will be created.

For example, double clicking on 'assembleRelease' will create all your release apks.
From the docs:
Building and Tasks
We previously saw that each Build Type creates its own assemble task, but that Build Variants are a combination of Build Type and Product Flavor.
When Product Flavors are used, more assemble-type tasks are created. These are:
1) assemble[Variant Name]
2) assemble[Build Type Name]
3) assemble[Product Flavor Name]
1) allows directly building a single variant. For instance assembleFlavor1Debug.
2) allows building all APKs for a given Build Type. For instance assembleDebug will build both Flavor1Debug and Flavor2Debug variants.
3) allows building all APKs for a given flavor. For instance assembleFlavor1 will build both Flavor1Debug and Flavor1Release variants.
The task assemble will build all possible variants.
Note the "Recent tasks" section which allows you to quickly execute previously run tasks.

You'll also note that the tasks that you run are added to your Configurations dropdown. This allows you to quickly access them by hitting Shift-F10.



And that's it! I hope that this helps you out.

Thursday, 21 August 2014

Localized getString() with parameters


getString

We all know the getString() method which is available in the Resources class and in the Context class. However, did you know that there is also a second version of that method that accepts parameters that will be merged into a format string? You can find the Android documentation here.

Simple example

Here is an example of this version of getString():

In your xml file:
 <string name="hello_person">Hello %1$s, how are you?</string>  

In your Java file:
 String userName = getUserName();  
 String hello = getResources().getString(R.string.hello_person, userName);  

This simplifies your code a lot. And it really is but a convenience at you can see in the source Android code:

 public String getString(int id, Object... formatArgs) throws NotFoundException {  
   String raw = getString(id);  
   return String.format(mConfiguration.locale, raw, formatArgs);  
 }  

Multipe placeholders example

You can also have more than one placeholder in your original string, and you can use more than one type:

In your xml file:

 <string name="hello_person_age">Hello %1$s, you are %2$d years old</string>   

In your Jave file:

 String userName = getUserName();  
 int age = getAge();  
 String hello = getResources().getString(R.string.hello_person_age, userName, age);   

Context class

And how about the version in the Context class?  It just delegates to the method in the Resources class:

 public final String getString(int resId, Object... formatArgs) {  
   return getResources().getString(resId, formatArgs);  
 }  

Thanks to +Wolfram Rittmeyer for tuning me into this version of getString()!

Tuesday, 19 August 2014

Automating ADB over Wi-Fi for multiple devices


Here is a script that will scan through your Android devices that are connected to ADB via a USB cable and then connect them all via ADB over Wi-Fi.

Usage is very simple.  If needed, modify the script with your IP range and then run the script. You will need to run this script every time you want to connect to your Wi-Fi network.

Note that I haven't yet found a way to test if a device is already connected via Wi-Fi so you may get errors such as "unable to connect to 192.168.1.2:5555:5555".  You'll know that the device is already connected if you see the double port value at the end.

Thanks to +Tony Owen for the original idea and to +Wolfram Rittmeyer with the help on the script.

Please feel free to expand this script or modify it. Let me know if you do so that I can update this post!


 #!/bin/bash  
   
 #Modify this with your IP range  
 MY_IP_RANGE="192\.168\.1"  
   
 #You usually wouldn't have to modify this  
 PORT_BASE=5555  
   
 #List the devices on the screen for your viewing pleasure  
 adb devices  
 echo   
   
 #Find USB devices only (no emulators, genymotion or connected devices  
 declare -a deviceArray=(`adb devices -l | grep -v emulator | grep -v vbox | grep -v "${MY_IP_RANGE}" | grep " device " | awk '{print $1}'`)  
   
 echo "found ${#deviceArray[@]} device(s)"  
 echo   
   
 for index in ${!deviceArray[*]}  
 do  
   echo "finding IP address for device ${deviceArray[index]}"  
   IP_ADDRESS=$(adb -s ${deviceArray[index]} shell ifconfig wlan0 | awk '{print $3}')   
     
   echo "IP address found : $IP_ADDRESS "  
     
   echo "Connecting..."  
   adb -s ${deviceArray[index]} tcpip $(($PORT_BASE + $index))  
   adb -s ${deviceArray[index]} connect "$IP_ADDRESS:$(($PORT_BASE + $index))"  
   
   echo  
   echo  
 done  
   
 adb devices -l  
 #exit  
   

Friday, 21 February 2014

Copying a template project

Today I fell upon a problem that really baffled me for a while.  Android Studio just refused to create my R class.  No lint problems, no compile problems (besides the missing R), nothing.  It just failed. I searched on the net but problems like that are difficult to find answers to because Android Studio is in such fluctuation that the answers no longer apply.

I tried cleaning my project. Rebuilding my project. It was then suggested that I invalidate my caches and restart Android Studio (you can find that in the File menu) but that didn't work.  I deleted my build directory. Nothing would work. Then it dawned on me...

I was trying to create a project from a template project that I created.  The Coloroos project will have many coloring books and each will require it's own project, so I wanted to create a template project and just copy paste it and go. What I did was copy and paste the project and then open it in Android Studio. There lies the problem. In order to properly reset everything I need to delete the .idea directory from the pasted project and then import it into Android Studio. Once I did that, it compiled and ran immediately.

Thursday, 23 January 2014

Creating distinct PendingIntents

With my recent work on the BiPolar widget I came upon an interesting bug in my code.  One that made me scratch my head while walking through the code.

The widget is rather simple, it displays the current temperature in Celsius and Fahrenheit simultaneously and allows you to click on it if you want to share the current temperature with your favourite social media site. Everything seemed to be working fine until I tried installing multiple instances of the widget.  At the point, clicking on any widget would always share the weather of the last installed widget.  I figured that I had a logic problem in my code and poured over it repeatedly.  Nothing.

Here is the original erroneous code :

// Create the Intent that will be sent when the widget is clicked on
Intent intent = new Intent(this, BiPolar.class);
intent.setAction(CLICK_ACTION);
intent.putExtra(CLICK_WIDGET_ID, appWidgetId);

// Create the PendingIntent for the RemoteViews
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

//attach an on-click listener to the widget
views.setOnClickPendingIntent(R.id.root, pendingIntent);

That code is inside of a loop that goes through all of the appWidgetIds and appears correct.  The problem lies in the fact that PendingIntent are reused by the system.  If the PendingIntent that would be returned by getBroadcast() or getActivity() is considered equal to one that already exists then a new one is not created, rather a copy of an existing one is returned. The problem lies in that Extras are not considered in the equality comparison. So in this case every call for a new PendingIntent returned the same PendingIntent over and over again.

From the documentation : 

A PendingIntent itself is simply a reference to a token maintained by the system describing the original data used to retrieve it. This means that, even if its owning application's process is killed, the PendingIntent itself will remain usable from other processes that have been given it. If the creating application later re-retrieves the same kind of PendingIntent (same operation, same Intent action, data, categories, and components, and same flags), it will receive a PendingIntent representing the same token if that is still valid, and can thus call cancel() to remove it.
Because of this behavior, it is important to know when two Intents are considered to be the same for purposes of retrieving a PendingIntent. A common mistake people make is to create multiple PendingIntent objects with Intents that only vary in their "extra" contents, expecting to get a different PendingIntent each time. This does not happen. The parts of the Intent that are used for matching are the same ones defined by Intent.filterEquals. If you use two Intent objects that are equivalent as per Intent.filterEquals, then you will get the same PendingIntent for both of them.

The Solution

So how to we make sure that the requested PendingIntent is different from the existing ones?  The solution is rather easy.  Again from the documentation : 

you will need to ensure there is something that is different about them to associate them with different PendingIntents. This may be any of the Intent attributes considered by Intent.filterEquals, or different request code integers supplied to getActivity(Context, int, Intent, int), getActivities(Context, int, Intent[], int), getBroadcast(Context, int, Intent, int), or getService(Context, int, Intent, int).
In my case the fix was very easy, just add the appWidgetId as the request code to the parameters of getBroadcast.
// Create the PendingIntent for the RemoteViews
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, appWidgetId, intent, FLAG_UPDATE_CURRENT);

Although that field is not yet used, and may never be, it is enough for the system to distinguish the PendingIntent as being different from the other and to create a new one.

Thursday, 21 November 2013

AsyncTask

Smart phones are great, they are like having a mini computer in your pocket. Smart phones suck, they are like having a mini computer in your pocket. You don't just pick up the phone and dial the number of the person with which you want to converse. First you must boot up the phone, find and then launch your telephone application, search for your friend's name, then within that entry you must choose with of their phone numbers you want to call. A nightmare. The last thing that you want within this process are applications that are laggy and do not respond to user input. Applications need to be snappy. And that's where multi-threading comes in to save the day.

When a process is created for your application, its main thread (aka GUI thread) is dedicated to running a message queue that takes care of managing the top-level application objects (activities, broadcast receivers, etc) and any windows they create. Only this thread can safely manipulate GUI objects and their state.
If you have to do some lengthy processing (such as complicated math, DB requests, SD card requests, network requests) then you should create a second thread (aka worker thread) to accomplish this work so that the initial thread remains snappy and responsive. However, remember that the worker thread can not update GUI objects. You can create your own threads, and communicate back with the main application (so that it may update GUI objects) thread through a Handler, as will be explained later on.
The simplest way to create a second thread is to use the android.os.AsyncTask

AsyncTask 
AsyncTask will create a worker thread for you and will also take care of the implementation details of communicating between your worker thread and your main thread. All you have to do is fill in the methods with your own code. Simple as pie.

The easiest way to use AsyncTask is as a private anonymous class within your Activity class. This will give you easy access to your Activity's member variables and any other resource you may need. You declare your new AsyncTask class like this :

private class LoadMatchDataAsyncTask extends AsyncTask<Void, Void, Void> {

As you can see AsyncTask is a templated class which receives three types. In this example I have simply used three Voids. These types are used for input values, updates and return values respectively. I personally find it more convenient to use the class' constructor for input values.

public LoadMatchDataAsyncTask(long playerId, long matchId) {
   mPlayerId = playerId;
   mMatchId = matchId;
}

But even this approach may be superfluous if you create your class as a private anonymous class.

The basic methods that you will want to override are

protected void onPreExecute()
protected Void doInBackground(Void...args)
protected void onProgressUpdate(Void... values)
protected void onPostExecute(Void return)

The onPreExecute(), onProgressUpdate() and onPostExecute() methods are executed within the context of your main thread and therefore allow you to update the UI. Such as putting up a progress dialog, setting text values and so on. The doInBackground() method is executed within the context of a worker thread that the AsyncTask class will create for you; this is where you will do all your lengthy processing. Inside of the doInBackground() method is also where you will make calls to publishProgress() in order to update your GUI to keep the user notified of what is going on. There are a few more methods that you may override, such as onCancel() which you will find in the documentation for AsyncTask.

To start your thread using the technique shown above, instantiate it and call execute(). In our example we declared no input type (Void) so the execute() method has no arguments.

new LoadMatchDataAsyncTask().execute();

The following graphic shows in which thread each method is run, as well as when the methods are called in relation to each other. Notice that in this graphic I have used three distinct types for the input, update and return parameters to make it easier for you to see where there are used.


As per the AsyncTask documentation there are a few rules that must be followed for this class to work properly
  • The task instance must be created on the UI thread.


Thread and Handler
The second way to create a thread in your code is to use java.lang.Thread to perform your background processing and an android.os.Handler to communicate back to your GUI thread. This is what AsyncTask does, but implementing it yourself gives you more freedom and control of your thread's execution.
First off, the Thread. Again we will implement our Thread as an anonymous class for simplicity. With the Thread class you must override the run() method, and this is where you will put your long running code.

Thread longRunningCode = new Thread() {
   @Override
   public void run() {
      // Count one BILLION dollars.
   }
};

longRunningCode.start();

And that's it. You now have a new thread counting up your ransom money. Of course your stand alone thread can't communicate with the user to update a progress dialog or anything of the sort. And of course like anything that gives you more control and power, it's as simple as pi [sic].

The way to communicate back to the GUI thread is through the usage of a Handler object.

When you instantiate a Handler it is automatically attached to the message queue belonging to the thread in which it is created. So if you want to communicate from a worker thread to a GUI thread you must instantiate a Handler in the GUI thread and then access it from the worker thread.

mHandler = new Handler();

The communication is done via posting a Runnable or sending a Message. A Runnable is a snippet of code that can be added to the Handler's message queue and then processed when appropriate.

Runnable mUpdateProgressBar = new Runnable () {
   public void run() {
      progressBar.setProgress(progressPercent);
   }
};

This technique will allow us to update the GUI object progressBar

Thread longRunningCode = new Thread() {
   @Override
   public void run() {
      // Count one BILLION dollars.

      // Display update in GUI thread
      mHandler.post( mUpdateProgressBar);
   }
};

As this point our AsyncTask example and our Thread/Handler example have the same functionality: a piece of long running code, and timely updates to the GUI. However the Thread class and the Handler class both have more tricks up their sleeves.



The Thread Class
Threads are a very powerful tool, and in Ben's famous words: “with great power comes great responsibility.”
The Thread class has many public methods, some of the more interesting are:
dumpStack() which prints out the current stack for this thread.
GetAllStackTraces() to retrieve the stack traces for all the currently live threads.
GetState which returns the current state of the thread
SetName which names the thread (so you can easily find it in DDMS)
setPriority()
sleep()

There are also many methods used for synchronization which is beyond the scope of this article.

The Handler class
As previously mentioned the handler class is bound to the message queue of the thread in which it was instantiated. This allows for much more than just posting a Runnable to the queue. With the Handler class you can also handle the messages which are sent to the thread by overriding the handleMessage(Message msg) method. Allowing you to send specialized messages from the worker thread and processing them within the main thread as you wish.

You also have control as to where your Messages and/or Runnables will be posted within the message queue using methods such as postAtFrontOfQueue(), postAtTime() and postDelayed(). These methods can help you design applications that can poll a network resource at a specific time, or wait an amount of time before launching your operation.

So which technique should I use?
As always, then answer to that question is: it depends. If you are new to threading, you will probably want to stick to AsyncTask for a little bit, just to get a better grasp of what's involved. In all my research I did not see an advantage for AsyncTask over Thread except for the fact that it is easier to code. However, after viewing the code for AsyncTask, there is no downside to using AsyncTask, there are no expensive lookups or a pile of conditionals. After that, it all depends on the job, and your context. For easy jobs in an application that is not very resource hungry you will want to go with AsyncTask. But if you require any kind of specialized processing you are going to want to get accustomed to using bare bones Java threading.