ViewFlipper isn't showing all of its children

368 Views Asked by At

In my android application, there's a ViewFlipper and its children are added dynamically. On different emulators everything works all right, but the problem occurs when the application is running on actual devices.

The problem is that only the first child is displayed (image or video), and when it should flip to the next one, it shows nothing for as long as the other children display time is. When I print in logcat the count of ViewFlipper's children or the index of currently displayed child, it's all correct, it just isn't showing any of the other children.

For now, I accidentally discovered that all the views get displayed correctly when I lock and then unlock the screen or when application goes to background and then comes back to foreground. If a rotation happens after this fix, it goes bad again.

I tried to call onPause() and onResume() on purpose, since it works fine when leaving and coming back to foreground, but it doesn't help. Also, I tried to show a dialog-like view over the layout with this ViewFlipper, make it last as long as the first child plus one second, just so it could flip to the second one, and then destroy it, but it turned out that that didn't work every time.

Since I wasn't able to fix this kind of behavior programmatically, I hope that someone will be able to help me with this.

Here's the code that's relevant to this part of application.

The function called from onInit(), used to set children of ViewFlipper:

public static void setMedia(final WeakReference<MainActivity> activityWeakReference) {
    flipperObjects.clear(); // flipperObject is an ArrayList of Media objects (contain information about the url and duration od image or video)
    ((ViewFlipper) activityWeakReference.get().findViewById(R.id.media)).removeAllViews();

    for (final Media m : currentMedia.getMedia()) {
        if (m.getLocalUrl() != null && !m.getLocalUrl().equals("null")) { // Images and videos are previously downloaded on device
            if (m.getLocalUrl().matches(".*\\.(?:jpg|jpeg|png)")) {
                final ImageView imageView = new ImageView(activityWeakReference.get());
                File imgFile = new File(m.getLocalUrl());
                    imageView.setImageBitmap(BitmapFactory.decodeFile(imgFile.getAbsolutePath()));
                imageView.setScaleType(ImageView.ScaleType.FIT_XY);

                boolean shouldAdd = true;

                for (ReklamaStavka r : flipperObjects) {
                    if (r.getLocalUrl().equals(m.getLocalUrl())) {
                        shouldAdd = false;
                        break;
                    }
                }

                if (shouldAdd) {
                    flipperObjects.add(m);
                    ((ViewFlipper) activityWeakReference.get().findViewById(R.id.media)).addView(imageView);
                }
            } else {
                final ScaledVideoView videoView = new ScaledVideoView(activityWeakReference.get());
                videoView.setVideoURI(Uri.fromFile(new File(m.getLocalUrl())));

                videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
                    @Override
                    public void onPrepared(MediaPlayer mp) {
                        videoView.start();
                    }
                });

                MediaController mediaController = new MediaController(activityWeakReference.get());
                mediaController.setVisibility(View.GONE);
                mediaController.setAnchorView(videoView);

                videoView.setMediaController(mediaController);

                videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        mp.reset();
                    }
                });

                videoView.setOnErrorListener(new MediaPlayer.OnErrorListener() {
                    @Override
                    public boolean onError(MediaPlayer mp, int what, int extra) {
                        Log.e("ERROR", "Video isn't played");
                        return true;
                    }
                });

                boolean shouldAdd = true;

                for (Media m1 : flipperObjects) {
                    if (m1.equals(m)) {
                        shouldAdd = false;
                        break;
                    }
                }

                if (shouldAdd) {
                    flipperObjects.add(m);
                    ((ViewFlipper) activityWeakReference.get().findViewById(R.id.media)).addView(videoView);
                }
            }
        }
    }

    currentIndex = 0;
    endIndex = ((ViewFlipper) activityWeakReference.get().findViewById(R.id.media)).getChildCount();
}

The function called after the previous one, used to execute flipping after certain number of seconds:

private static void nextChild(final WeakReference<MainActivity> activityWeakReference) {
    int delaySeconds = 0;

    if (flipperObjects.size() > 0) {
        ((ViewFlipper) activityWeakReference.get().findViewById(R.id.media)).setDisplayedChild(currentIndex);
        delaySeconds = flipperObjects.get(currentIndex).getDuration();

        currentIndex++;

        if (currentIndex >= endIndex) {
            currentIndex = 0;
        }
    }

    if (nextImageHandler == null) {
        nextImageHandler = new Handler(Looper.getMainLooper());
    }

    nextImageHandler.postDelayed(new Runnable() {
        @Override
        public void run() {
            if (running) {
                nextChild(activityWeakReference);
            }
        }
    }, delaySeconds * 1000);
}

Here's my onDestroy() function:

@Override
protected void onDestroy() {
    running = false;
    flipperObjects.clear();
    ((ViewFlipper) findViewById(R.id.media)).removeAllViews();
    currentIndex = 0;
    endIndex = 0;

    if (nextImageHandler != null) {
        nextImageHandler.removeCallbacksAndMessages(null);
    }

    super.onDestroy();
}

And here's the activity_main.xml file:

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#000000"
    android:fitsSystemWindows="true"
    tools:context=".MainActivity">

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:fitsSystemWindows="true">

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guidelineTop"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="0" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guidelineLeft"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="0" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guidelineRight"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_percent="1" />

        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/guidelineBottom"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="horizontal"
            app:layout_constraintGuide_percent="1" />

        <ViewFlipper
            android:id="@+id/media"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:contentDescription="@string/app_name"
            app:layout_constraintBottom_toTopOf="@+id/guidelineBottom"
            app:layout_constraintEnd_toStartOf="@+id/guidelineRight"
            app:layout_constraintStart_toStartOf="@+id/guidelineLeft"
            app:layout_constraintTop_toTopOf="@+id/guidelineTop"
            tools:srcCompat="@tools:sample/backgrounds/scenic" />

    </androidx.constraintlayout.widget.ConstraintLayout>

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header"
        app:itemBackground="@android:color/transparent"
        app:menu="@menu/drawer_menu" />

</androidx.drawerlayout.widget.DrawerLayout>
0

There are 0 best solutions below