Предварительная загрузка WebView во время заставки видео в Android

Я работаю в приложении для Android и хочу предварительно загрузить заставку, пока webView загружает веб-страницу, НО у меня есть локальное видео .mp4 вместо изображения.

Таким образом, как только пользователь нажмет на приложение, начнется воспроизведение .mp4 (4 секунды). В течение этих 4 секунд webView должен предварительно загрузить веб-страницу, SO когда видео закончится, показать мою веб-страницу (если веб-страница уже загружена), в противном случае подождите в заставку, пока веб-страница не будет готова, а затем загрузите ее.

Вот моя основная активность:

public class MainActivity extends AppCompatActivity {

    private WebView webView;
    public static final Object SPLASH_LOCK = new Object();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        String myURL = "https://www.testpage.com";

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        webView = (WebView) findViewById(R.id.webView);
        webView.getSettings().setAllowContentAccess(true);

        /** tell the webView to enable javascript execution */
        WebSettings webSettings = webView.getSettings();
        webSettings.setJavaScriptEnabled(true);

        webView.getSettings().setDomStorageEnabled(true);
        webView.getSettings().setDatabaseEnabled(true);

        webSettings.getAllowFileAccessFromFileURLs();
        webSettings.getAllowUniversalAccessFromFileURLs();

        /** Load the HTML page */
        webView.loadUrl(myURL);

        /** Call the JavaScriptInterface within the WebView */
        webView.addJavascriptInterface(this, "jsinterface");

        startActivity(new Intent(this, AnimationScreenActivity.class));

        /** Enable Javascript in WebView
        / callback for browser events */
        webView.setWebViewClient(new WebViewClient(){

            @Override
            public void onPageFinished (WebView webView, String url) {
                synchronized (SPLASH_LOCK) {
                    SPLASH_LOCK.notifyAll();
                }
            }
        });  
    }
}

Вот AnimationScreenActivity:

public class AnimationScreenActivity extends AppCompatActivity{

    private static String TAG = AnimationScreenActivity.class.getName();
    private static long MAX_SPLASH_TIME = 10000; 

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.animation_screen);

                try {
                    VideoView videoHolder = (VideoView) findViewById(R.id.videoView1);
                    Uri video = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.myvideo);
                    videoHolder.setVideoURI(video);

                    videoHolder.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                        public void onCompletion(MediaPlayer mp) {

                            jump();
                        }
                    });
                    videoHolder.start();
                } catch (Exception ex) { jump(); }

    }

    private void jump() {
        new Thread() {
            @Override
            public void run() {
                synchronized (MainActivity.SPLASH_LOCK) {
                    // wait for notify or time-out
                    try {
                        MainActivity.SPLASH_LOCK.wait(MAX_SPLASH_TIME);
                    } catch (InterruptedException ignored) {}
                }
                finish();
            }
        }.start();

    }
}

Вот файл activity_main.xml:

    <?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="test.test_android.MainActivity">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</RelativeLayout>

Вот файл animation_screen_activity.xml:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/animation_screen"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="test.test.AnimationScreenActivity">

    <VideoView
        android:id="@+id/videoView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
        android:layout_alignParentRight="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_alignParentEnd="true"
        android:layout_alignParentTop="true"
        android:layout_alignParentBottom="true" />

</RelativeLayout>

И, наконец, Manifest.xml, где я установил MainActivity как LAUNCHER:

<activity android:name=".MainActivity"
                  android:theme="@style/FullScreenTheme"
                  android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        </activity>

        <activity android:name=".AnimationScreenActivity"
                  android:theme="@style/FullScreenTheme"
                  android:screenOrientation="portrait"/>

Итак, что у меня есть до сих пор, так это то, что как только пользователь запускает приложение, запускается .mp4, а когда .mp4 заканчивается THEN, он ждет 10 секунд в AnimationScreenActivity и THEN он загружает веб-страницу.

Любая помощь будет оценена!


person Johny    schedule 16.03.2017    source источник


Ответы (3)


У вас может быть одно действие, в котором есть то, что у вас есть в двух действиях, с помощью ViewSwitcher (или ViewAnimator) для переключения между макетами. Это также устранит необходимость в объекте SPLASH_LOCK.

Во время загрузки переключите ViewSwitcher (или ViewAnimator) на макет видео, а когда вы закончите загрузку страницы, переключите его на макет WebView.

Я сделал простой код, чтобы упростить переключение между представлениями. При желании вы можете использовать его:

