Tag: Mobile

Programming Stuff

Avoiding Android App Crashes Caused by Device Orientation Changes

A challenge commonly faced when first developing in Android is the potentially frequent destruction and reconstruction of an Activity. The most common time this occurs is when the user rotates the device between horizontal and portrait orientations.

Many an app that runs fine during testing suddenly crashes when put into a user’s hands simply because the user tilted the device one way or another.

This crashing usually occurs because device orientation changes cause the Android framework to tear down the displayed Activity along within any contained Views, and then to fully reconstruct the Activity/View hierarchy. Any references to the Activity or to the Views within the Activity suddenly become invalid. Similarly any references within the Activity or Views that were set as a result of a user action or similar are now lost.

There are a number of ways to deal with this issue but one of the easiest is to take advantage of Fragments.

NOTE: You can use the configChanges attribute on your Activity’s manifest entry to prevent the teardown/reconstruction process caused by orientation changes but that has its own headaches.

Fragments won’t automatically resolve this issue because, by default, when the Activity is torn-down in response to an orientation change the Fragment contained within the Activity is also torn down along with any contained Views.

The solution lies in an underused method: Fragment.setRetainInstance.

Calling setRetainInstance with a value of true causes Android to preserve the Fragment across the teardown/reconstruction cycle of an Activity. Along with the Fragment, the Views or other object references contained within the Fragment or Views remain.

With setRetainInstance(true) called on a Fragment instance … when an orientation change occurs, Android…

  1. Holds a reference to the Fragment instance
  2. Tears down the old Activity instance
  3. Creates a new Activity instance
  4. Attaches the preserved Fragment instance to the new Activity instance

With that, the Fragment, contained Views and object references, remain intact.

Something to keep in mind though … because your Fragment instance will be moved between different Activity instances, you should avoid caching a reference to the Activity. Instead call Fragment.getActivity anytime you need to reference the Activity.

Jim talks more about Fragments in his Pluralsight course…

AndroidFragments_400x100

Programming Stuff

Android 4.x jumps from 45% of Android devices to nearly 55% overnight

That’s right if you look at the Android Dashboard Charts for the current period (period ending April 2, 2013 as of this writing) you’ll find that the combination of 4.0, 4.1, & 4.2 devices is 54.3%.

AndroidChart_2013-04-02

If you looked at the chart for the previous period you find that same family of devices had only 45% of all Android devices. How does one account for such a huge jump?

Well – one way is to change the way one counts. 🙂

You’ll find the following note on the Android Dashboard Page:

Note: Beginning in April, 2013, these charts are now built using data collected from each device when the user visits the Google Play Store. Previously, the data was collected when the device simply checked-in to Google servers. We believe the new data more accurately reflects those users who are most engaged in the Android and Google Play ecosystem.

So basically .. they now count devices that actually attach to Google Play rather than counting every single device that just happens to wake up periodically and send a heartbeat to the Google servers.

So the cynic might say that Google is skewing things for their own advantage (I’m not saying they’re unhappy with this new way of counting) but I don’t really think that’s the case here.

Honestly, most of us looking at those charts are interested in seeing what versions of the platform we should target with our apps. Those apps are distributed via Google Play … so, I agree that this is the “right way” to count.

For information on creating apps for Android 4.x, checkout Jim’s Pluralsight Course

Android40WhatsNew_350x100

 

Programming Stuff

Android Network Locates: When Enabled is NOT Enabled

The Network Location Provider is a key part of an Android location-based solution because it is far more power efficient than GPS and works in places where GPS doesn’t (of course GPS works in places the Network Location Provider doesn’t so it’s often good to use both).

The Network Location Provider capitalizes on the Wi-Fi and cellular radios within your phone to estimate location. This, of course, means that the Network Location Provide only works when those radios are working … and this is where we can easily run into trouble.

Prior to using a location provider, it’s always a good idea to confirm that the user hasn’t disabled it. According the Android docs, the code in the following function checks that the Network Location Provider is enabled.

  // Check that Network Location Provider reports enabled
  boolen isNetLocEnabled(Context context) {
    LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
    return lm.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
  }

