Thursday, November 3, 2011

NullPointerException in IntentService

0x000000

NullPointerException.  My all time favorite Java exception.  Probably the single most common exception in Java.  Richly ironic, isn't it?  For a language that doesn't have "pointers?"

Anyway, my latest encounter with NPE was one thrown from the Android framework in the constructor of my IntentService-derived class.

Try it:

public class MyService extends IntentService {



    public MyService() {

        super("MySericeName");

        String s = this.getPackageName();




NullPointerException at
android.content.ContextWrapper.getPackageName(ContextWrapper.java:120)

Here's the inheritance hierarchy:

The no-args constructor of Service, which extends ContextWrapper, calls super(null).  So wrapper is wrapping null.

ContextWrapper doesn't do much of anything but delegate calls to the real context that it's given.  So if you try to make any calls on the Context during construction, you will get an NPE.

Your IntentService derived class, although it gets instantiated when the app starts, will not get a Context until it gets "attached."

That happens before your onHandleIntent method gets invoked.  So anything that needs a Context will have to wait until onHandleIntent gets called.


Launching an Intent by Action

I had some trouble getting my implicit intent to launch.  An implicit intent is one that uses just the action name string, without specifying the actual class of the action to launch.

This is an explicit Inent:

new Intent(context, com.example.MyActivity.class);


This is an implicit Intent:

new Intent("com.example.my_action");


My app has two different flavors (see earlier post on supporting this), and each one needs to handle a pending intent (in a user Notification) with different Activity classes.  So, the common code, rather than trying to figure out what Activity class to start -- that would be evil indeed, a library having a dependency on its clients -- it specifies an Action in the pending intent, like this:


PendingIntent.getActivity(
    this, -1, new Intent("MY_ACTION")...


Here is the snippet from the manifest:


<activity android:name="com.example.MyActivity" >
  <intent-filter>
        <action android:name="MY_ACTION" /> 
 </intent-filter>

</activity>

Problem was that I would tap on the notification, but nothing would happen.  I finally noticed the following line in LogCat:

WARN/IntentResolver(61): resolveIntent failed: found match, but none with Intent.CATEGORY_DEFAULT

Two things I did wrong.  Both were clearly stated in the documentation, but I missed it.

First, the action name MUST be prefixed with the application package, as declared in the manifest.

Second, the intent-filter element must contain the android.intent.category.DEFAULT category, or else Android will not find your activity to launch. 

So the proper intent filter in the manifest should look like this:


<intent-filter>
  <action android:name="com.example.MY_ACTION" /> 
  <category android:name="android.intent.category.DEFAULT" />

</intent-filter> 


And, of course, the action specified in the Intent constructor should be "com.example.MY_ACTION".

Works great after doing this.

Tuesday, October 25, 2011

Are Anonymous Inner Classes Evil in Android Apps?

Not intrinsically evil, but potentially problematic enough that they ought to be avoided (just in Android apps)?


I have now encountered two problems -- one handling dialogs, the other a leaked Intent Receiver -- that were both the result of not carefully using anonymous inner classes in an Android app.

Part of the reason it is tricky is that you don't have total control over the life cycle of your application's classes in Android.

In the dismissDialog defect, which is described here, if the Thread were a separate class that did not have access to my activity's privates, then I would be forced to deal with the dependency in a more explicit way.  The problem would have been more immediately obvious.

I love anonymous inner classes.  They're the closest thing we've got to closures in Java.  But in an Android app, it seems wise to either avoid them altogether, or think very carefully about what you're doing when you use one.



An Android Worker Thread: Neat, Plausible and Wrong



So you're smart.  You know not to block the main (aka UI) thread in your Android app.  So you put your heavy work in a background thread.  Excellent.

You're also kind enough to display a progress dialog, since the user can't do much in your app until your work is done.

And you're even educated enough to know that you really should call dismissDialog on the UI thread.

But then you do something dumb, like I did.  Your solution looks like mine (below).

It works great at first.  The dialog pops up, the thread does its work, and 5 seconds later, the dialog goes away.


public class ScratchActivity extends Activity {

    private static final String TAG = "ScratchActivity";
    
    private ProgressDialog dialog = null;
        
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                doSomethingInBackground();
            }

        });
    }

    protected void doSomethingInBackground() {
        showDialog(1);
        
        Thread someBackgroundProcess = new Thread() {

            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    allDoneNow();

                } catch (Exception ex) {
                    Log.d(TAG, "ahhhh", ex);
                }
            }
        };
        someBackgroundProcess.start();
    }
    
    private void allDoneNow() {
        
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                
                try {
                 dismissDialog(1);
                 
                }catch(Exception ex) {
                    Log.d(TAG, "ahhhh", ex);
                }
            }
        }); 
    }
    
     @Override
    protected Dialog onCreateDialog(int id) {
         Log.d(TAG, "onCreateDialog " + id);
         
        if (dialog == null) {
            dialog = new ProgressDialog(this);
        }
        return dialog;
    }