public static void setViewToSwitchTo(@NonNull final ViewAnimator viewAnimator, @NonNull final View viewToSwitchTo) {
    if (viewAnimator == null)
        return;
    if (viewAnimator.getCurrentView() == viewToSwitchTo)
        return;
    for (int i = 0; i < viewAnimator.getChildCount(); ++i)
        if (viewAnimator.getChildAt(i) == viewToSwitchTo) {
            viewAnimator.setDisplayedChild(i);
            break;
        }
}

public static void setViewToSwitchTo(@NonNull final ViewAnimator viewAnimator, @IdRes final int viewIdToSwitchTo) {
    if (viewAnimator == null)
        return;
    if (viewAnimator.getCurrentView().getId() == viewIdToSwitchTo)
        return;
    for (int i = 0; i < viewAnimator.getChildCount(); ++i)
        if (viewAnimator.getChildAt(i).getId() == viewIdToSwitchTo) {
            if (viewAnimator.getDisplayedChild() == i)
                return;
            viewAnimator.setDisplayedChild(i);
            return;
        }
}

Использование:

setViewToSwitchTo(viewSwitcher, R.id.webViewLayout);

or:

setViewToSwitchTo(viewSwitcher, webViewLayout);

Вы даже можете иметь анимацию при переключении между представлениями, используя атрибуты «inAnimation» и «outAnimation».

И, если код становится слишком большим, вы можете использовать фрагменты вместо представлений. Один для WebView, а другой для видео.

Что касается многократного вызова onPageFinished, вам нужно проверить, какой из них является тем, который вы считаете действительно законченным. Поскольку каждый веб-сайт отличается и может иметь несколько фреймов, вам придется добавить эту логику. Если вы хотите, вы можете отслеживать onPageStarted, как показано здесь:

Кстати, если вы измените ориентацию в манифесте, обратите внимание, что, поскольку у вас есть WebView, вам придется подумать, что делать с изменением ориентации, потому что он плохо восстанавливает свое состояние.


РЕДАКТИРОВАТЬ:

Вот файл макета:

<ViewSwitcher xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/viewSwitcher"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="test.test_android.MainActivity">

    <VideoView
        android:id="@+id/videoView1"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="match_parent" 
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen" />

</ViewSwitcher>

в onCreate используйте код обоих ваших действий и добавьте это, чтобы перейти к видео:

setViewToSwitchTo(viewSwitcher, R.id.videoView1);

и это, чтобы перейти к webView (когда он выполнил загрузку, в вашем случае):

setViewToSwitchTo(viewSwitcher, R.id.webView);
person android developer    schedule 03.04.2017
comment
Спасибо за Ваш ответ! onPageFinished не вызывается несколько раз. Причина, по которой я меняю ориентацию в манифесте, заключается в том, что я хочу, чтобы он всегда был в портретном режиме. Также, если я использую ViewSwitcher или ViewAnimator, как это решит проблему с загрузкой сети во время заставки (анимации)? Можно ли предоставить мне код, как это сделать? - person Johny; 04.04.2017
comment
Значит, мне нужно использовать один из двух кодов, которые вы предоставили? И как я могу использовать это в своем коде? - person Johny; 04.04.2017
comment
Да, это будет работать нормально. Макет действия будет иметь ViewSwitcher в качестве родителя: один из webView и один с видео. - person android developer; 04.04.2017
comment
Я обновил свой вопрос с двумя макетами, если возможно, не могли бы вы помочь мне, как объединить их в один, используя viewSwitcher? - person Johny; 04.04.2017
comment
Вам нужно только создать макет, в котором ViewSwitcher является родителем WebView и VideoView. Переключайтесь между ними в зависимости от того, что происходит. Если вы используете ViewAnimator, вы также можете добавить другое представление для состояния ошибки (поскольку в веб-представлении тоже могут быть ошибки). - person android developer; 04.04.2017
comment
Давайте продолжим обсуждение в чате. - person Johny; 04.04.2017
comment
Обновленный ответ еще раз, с полным макетом и объяснением того, что делать с кодом. - person android developer; 04.04.2017

После большой помощи от разработчика @android (большое спасибо!) и сообщений stackoverflow я объединил оба действия MainActivity, AnimationScreenActivity в одно действие (MainActivity).

