Example project (and code presented here) on GitHubAt first, simple example.layout / activity_slide_show.xml<RelativeLayout xmlns:android=http://schemas.android.com/apk/res/android    xmlns:tools=http://schemas.android.com/tools    android:layout_width=match_parent    android:layout_height=match_parent    android:paddingLeft=@dimen/activity_horizontal_margin    android:paddingRight=@dimen/activity_horizontal_margin    android:paddingTop=@dimen/activity_vertical_margin    android:paddingBottom=@dimen/activity_vertical_margin >    <ImageView        android:id=@+id/image_view_1        android:layout_centerInParent=true        android:layout_width=wrap_content        android:layout_height=wrap_content/>    <ImageView        android:id=@+id/image_view_2        android:layout_centerInParent=true        android:layout_width=wrap_content        android:layout_height=wrap_content/></RelativeLayout>SlideShowActivitypublic class SlideShowActivity extends ActionBarActivity {    private static final List<String> IMAGE_PATHS = prepareImagePaths();    private SlideShowController slideShowController;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_slide_show);    }    @Override    protected void onStart() {        super.onStart();        slideShowController = startSlideShow();    }    @Override    protected void onStop() {        slideShowController.stop();        super.onStop();    }    private SlideShowController startSlideShow() {        SlideShow<String> slideShow = new SlideShow(String.class).items(imagePaths).period(5000).animationDuration(1000);        ImageView imageView1 = findImageViewById(R.id.image_view_1);        ImageView imageView2 = findImageViewById(R.id.image_view_2);        return slideShow.start(this, imageView1, imageView2, new SlideShowOptions.ImageViewsFromPaths());    }    private ImageView findImageViewById(int id) {        return (ImageView) findViewById(id);    }}All helper classes in the same package.Actually there is no need to subclass AlphaAnimation. But I create SlideShowAnimation to separate AlphaAnimation initialization and to add helper method duration() for method chaining.SlideShowAnimationpublic class SlideShowAnimation extends AlphaAnimation {    public static SlideShowAnimation newAppearance() {        return new SlideShowAnimation(0.0f, 1.0f);    }    public static SlideShowAnimation newDisappearance() {        return new SlideShowAnimation(1.0f, 0.0f);    }    public SlideShowAnimation(float fromAlpha, float toAlpha) {        super(fromAlpha, toAlpha);    }    public SlideShowAnimation duration(long duration) {        setDuration(duration);        return this;    }}I divide slide show into the two classes SlideShow and SlideShowController to separate stored data and code to manage slide show (start\stop, etc.). You can't share SlideShow instance to show several slide shows at the same time.SlideShowpublic class SlideShow<ItemType> implements Parcelable {    public static final Creator<SlideShow> CREATOR = new Creator<SlideShow>() {        @Override        public SlideShow createFromParcel(Parcel parcel) {            return new SlideShow(parcel);        }        @Override        public SlideShow[] newArray(int size) {            return new SlideShow[size];        }    };    private static final String PERIOD_UNIT = ms;    private static final long MIN_PERIOD = 100;    private static final long MIN_ANIMATION_DURATION = 100;    int currentImage;    private final Class<ItemType> itemType;    // required parameters    private List<ItemType> items;    private Long period;    // optional parameters    private Long animationDuration;    public SlideShow(Class<ItemType> itemType) {        this.itemType = itemType;        this.items = null;        this.period = null;        this.animationDuration = null;        this.currentImage = 0;    }    public SlideShow items(List<ItemType> items) {        if (items == null) {            throw new NullPointerException(items can't be null);        }        if (items.isEmpty()) {            throw new IllegalArgumentException(You couldn't set empty list of items.);        }        this.items = items;        return this;    }    List<ItemType> getItems() {        return new ArrayList<ItemType>(items);    }    public SlideShow period(long period) {        if (period < MIN_PERIOD) {            throw new IllegalArgumentException(                    You couldn't set period lower than  + MIN_PERIOD +   + PERIOD_UNIT);        }        this.period = period;        return this;    }    long getPeriod() {        return period;    }    public SlideShow animationDuration(long animationDuration) {        if (animationDuration < MIN_ANIMATION_DURATION) {            throw new IllegalArgumentException(                    You couldn't set minimum animation duration lower than  + MIN_ANIMATION_DURATION +  ms);        }        this.animationDuration = animationDuration;        return this;    }    Long getAnimationDuration() {        return animationDuration;    }    public <TransformedItemType, ViewType extends View> SlideShowController                            start(Context context,                                  ViewType view1,                                  ViewType view2,                                  SlideShowOption<ItemType, TransformedItemType, ViewType> slideShowOption) {        checkAllRequiredParametersAreSet();        SlideShowController controller = new SlideShowController(this, context, view1, view2, slideShowOption);        controller.start();        return controller;    }    private void checkAllRequiredParametersAreSet() {        for (Object requiredParameter : getRequiredParameters()) {            if (requiredParameter == null) {                throw new IllegalArgumentException(                        You should set all required parameters to start slide show                );            }        }    }    private Iterable<? extends Object> getRequiredParameters() {        return Arrays.asList(items, period);    }    public SlideShow(Parcel in) {        itemType = (Class<ItemType>) in.readSerializable();        items = new ArrayList<ItemType>();        in.readList(items, itemType.getClassLoader());        period = (Long) in.readSerializable();        animationDuration = (Long) in.readSerializable();        currentImage = in.readInt();    }    @Override    public void writeToParcel(Parcel out, int i) {        out.writeSerializable(itemType);        out.writeList(items);        out.writeSerializable(period);        out.writeSerializable(animationDuration);        out.writeInt(currentImage);    }    @Override    public int describeContents() {        return 0;    }}SlideShowControllerpublic class SlideShowController<ItemType, TransformedItemType, ViewType extends View> {    private static class Visibility {        static final int SHOW_VIEW = View.VISIBLE;        static final int HIDE_VIEW = View.GONE;    }    private final Object LOCK_START = new Object();    private final Object LOCK_STOP = new Object();    private final Handler handler = new Handler();    private final Context context;    private final int numberOfItems;    private final List<ItemType> items;    private final List<TransformedItemType> transformedItems;    private final long animationDuration;    private final long period;    private final SlideShow slideShow;    private final SlideShowOption<ItemType, TransformedItemType, ViewType> slideShowOption;    private boolean isStarted;    private boolean isStopped;    private ViewType view1;    private ViewType view2;    SlideShowController(SlideShow slideShow,                        Context context,                        ViewType view1,                        ViewType view2,                        SlideShowOption<ItemType, TransformedItemType, ViewType> slideShowOption) {        this.slideShowOption = slideShowOption;        this.slideShow = slideShow;        this.animationDuration = getAnimationDuration(context, slideShow);        this.items = slideShow.getItems();        this.numberOfItems = items.size();        this.transformedItems = newArrayListWithSize(items.size());        this.period = slideShow.getPeriod();        this.context = context;        this.view1 = view1;        this.view2 = view2;        this.isStarted = false;        this.isStopped = false;    }    private static long getAnimationDuration(Context context, SlideShow slideShow) {        Long duration = slideShow.getAnimationDuration();        if (duration == null) {            duration = (long) context.getResources().getInteger(R.integer.default_slideshow_animation_duration);        }        return duration;    }    private static <T> ArrayList<T> newArrayListWithSize(int size) {        ArrayList<T> list = new ArrayList<T>(size);        for (int i = 0; i < size; ++i) {            list.add(null);        }        return list;    }    void start() {        synchronized (LOCK_START) {            if (isStarted) {                throw new IllegalStateException(Slide show is already started);            }            isStarted = true;            handler.post(new Runnable() {                @Override                public void run() {                    slideShowOption.render(null, view1);                    slideShowOption.render(null, view2);                    slider.run();                }            });        }    }    private final Runnable slider = new Runnable() {        public void run() {            synchronized (LOCK_STOP) {                if (isStopped) {                    return;                }                try {                    slide();                } catch (Throwable exception) {                    exception.printStackTrace();                }            }        }    };    private void slide() {        startAnimationHideImage(view1);        startAnimationShowImage(view2, slideShow.currentImage);        handler.postDelayed(new Runnable() {            @Override            public void run() {                slideShowOption.render(null, view1);                view1.setVisibility(Visibility.HIDE_VIEW);                view1.clearAnimation();                view2.clearAnimation();                swapImageViews();                slideShow.currentImage = nextImageIndex();                handler.postDelayed(slider, period);            }        }, animationDuration);    }    private void startAnimationHideImage(final ViewType imageView) {        handler.post(new Runnable() {            @Override            public void run() {                Animation animationHide = SlideShowAnimation.newDisappearance().duration(animationDuration);                imageView.startAnimation(animationHide);            }        });    }    private void startAnimationShowImage(final ViewType view, final int index) {        final TransformedItemType transformedItem = getTransformedItem(index);        handler.post(new Runnable() {            @Override            public void run() {                view.setVisibility(Visibility.HIDE_VIEW);                slideShowOption.render(transformedItem, view);                Animation animationShow = SlideShowAnimation.newAppearance().duration(animationDuration);                animationShow.setAnimationListener(new Animation.AnimationListener() {                    @Override                    public void onAnimationStart(Animation animation) {                        handler.post(new Runnable() {                            @Override                            public void run() {                                view.setVisibility(Visibility.SHOW_VIEW);                            }                        });                    }                    @Override                    public void onAnimationEnd(Animation animation) {                        // skip                    }                    @Override                    public void onAnimationRepeat(Animation animation) {                        // skip                    }                });                view.startAnimation(animationShow);                view.bringToFront();            }        });    }    private TransformedItemType getTransformedItem(int index) {        TransformedItemType transformedItem = transformedItems.get(index);        if (transformedItem == null) {            ItemType item = items.get(index);            transformedItem = slideShowOption.transform(item);            transformedItems.set(index, transformedItem);        }        return transformedItem;    }    private void swapImageViews() {        ViewType temp = view1;        view1 = view2;        view2 = temp;    }    private int nextImageIndex() {        int index = slideShow.currentImage + 1;        return (index < numberOfItems) ? index : 0;    }    public void stop() {        synchronized (LOCK_START) {            if (!isStarted) {                throw new IllegalStateException(You couldn't stop not started slide show);            }            isStarted = false;            synchronized (LOCK_STOP) {                if (isStopped) {                    throw new IllegalStateException(You couldn't stop slide show more than once);                }                isStopped = true;                releaseResources();            }        }    }    private void releaseResources() {        String prefix = getClass().getName() + .releaseResources(): ;        for (int i = 0; i < transformedItems.size(); ++i) {            Log.d(Leonid, prefix + recycle item # + i);            slideShowOption.releaseResources(items.get(i), transformedItems.get(i));            items.set(i, null);            transformedItems.set(i, null);        }    }}SlideShowOptionpublic interface SlideShowOption<ItemType, TransformedItemType, ViewType extends View> {    TransformedItemType transform(ItemType what);    void render(TransformedItemType itemToRender, ViewType view);    void releaseResources(ItemType item, TransformedItemType transformedItem);}SlideShowOptionspublic class SlideShowOptions {    public static class ImageViewsFromPaths implements SlideShowOption<String,Bitmap,ImageView> {        @Override        public Bitmap transform(String what) {            return BitmapFactory.decodeFile(what);        }        @Override        public void render(Bitmap bitmap, ImageView view) {            BitmapDrawable drawable = new BitmapDrawable(view.getResources(), bitmap);            if (Build.VERSION.SDK_INT >= 16) {                view.setBackground(drawable);            } else {                view.setBackgroundDrawable(drawable);            }        }        @Override        public void releaseResources(String item, Bitmap bitmap) {            if (bitmap != null && !bitmap.isRecycled()) {                bitmap.recycle();            }        }    }    public static class TextViewsFromResourceIds implements SlideShowOption<Integer,Integer,TextView> {        @Override        public Integer transform(Integer what) {            return what;        }        @Override        public void render(Integer resId, TextView view) {            view.setText(resId);        }        @Override        public void releaseResources(Integer resId1, Integer resId2) {            // do nothing        }    }}
Helper to show simple slide show
java;android
Pardon me if I am underestimating your requirement, but if you are only swapping images using ImageView, I think you can achieve the same effect using one ImageView with a LevelListDrawable.If you look at the xml example at the top of the LevelListDrawble page, it shows how you can define a level-list by grouping multiple  tags, each consisting an integer value and a drawable reference. You can then set this level-list to an ImageView as its drawable.After that, you can use setImageLevel(int level) from the ImageView to set the drawable to display and you can also apply fade in / fade out animation on the ImageView before and after you change the images.This will eliminate the need of Bitmap decoding in your SlideShowOptions class.Also, if you need to resume an interrupted slideshow, you only need to remember which level your ImageView was displaying and you can resume from there.UPDATE:To achieve a simple cross-fade effect, try using a TransitionDrawable.Here is some pseudo code:Drawable[] drawableLayer = new Drawable[2];drawableLayer[0] = current drawabledrawableLayer[1] = drawable to be displayedTransitionDrawable td = new TransitionDrawable(d);td.setCrossFadeEnabled(true);imageView.setImageDrawable(td);td.startTransition(1000); // cross-fade durationOne downside I can think of right now is that you cannot set an Interpolator to the transition animation.