Trouble Strikes
Then you do the unthinkable.  You press the button to show the dialog, and before the dialog gets dismissed, you rotate your device into landscape mode.

You wait.  And wait.  And wait...

The stupid black dialog never goes away.  So you smartly check LogCat and discover:

no dialog with id 1 was ever shown !!

10-25 11:26:41.738: DEBUG/ScratchActivity(2279): ahhhh
10-25 11:26:41.738: DEBUG/ScratchActivity(2279): java.lang.IllegalArgumentException: no dialog with id 1 was ever shown via Activity#showDialog
10-25 11:26:41.738: DEBUG/ScratchActivity(2279):     at android.app.Activity.missingDialog(Activity.java:2600)
10-25 11:26:41.738: DEBUG/ScratchActivity(2279):     at android.app.Activity.dismissDialog(Activity.java:2585)
10-25 11:26:41.738: DEBUG/ScratchActivity(2279):     at com.scratch.ScratchActivity$3.run(ScratchActivity.java:68)


"It sure the heck was shown!"  You scream at the stupid framework.  "If it wasn't shown, how is it on my screen?"

Idiotic voodoo framework. 
Oh, oops
After a little noodling on the problem for a while -- even wondering whether there is a bug in the framework -- you (by which I mean me) realize the problem is indeed your own stupid code, by which I mean yours, not mine ;-)  

The problem is subtle, insofar as it involves not what is explicit in the code, but what is implicit in the code.  When you create your anonymous inner class on line 26 above --
        ...  new Thread() {
        ...
                allDoneNow();
...

What ScratchActivity instance is allDoneNow going to execute with?  The anonymous class gets an implicit reference to the current ScratchActivity instance.  Ok, fine.

Problem is, when you change orientation, Android -- by default -- destroys your activity and creates a new one.  That means the anonymous inner class is now referring to the old ScratchActivity instance (which is now torn-down).  The activity on screen is a new instance.

Now, if you use showDialog to create a dialog, the Activity class adds the dialog to a list of dialogs that it is managing (so that it can dismiss it, restore it, etc. during the activity life cycle).

Later, in Activity.onDestroy, the list of so-called "managed dialogs" gets set to null.  So it makes sense, then, that calling dismissDialog on a destroyed activity must fail.

Fabulous!  So, let's change our code to ensure that the background thread will call the right ScratchActivity instance.

One thing we have to consider, though, is a kind of race condition.  We have to ensure that we do not try to fetch a reference to the activity while a configuration change is impending.  [Orientation changes are considered configuration changes.]

The simplest way to do that is by having the code execute on the UI thread.  Fortunately, we've already done that by using Activity.runOnUiThread.

Once on the UI thread, it is guaranteed that the call to dismissDialog will occur entirely before or entirely after the orientation change.

Now that we've got that covered, the most straightforward thing to do is add a static field to hold the currently active Activity.  Then we set that field in onCreate.

    private static Activity currentActivity = null;
    public static synchronized Activity getCurrentActivity() {
        return currentActivity;
    }
    
    public static synchronized void setCurrentActivity(Activity activity) {
        currentActivity = activity;
    }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        setCurrentActivity(this);
        super.onCreate(savedInstanceState); 
 

Then,  allDoneNow, instead of calling just dismissDialog(1); calls getCurrentActivity().dismissDialog(1);

Problem solved, right?

Ugh, Not Yet
This code is bad too!  We just caused a memory leak.  When the activity is all done -- for real, not because of an orientation change -- currentActivity (a static field) continues to hold a reference to the activity, which keeps it, and the entire object graph that it references, in memory.

Simple, fix, though.  Just be sure to call setCurrentActivity(null) in onDestroy.

So an acceptable solution might look like this. Although, there are other ways to do this, and it sure would be nice if the framework helped a little more.  Maybe Activity itself could provide this capability.

public class ScratchActivity extends Activity {

    private static final String TAG = "ScratchActivity";
    
    private ProgressDialog dialog = null;
        
    private static Activity currentActivity = null;
    
    public static synchronized Activity getCurrentActivity() {
        return currentActivity;
    }
    
    public static synchronized void setCurrentActivity(Activity activity) {
        currentActivity = activity;
    }
    
    @Override
 protected void onDestroy() {
  super.onDestroy();
  setCurrentActivity(null);
 }
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        Button button = (Button) findViewById(R.id.button);
        button.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View view) {
                doSomethingInBackground();
            }

        });
    }

    protected void doSomethingInBackground() {
        showDialog(1);
        
        Thread someBackgroundProcess = new Thread() {

            @Override
            public void run() {
                try {
                    Thread.sleep(5000);
                    allDoneNow();

                } catch (Exception ex) {
                    Log.d(TAG, "ahhhh", ex);
                }
            }
        };
        someBackgroundProcess.start();
    }
    
    private void allDoneNow() {
        
        runOnUiThread(new Runnable() {

            @Override
            public void run() {
                
                try {
                 dismissDialog(1);
                 
                }catch(Exception ex) {
                    Log.d(TAG, "ahhhh", ex);
                }
            }
        }); 
    }
    
     @Override
    protected Dialog onCreateDialog(int id) {
         Log.d(TAG, "onCreateDialog " + id);
         
        if (dialog == null) {
            dialog = new ProgressDialog(this);
        }
        return dialog;
    }