Вот код:

    public class MainActivity extends AppCompatActivity {
        private String myURL = "https://www.testpage.com";
        VideoView videoView;
        ViewSwitcher viewSwitcher;
        private WebView webView;
        private boolean hasFinishedLoadingPage;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);

            try {
                viewSwitcher = (ViewSwitcher) findViewById(R.id.viewSwitcher);
                final VideoView videoView = (VideoView) findViewById(R.id.videoView1);
                Uri video = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.myvideo);
                videoView.setVideoURI(video);

                videoView.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
                    @Override
                    public void onCompletion(MediaPlayer mp) {
                        if (hasFinishedLoadingPage)
                            setViewToSwitchTo(viewSwitcher, webView);

                       // else webView.reload();

                    setViewToSwitchTo(viewSwitcher, webView);

                    }
                });

                videoView.start();
            } catch (Exception ex) {
            }

            webView = (WebView) findViewById(R.id.webView);
            webView.getSettings().setAllowContentAccess(true);
            WebSettings webSettings = webView.getSettings();
            webSettings.setJavaScriptEnabled(true);
            webView.getSettings().setDomStorageEnabled(true);
            webView.getSettings().setDatabaseEnabled(true);
            webSettings.getAllowFileAccessFromFileURLs();
            webSettings.getAllowUniversalAccessFromFileURLs();

            webView.setWebViewClient(new WebViewClient() {

                boolean isRedirected;

                @Override
                public boolean shouldOverrideUrlLoading(WebView view, String url) {
                    return false;
                }

                @Override
                public void onPageStarted(WebView view, String url, Bitmap favicon) {
                    super.onPageStarted(view, url, favicon);
                    if (!isRedirected) {
                        setViewToSwitchTo(viewSwitcher, videoView);
                    }
                    isRedirected = true;
                }

                @Override
                public void onPageFinished(WebView webView, String url) {
                    super.onPageFinished(webView, url);
                    hasFinishedLoadingPage = true;
                }
            });

            /** Callback for web events */
            webView.setWebChromeClient(new WebChromeClient() {
            });
            webView.loadUrl(myURL);
        }

        public static void setViewToSwitchTo(@NonNull final ViewAnimator viewAnimator, @NonNull final View viewToSwitchTo) {
            if (viewAnimator == null)
                return;
            if (viewAnimator.getCurrentView() == viewToSwitchTo)
                return;
            for (int i = 0; i < viewAnimator.getChildCount(); ++i)
                if (viewAnimator.getChildAt(i) == viewToSwitchTo) {
                    viewAnimator.setDisplayedChild(i);
                    break;
                }
        }
    }
person Johny    schedule 11.04.2017
comment
Работает как шарм! - person Steven; 08.11.2017
comment
Настоящая живая заставка! - person Steven; 08.11.2017
comment
Рад, что вам помогает :) - person Johny; 08.11.2017

Я бы посоветовал избегать двух видов деятельности, я подозреваю, что это одна из ваших проблем.

Имейте только одно действие с VideoView и WebView внутри RelativeLayout, чтобы VideoView был выше WebView.

Когда WebView будет готов, просто VideoView.setVisibity(View.GONE)

person neteinstein    schedule 19.03.2017
comment
Спасибо за ваш ответ, но если я сделаю VideoView.setVisibity(View.GONE), он остановит видео в середине, где я хочу, чтобы оно закончилось, несмотря ни на что, а затем загрузил веб-страницу. Также вы имеете в виду одно действие и один макет как для VideoView, так и для WebView? - person Johny; 20.03.2017
comment
@Johny Я имею в виду, что вы меняете видимость, когда видео заканчивается и загружается WebView. Точно так же, как ваш код, но в одном действии. - person neteinstein; 20.03.2017
comment
Итак, сначала мне нужно использовать только один макет, который будет иметь как VideoView, так и WebView (вместо двух макетов), а также одно действие, которое будет выполнять всю часть видео и WebView. Я попробую это, но можно ли написать код так, как он должен быть? - person Johny; 20.03.2017
comment
@netesinstein я узнаю, что когда я вхожу в систему onPageFinished, она вызывается три раза. У других людей была такая же проблема, они использовали onPageStarted и shouldOverrideUrlLoading, но я пробовал безрезультатно. - person Johny; 20.03.2017
comment
Это может случиться. Чтобы избежать этого, используйте это: stackoverflow.com/questions/3149216/ - person neteinstein; 21.03.2017
comment
@ neteinstein мне удалось решить проблему с несколькими вызовами onPageFinished, но я все еще не могу решить основную проблему (предварительная загрузка WebView во время заставки видео в Android). Можно ли писать код так, как он должен? - person Johny; 22.03.2017