What that code actually checks is whether the user has the Location Service enabled … basically … is the following box checked in the device settings?

LocationSettings_251x397

But what that code does not check is whether the phone’s Wi-Fi radio is turned on or if the phone is in Airplane mode …. that’s these device settings …

WiFiSettings

AirplaneSettings

If the user disables Wi-Fi, the Network Location Provider can no longer use the Wi-Fi system and will be limited to cellular towers for locates. Using cellular towers generally provides very limited accuracy (in the area of 1 to 3 kilometers … not accurate enough for most systems).

If the user puts the phone in Airplane mode, neither Wi-Fi nor the cellular radio are available .. in this case, the Network Location Provider will simply never report any location values.

And here’s the problem – in both of these cases, LocationManager.isProviderEnabled will still report that the Network Location Provider is enabled. This is a false positive.

To safely use the Network Location Provider, we need to explicitly check the Wi-Fi and Airplane Mode, settings. The following code shows how we can check those.

  // Check Wi-Fi is on
  boolean confirmWiFiAvailable(Context context) {
    ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo wifiInfo = cm.getNetworkInfo(ConnectivityManager.TYPE_WIFI);
    return wifiInfo.isAvailable();
  }

  // Check Airplane Mode - we want airplane mode off
  boolean confirmAirplaneModeOff(Context context) {
    int airplaneSetting =
      Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0) ;
    return airplaneSetting == 0;
  }

Using the above 2 functions along with the isNetLocEnabled function from earlier in this post, we can now use the following function to determine if the Network Location Provider is really usable.

  bool isNetLocUsable(Context context) {
    return
      isNetLocEnabled(context) &&
      confirmAirplaneModeOff(context) &&
      confirmWiFiAvailable(context);
  }

With that, we can now be sure that the Network Location Provider is enabled and the underlying services it relies upon are also available.

For complete certainty, in addition to checking the Wi-Fi and Airplane Mode settings prior to using the Network Location Provider, we should also continuously monitor the Wi-Fi and Airplane Mode settings (notification mechanisms exist for each) the entire time we’re using the Network Location Provider. Doing so allows our application to respond accordingly should the user change either setting while we’re using the Network Location Provider.

This post is adapted from Jim’s Plurasight Course

AndroidLBS_436x155

For more information about Jim and his courses visit his Pluralsight Author Page

Programming Stuff

Android ADB reports device is “offline”

Device upgrades are so often a good-news-bad-news situation … and so was the case of my device’s upgrade to Android 4.2.2 over the weekend.

I love this latest version of Android – in addition to just generally being a good update, it also has a sweet new camera and, some cool new clock/stopwatch/timer features.

The new camera features are especially cool for me as I’m right in the midst of writing a new Android developer course Android Photo and Video Programming for Pluralsight.

But like so many exciting weekend events, Monday often comes with regret … and so it was today.

I fire up my favorite Android IDE (currently JetBrains IntelliJ IDEA), connect my device, then launch the debugger … and it’s then that I see “waiting for device” … I keep waiting, waiting, waiting.

To check things out, I do an ‘adb kill-server’ followed by an ‘adb devices’ and I see…

List of devices attached
99999C99999D999         offline

That’s something I don’t see too often so I do the standard stuff … reboot my desktop computer, reboot the device. Always the same result … the device reports being offline

The Answer….

I resolved the issue by upgrading to the latest version of the Android SDK Platform-tools – for me, that’s version 16.0.2:

AndroidSDKManager-PlatformTools16.0.2

Just something to remember … you may have to run the SDK Manager more than once to get all of the latest updates.

In my case, I had to…

  • Run the SDK Manager
  • Execute ‘Install packages…’
  • Exit the SDK Manager
  • Restart the SDK Manager
  • Execute ‘Install packages…’

Only then did I get the necessary updates to resolve the offline issue so that I now see the much more familiar (and welcome) device message in ADB.

List of devices attached
99999C99999D999         device