Inertia

July 30th, 2011

Inertia is the resistance of any physical object to a change in its state of motion or rest, or the tendency of an object to resist any change in its motion.

For me, this also describes my tendencies toward side projects like my Pingus project. When I last worked on Pingus a couple of months ago, I updated the underlying AndEngine libraries and found a ton of breaking changes. I put Pingus on the shelf until I had more time to look at the breakage and how to solve it. The AndEngine changes are pretty significant and I’m going to need to rethink portions of Pingus in order to get things running correctly again.

Now my personal inertia is kicking in and causing me to put off this rework for a while. To me, this is the biggest difference between work and hobby projects… I don’t have to work on hobby projects if I don’t want to. Thus, Pingus is “on a break” for a while until I find the energy to bring it up to date relative to the underlying game engine.

In the meantime, I decided I wanted to spend a bit of time taking a look at Android’s App Widget support. Until I started digging into the documentation and examples, I had always assumed that a widget was provided a Canvas to draw directly on to the home screen. To me this seemed like it would have been the easiest way for developers to develop widgets.

It turns out that Android AppWidgets don’t work that way at all. AppWidgets are built on top of Remote Views. According to the Android documentation, Remote Views are

A class that describes a view hierarchy that can be displayed in another process. The hierarchy is inflated from a layout resource file, and this class provides some basic operations for modifying the content of the inflated hierarchy.

A Remote View is created in one process and passed into the process that owns the Android home screen. It is actually a Parcelable object, however due to class loading issues, there is only a very small number of Views and Widgets that are allowed to be passed across the process boundary. For anything that involves relatively complex graphical rendering, the only real way to drive the widget’s contents is by specifying a very simple widget layout:


    
    
	    

and then sending bitmaps to the image view:

	private void updateWidget(Context context, AppWidgetManager appWidgetManager) {
		Bitmap bitmap = Bitmap.createBitmap(100, 100, Config.ARGB_8888);
		Canvas canvas = new Canvas(bitmap);
		
		this.drawable.draw(canvas);

		RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
		views.setImageViewBitmap(R.id.imageview, bitmap);

		ComponentName componentName = new ComponentName(context, MyAppWidgetProvider.class);
		appWidgetManager.updateAppWidget(componentName, views);
	}

While this seems like a high overhead way to handle updates to the widget contents, I have to assume that the Android developers had a good reason for doing things like this. I can only hope that there are some tricks being done in the Android implementation that lower the cost of this operation. Given that I’ve just managed to get this to work at all, I imagine there are is a lot of room for improvement in my use of this API. However, I found it confusing enough to figure out how to do and thought others might benefit from my pain.

  1. Tijl
    July 30th, 2011 at 23:01 | #1

    The reasons are twofold: security and stability for the home screen (none of your code running persistently in the homescreen procress) and power usage (essentially the widget decides when it should be updated graphically rather than you)

  2. July 31st, 2011 at 06:55 | #2

    The second item is definitely where some types of widgets lose out. While I understand the thinking there, it makes some types of widgets extremely difficult to implement.

Comments are closed.