July 23, 2014

Rotational Forces, Part Three

First, we showed you how rotation events can be handled just like any other lifecycle occurence, such as when your application is evicted from RAM. Then, we showed you how you can use onRetainNonConfigurationInstance() as an alternative, so you can hang onto more data than can fit into a Bundle, such as an open socket.

Today, we’ll cover yet another alternative for handling rotation events in Android: telling Android to mind its own business, allowing you to handle everything involved with the rotation yourself. Once again, this is an adapted excerpt from Version 1.4 of The Busy Coder’s Guide to Android Development.

Even onRetainNonConfigurationInstance() may be too intrusive to your application. Suppose, for example, you are creating a real-time game, such as a first-person shooter. The “hiccup” your users experience as your activity is destroyed and recreated might be enough to get them shot, which they may not appreciate. While this would be less of an issue on the T-Mobile G1, since a rotation requires sliding open the keyboard and therefore is unlikely to be done mid-game, other devices might rotate based solely upon the device’s position as determined by accelerometers.

The third possibility for handling rotations, therefore, is to tell Android that you will handle them completely yourself and that you do not want assistance from the framework. To do this:

  1. Put an android:configChanges entry in your file, listing the configuration changes you want to handle yourself versus allowing Android to handle for you
  2. Implement onConfigurationChanged() in your Activity, which will be called when one of the configuration changes you listed in android:configChanges occurs

Now, for any configuration change you want, you can bypass the whole activity-destruction process and simply get a callback letting you know of the change.

To see this in action, let us modify the sample application from the previous blog post. The Java code is significantly different, because we are no longer concerned with saving our state, but rather with updating our UI to deal with the layout.

But first, we need to make a small change to our manifest:

[sourcecode lang='xml']

package="com.commonsware.android.rotation.three"
android:versionCode="1"
android:versionName="1.0.0">

android:label="@string/app_name"
android:configChanges="keyboardHidden|orientation">







[/sourcecode]

Here, we state that we will handle keyboardHidden and orientation configuration changes ourselves. This covers us for any cause of the “rotation” – whether it is a sliding keyboard or a physical rotation. Note that this is set on the activity, not the application – if you have several activities, you will need to decide for each which of the tactics outlined in this chapter you wish to use.

The Java code for this project is shown below:

[sourcecode lang='java']
public class RotationThreeDemo extends Activity {
static final int PICK_REQUEST=1337;
Button viewButton=null;
Uri contact=null;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setupViews();
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==PICK_REQUEST) {
if (resultCode==RESULT_OK) {
contact=data.getData();
viewButton.setEnabled(true);
}
}
}

public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);

setupViews();
}

private void setupViews() {
setContentView(R.layout.main);

Button btn=(Button)findViewById(R.id.pick);

btn.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
Intent i=new Intent(Intent.ACTION_PICK, Uri.parse(“content://contacts/people”));

startActivityForResult(i, PICK_REQUEST);
}
});

viewButton=(Button)findViewById(R.id.view);

viewButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
startActivity(new Intent(Intent.ACTION_VIEW, contact));
}
});

viewButton.setEnabled(contact!=null);
}
}
[/sourcecode]

The onCreate() implementation delegates most of its logic to a setupViews() method, which loads the layout and sets up the buttons. The reason this logic was broken out into its own method is because it is also called from onConfigurationChanged().

Now when the device orientation changes, our activity is not destroyed. Instead, onConfigurationChanged() is called, and we handle the rotation ourselves. This gives us the utmost in flexibility.