Logo Icon Logo
A Crowd-sourced Cookbook on Writing Great Android® Apps
GitHub logo Twitter logo OReilly Book Cover Art

Handling Orientation Changes: From ListView Data Values to Landscape Charting

Published? true
FormatLanguage: WikiFormat


Accomplish view changes on device orientation changes. For example, data values to be plotted are contained in a Portrait ListView, and upon device orientation a graphical display of the data values in a chart/plot is displayed.


Handle physical device orientation changes. Android emulator Control-F11 key combination will result in a Portrait to Landscape orientation change. A new View object is created on orientation changes. The Android method onConfigurationChanged(Configuration newConfig) can be overriden to accomodate for orientation changes.

Most important is to modify the AndroidManifest.xml to allow for the following: android:configChanges="orientation|keyboardHidden"


In this example, data values to be plotted are contained in a Portrait ListView. When the device/emualator is changed to counter-clockwise, a new Intent is launched to change to a plot/charting View to graphically display the data values. Charting is accomplished using the excellent DroidCharts package (http://code.google.com/p/droidcharts/).

The portrait version looks like this:

Rotate your device to landscape and you'll see this:

First is the AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>

    <uses-sdk android:minSdkVersion="13" android:targetSdkVersion="17"/>

	    <!--  Android 13 or later, configChange must include screenSize -->
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />

We start with the "main" Activity file, DemoList.java.

public class DemoList extends ListActivity implements OnItemClickListener {
	private static final String TAG = "DemoList";
	private ListView listview;
	private ArrayAdapter<String> listAdapter;

	// Our data for plotting
	private final double[][] data = { 
			{ 1, 1.0 }, 
			{ 2.0, 4.0 }, 
			{ 3.0, 10.0 },
			{ 4, 2.0 }, 
			{ 5.0, 20 }, 
			{ 6.0, 4.0 }, 
			{ 7.0, 1.0 }, 

	public void onCreate(Bundle savedInstanceState) {
		Log.d(TAG, "DemoList.onCreate()");

		// Set the View Layer

		// Get the Default declared ListView @android:list
		listview = getListView();

		// List for click events to the ListView items

		// Get the data to
		List<String> dataList = getDataStringList(data);

		// Create an Adapter to for viewing the ListView
		listAdapter = new ArrayAdapter<String>(this,
				android.R.layout.simple_list_item_1, dataList);

		// Bind the adapter to the ListView


	 * Convert the double[] to List<String> for display
	 * @param dataVals
	 * @return
	private List<String> getDataStringList(double[][] dataVals) {
		List<String> list = new ArrayList<String>();

		for (int i = 0; i < dataVals.length; i++) {
			String datum = "[" + String.valueOf(dataVals[i][0]) + ","
					+ String.valueOf(dataVals[i][1]) + "]";
		return list;

	public void onConfigurationChanged(Configuration newConfig) {
		Toast.makeText(this, "Orientation Change", Toast.LENGTH_SHORT).show();

		// Create an Intent to switch view to the Chart page view
		Intent intent = new Intent(this, DemoCharts.class);

		// The type "double[][]" does not go through as a SerializableExtra, so wrap in List.
		List<double[]> passedData = new ArrayList<double[]>();
		for (double[] dd : data) {
		// Pass parameters along to the next page
		intent.putExtra("param", (Serializable)passedData);

		// Start the activity

	public void onItemClick(AdapterView<?> parent, View view, int position,
			long duration) {
		// Upon clicking item in list pop a toast
		String msg = "#Item: " + String.valueOf(position) + " - "
				+ listAdapter.getItem(position);
		Toast.makeText(getApplicationContext(), msg, Toast.LENGTH_LONG).show();

When you rotate the screen, the data is wrapped in a List and passed to the graphics routine, DemoCharts.java.

import net.droidsolutions.droidcharts.core.data.XYDataset;
import net.droidsolutions.droidcharts.core.data.xy.XYSeries;
import net.droidsolutions.droidcharts.core.data.xy.XYSeriesCollection;

public class DemoCharts extends Activity {
	private static final String TAG = "DemoCharts";
	private final String chartTitle = "My Daily Starbucks Allowance";
	private final String xLabel = "Week Day";
	private final String yLabel = "Allowance";

	/** Called when the activity is first created. */
	public void onCreate(Bundle savedInstanceState) {
		Log.d(TAG, "DemoCharts.onCreate()");

		// Get the passed parameter values
		List<double[]> wrappedList = (List<double[]>) getIntent().getSerializableExtra("param");
		Log.d(TAG, "passed extra " + wrappedList + " is of type " + wrappedList.getClass());
		double[][] data = (double[][]) wrappedList.toArray(new double[wrappedList.size()][]);

		Log.d(TAG, "Data Param:= " + data);

		XYDataset dataset = createDataset("My Daily Starbucks Allowance", data);
		XYLineChartView graphView = new XYLineChartView(this, chartTitle,
				xLabel, yLabel, dataset);

	 * Creates an XYDataset from the raw data passed in.
	private XYDataset createDataset(String title, double[][] dataVals) {
		final XYSeries series1 = new XYSeries(title);
		for (double[] tuple : dataVals) {
			series1.add(tuple[0], tuple[1]);

		// Create a collection to hold various data sets
		final XYSeriesCollection dataset = new XYSeriesCollection();
		return dataset;

	public void onConfigurationChanged(Configuration newConfig) {
		Toast.makeText(this, "Orientation Change", Toast.LENGTH_SHORT).show();

		// Let's get back to our DemoList view
		Intent intent = new Intent(this, DemoList.class);

		// Finish current Activity

This will pass control back to DemoList if the device is rotated again.

The actual graphing is done in XYLineChartView.java.

import net.droidsolutions.droidcharts.awt.Rectangle2D;
import net.droidsolutions.droidcharts.core.ChartFactory;
import net.droidsolutions.droidcharts.core.JFreeChart;
import net.droidsolutions.droidcharts.core.axis.NumberAxis;
import net.droidsolutions.droidcharts.core.data.XYDataset;
import net.droidsolutions.droidcharts.core.plot.PlotOrientation;
import net.droidsolutions.droidcharts.core.plot.XYPlot;
import net.droidsolutions.droidcharts.core.renderer.xy.XYLineAndShapeRenderer;

public class XYLineChartView extends View {

		private final String mChartTitle;
		private final String mXLabel;
		private final String mYLabel;
		private final XYDataset mDataSet;

		/** The view bounds. */
		private final Rect mRect = new Rect();

		 * Creates a new graphical view.
		 * @param context
		 *          the context
		 * @param chart
		 *          the chart to be drawn
		public XYLineChartView(Context context, String chartTitle, String xLabel, String yLabel, XYDataset dataSet) {
				mChartTitle = chartTitle;
				mXLabel = xLabel;
				mYLabel = yLabel;
				mDataSet = dataSet;
		public XYLineChartView(Context context) {
			this(context, "A Title", "An X label", "A Y Label", null);

		protected void onDraw(Canvas canvas) {


				// Get the passed in data set
				final XYDataset dataset = mDataSet;

				// Create the Chart
				final JFreeChart chart = createChart(dataset);

				// Draw it
				chart.draw(canvas, new Rectangle2D.Double(0, 0, mRect.width(), mRect.height()));

		 * Creates a chart.
		 * @param dataset
		 *          the data for the chart.
		 * @return a chart.
		private JFreeChart createChart(final XYDataset dataset) {
				// create the chart...
				// (chart title, x-axis label, y-axis label,
				// dataset,orientation,orientation ,url)

				final JFreeChart chart = ChartFactory.createXYLineChart(mChartTitle, mXLabel, mYLabel, dataset, PlotOrientation.VERTICAL, true, true, false);

				Paint white = new Paint(Paint.ANTI_ALIAS_FLAG);

				Paint dkGray = new Paint(Paint.ANTI_ALIAS_FLAG);

				Paint lightGray = new Paint(Paint.ANTI_ALIAS_FLAG);

				// Set Chart Background color

				final XYPlot plot = chart.getXYPlot();


				final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
				renderer.setSeriesLinesVisible(0, true);

				// change the auto tick unit selection to integer units only...
				final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
				// final NumberAxis domainAxis = (NumberAxis) plot.getDomainAxis();
				// domainAxis.set(CategoryLabelPositions.STANDARD);

				return chart;


See Also:

You cannot limit the orientation to "portrait" for the starting activity in the AndroidManifest, as that now appears to prevent rotation. So the onConfigurationChanged routines should be smarter, figuring out what the current orientation is, and choosing the "correct" view.

The graphics currently draws extra rectangle regions around each line segment; it's not clear what causes this.

The updated code shown here is in our Github repo; the author's original version may be found in the source download link listed.


The source code for this project can be downloaded from http://www.filefactory.com/file/b43d470/n/AndroidOrientationChanges.zip.


The source code for this project is in the Android Cookbook repository, http://github.com/IanDarwin/Android-Cookbook-Examples/,in the subdirectory OrientationChanges.