The ViewFlipper is a really useful view on android. It allows you to build up a set of pages and easily move between them. At its simplest, you call the showPrevious and showNext methods on the view and it moves through your pages and wraps back to the beginning when it gets to the end. At the other end of the spectrum you can incorporate gestures to enable the user to swipe through the pages, and with the ViewFlipper handling just three views you can allow the user to move through any number of pages.

In this first article, I am just going to show you a simple application so that you can see what it does. I will go into the more complex examples in other posts.

So, this application is going to show two buttons at the top to allow the user to go to the next and previous pages. Beneath them will be the ViewFlipper which contains three TextViews.

So firstly create a new android project called ViewFlipperSimple and change the res/layout/main.xml file to be the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent"
    android:orientation="vertical">
    <LinearLayout
        android:layout_width="wrap_content" 
        android:layout_height="wrap_content">
        <Button 
            android:id="@+id/previous" 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="Prev" />
        <Button 
            android:id="@+id/next" 
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" 
            android:text="Next" />
    </LinearLayout>
    <ViewFlipper
        android:id="@+id/flipper" 
        android:layout_width="fill_parent" 
        android:layout_height="fill_parent">
        <TextView
            android:text="view 1"
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" />
        <TextView
            android:text="view 2"
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" />
        <TextView
            android:text="view 3"
            android:layout_width="fill_parent" 
            android:layout_height="fill_parent" />
    </ViewFlipper>
</LinearLayout>

Now replace the contents of ViewFlipperSimple.java with:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.example.android.viewflippersimple;
 
import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ViewFlipper;
 
public class ViewFlipperSimple extends Activity implements OnClickListener {
    Button next;
    Button previous;
    ViewFlipper flipper;
 
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
 
        flipper = (ViewFlipper)findViewById(R.id.flipper);
        next = (Button) findViewById(R.id.next);
        previous = (Button) findViewById(R.id.previous);
 
        next.setOnClickListener(this);
        previous.setOnClickListener(this);
    }
 
    @Override
    public void onClick(View v) {
        if (v == next) {
            flipper.showNext();
        }
        else if (v == previous) {
            flipper.showPrevious();
        }
    }
}

You can see on line 10 that the Activity class implements the OnClickListener class. This is so that our activity knows when the user clicks on the buttons: lines 24 and 25 tell the buttons that we want to know about the clicks.

The onClick method determines which button was pressed and calls showNext or showPrevious on the ViewFlipper.

That is all we need to do for the application to work, so try running it and see what happens.

Unfortunately, that is not the whole story, because on android 2.1 there is a problem with changing orientation. I also get the crash on android 2.2. An IllegalArgumentException occurs in the onDetachedFromWindow method of ViewFlipper. You can find out about the about the problem here. In the emulator, with the num lock key off press the 7 key to change to landscape and then the 9 key to go to back to portrait. Did the app crash? If not try going back and forth between landscape and portrait quickly. After the crash you should see something like this in the Debug window:

Thread [<1> main] (Suspended (exception IllegalArgumentException))
    WindowManagerImpl.removeViewImmediate(View) line: 226
    Window$LocalWindowManager.removeViewImmediate(View) line: 436
    ActivityThread.handleDestroyActivity(IBinder, boolean, int, boolean) line: 3684
    ActivityThread.handleRelaunchActivity(ActivityThread$ActivityRecord, int) line: 3789
    ...

The java exception is something like:

java.lang.IllegalArgumentException: Receiver not registered: android.widget.ViewFlipper$1@44b6ab90
    at android.app.ActivityThread$PackageInfo.forgetReceiverDispatcher(ActivityThread.java:667)
    at android.app.ApplicationContext.unregisterReceiver(ApplicationContext.java:747)
    at android.content.ContextWrapper.unregisterReceiver(ContextWrapper.java:321)
    at android.widget.ViewFlipper.onDetachedFromWindow(ViewFlipper.java:104)

There is a workaround for this bug. Which is to create a wrapper class around ViewFlipper and catch the exception. To fix our application create a new class called MyViewFlipper and change the code to be:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.widget.ViewFlipper;
 
public class MyViewFlipper extends ViewFlipper {
    public MyViewFlipper(Context context) 
    {
        super(context);
    }
 
    public MyViewFlipper(Context context, AttributeSet attrs) 
    {
        super(context, attrs);
    }
 
    @Override
    protected void onDetachedFromWindow() 
    {
        if (Integer.parseInt(Build.VERSION.SDK) &gt;= 7) 
        {                          
            try 
            {                                  
                super.onDetachedFromWindow();                          
            } 
             catch (IllegalArgumentException e) 
            {                                  
                Log.e("MyViewFlipper", "Android issue 6191: http://code.google.com/p/android/issues/detail?id=6191");                          
            } 
            finally 
            {                                  
                super.stopFlipping();                          
            }                  
        }  
        else 
        {                          
            super.onDetachedFromWindow();                  
        }  
    }
}

All we need to do to use our extended ViewFlipper is to modify the AndroidManifest.xml file. Change “ViewFlipper” to be “com.example.android.viewflippersimple.MyViewFlipper” on lines 21 and 37.

Run the application again and try changing the orientation. The application should function as you would expect. If you look in the LogCat window in eclipse you will see the red exception line that the MyViewFlipper class puts out when it absorbs the exception.

Download

You can download this example from here.

To add this example to eclipse go to File|New|Android Project, select “Create project from existing source” and then browse to the folder inside of the downloaded zip file.

,

By day I am a C#/SQL developer, and have been for… well, too long to remember. But now Android is here, and it is fascinating stuff, so now I develop Android apps in my spare time. There is a lot of stuff on the internet that has really helped get to grips with developing for Android, but quite often there was a step missing in the information that left me piecing bits together. So this blog will be about the blockers that I encounter as I learn.

Some of the stuff will be from other blogs, but the idea is not to regurgitate what others have done, but to provide complete solutions that others can use. I should have posted the missing details as comments on the blogs that I did find useful, but in my haste to get up-to-speed, I did not. That’s life. In the future I will add comments, as I hope readers of this blog will.

If I feel the urge I will post on C#, SQL and other developer type stuff along the way.

, ,