There are other solutions to this problem of course, but this one is simple enough for now.

All of this brings me to the topic of my next post:

Are Anonymous Inner Classes Evil for Android Apps?




Thursday, October 20, 2011

Android ScrollView and Horizontal Scrolling

Don't waste your time trying to make ScrollView scroll horizontally.  It doesn't.  And the API docs clearly say so. 

For horizontal scrolling, use HorizontalScrollView.

If you need both horizontal and vertical scrolling, like I did, it works to embed the two.  Looks like this:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:fillViewport="false"
    android:fadeScrollbars="true"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

<HorizontalScrollView 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    
>
    <RelativeLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content">


Monday, October 17, 2011

Phone Handed

Are you phone ambidextrous?

Will either hand do?  Just one?
Always?
Both?
Sideways?

Do you use thumbs or index fingers, perhaps?
Maybe knuckles with no gaps.

The indexing user, pointing as she swipes
like an accuser of her screen,
how many times she gripes.

They say it is coming, the curved phone screen.
How will your fingers fair?
Or will you just stand there and stare?

So, how do you use your phone?

Friday, October 14, 2011

aRRRR!! Getting R Into a Different Package

R
In the post on creating an Android library to support multiple application files, I ran into the problem of what the Android SDK considers -- at least internally -- the "manifest package."
That package gets used for too many things, I think.   I believe that the application ID, the application's user ID and the resource package should all be independently determinable.  Alas they are not.  At least not yet.

Some day you might need to control the specific package that R gets generated in.  I'm not sayin it's a good idea.  But somebody will want to do it.  Just sayin...

So here is a hack of a whorkaround [sic] to get R into the fixed package of your nightmarish fancy...


If you're using ANT to build your app, then things are a little easier.  If you're using only ADT, there are a couple of extra steps.

First thing to do, if you're using ADT only, is to create ant build files: build.properties and build.xml.  Simplest way to do this is to create a dummy Android Ant project and copy those files:

android create project -n duh -p duh -k org.duh -t 2 -a duh

Once you have your and build files, open build.xml.  Scroll down.  Close to the bottom, you should see a line like this:

<setup />

Just above that line, copy and paste the following xml:
    <target name="-dirs">
            <echo>Creating output directories if needed...</echo>
            <mkdir dir="${resource.absolute.dir}" />
            <mkdir dir="${jar.libs.absolute.dir}" />
            <mkdir dir="${out.absolute.dir}" />
            <if condition="${manifest.hasCode}">
                <then>
                    <mkdir dir="${gen.absolute.dir}" />
                    <mkdir dir="${out.classes.absolute.dir}" />
                </then>
            </if>
    </target>

    <target name="-resource-src" depends="-dirs">
        <if condition="${manifest.hasCode}">
            <then>
                
                <echo>Generating R.java / Manifest.java from the resources using custom aapt execution...</echo>         
                <exec executable="${aapt}" failonerror="true">
                            <arg line="package -v --custom-package ${resource.custom.package} -M AndroidManifest.xml -I ${android.jar} -J ${gen.absolute.dir} -S ${resource.absolute.dir}" />
                            <arg value="-m"/>
                        </exec>
            </then>
            <else>
                <echo>hasCode = false. Skipping...</echo>
            </else>
        </if>
    </target>
    <target name="resource-src-fix" depends="-resource-src" />



Now, open build.properties and enter this line:

resource.custom.package=org.inanity.domestic

If you are building with ANT, then that's all you have to do.  You can now change your package in your manifest without it moving your R.java file.

If you are using ADT, there will be one more hack you'll want to do.  Every time the Android Pre Compiler builder runs (which will be frequently if you have automatic builds turned on), it will clobber your beloved R.java.

Here's what you can do about that.


Go to Project... Properties...

  1. Select Builders and click on the New... button.  
  2. Select "Ant Builder" from the list and click Ok. 
  3. In the Main tab, click the Browse Workspace... button to find your modified build.xml file.  
  4. Switch to the Targets tab and select the "resource-src-fix" target wherever you want it.
  5. Name your builder something sensible -- like Resource_compensation_builder -- and click Ok.
Now Make sure your new builder is set to execute AFTER the Android Pre Compiler builder -- because it is that builder that will clobber your file.  Highlight it and use the up/down buttons to get it there.  Should look like this:


Disclaimer: I never said that any of this this was a good idea.  Just that it can be done. :-)