cordova javascript - Android WebView отображает пустой / белый, просмотр не обновляется при изменениях css или изменениях в HTML, анимация изменчивая





documentation setwebviewclient (8)


Для меня эта проблема произошла только на устройствах Samsung. Я смог исправить это, отключив аппаратное ускорение для WebViews:

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Надеюсь, поможет.

Когда я делаю изменение класса css, изменения не всегда появляются. Это происходит, когда у меня есть событие касания, которое добавляет что-то вроде имени вниз для кнопки к кнопке. Кнопка не обновляется, и на странице ничего не происходит. Это очень непостоянно, когда оно работает. Я также заметил, что иногда мои элементы кажутся белыми без содержания или чего-то еще. Это очень неприятно!




У меня была эта проблема, потому что onPageStared и onPageFinished я показываю и скрываю анимацию загрузки.

Так как я вводил JS, делаю свои меню и прочее с исходного сайта, и заметил, что инъекция JS on onPageFinished заставит веб-просмотр рисовать содержимое. Вот пример того, что вы можете добавить в конце onPageFinished

view.loadUrl("javascript:(function() { var select = document.getElementsByClassName('something')[0]\r\n" + 
                            "                     if(select)" +
                            "                       select.style.display = 'none';})()");






Как указано выше и в другом месте - переопределение View.onDraw() и вызов View.invalidate приведет к View.invalidate производительности батареи / приложения. Вы также можете сделать ручную invalidate вызова, когда-либо x ms, как это сделать

/**
 * Due to bug in 4.2.2 sometimes the webView will not draw its contents after the data has loaded. 
 * Triggers redraw. Does not work in webView's onPageFinished callback for some reason
 */
private void forceWebViewRedraw()
{
    mWebView.post(new Runnable() {
        @Override
        public void run()
        {
            mWebView.invalidate();
            if(!isFinishing())
                mWebView.postDelayed(this, 1000);
        }
    });
}

Я попытался поставить вызов invalidate в WebViewClient.onPageLoaded() но это, похоже, не работает. Хотя мое решение может быть лучше его простым, и оно работает для меня (im, просто показывающий вход в twitter)




Заметка:
Есть лучшее решение для Android 4.4+. Это замена WebView под названием CrossWalk . Он использует новейший набор Chromium, и это фантастика. Вы можете прочитать об этом здесь: crosswalk-project.org

Кроме того, похоже, что с Android 4.4 решение invalidate() больше не требуется, и вы можете избавиться от использования другого безопасного ответа. Я бы использовал этот метод invalidate() как последнее усилие.

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

Я пробовал несколько способов сделать вещи лучше, даже все пресловутые - webkit-transform: translate3d(0,0,0); Даже это не слишком хорошо работает.

Позвольте мне поделиться с вами тем, что сработало.

Сначала используйте новейший API. Я использую API 15. В вашем AndroidManifest.xml обязательно включите аппаратное ускорение . Если ваша версия API не поддерживает это, переходите к следующему биту.

Если ваша версия поддерживает его, вы можете включить его, изменив свой манифест:

<application
   ...
   android:hardwareAccelerated="true">

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

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

( Обновление : теперь вы должны изменить эти значения в build.gradle )

Теперь, в вашем основном файле CSS для того, что будет представлено в WebView, добавьте что-то вроде этого:

body div {
    -webkit-transform: translate3d(0,0,0);
}

Добавьте бит body div с любыми другими типами элементов, которые у вас есть; вы, вероятно, можете исключить изображения, ul , li и т. д. Причина применения этого стиля CSS ко всему - это просто пробная версия и ошибка, и я обнаружил, что грубое применение этого ко всему кажется лучшим для работы. С большим деревом DOM вам может понадобиться быть более конкретным. Однако я не уверен, что спецификация будет.

Когда вы создаете экземпляр своего WebView , есть некоторые настройки, которые вы хотите установить:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    super.loadUrl("file:///android_asset/www/index.html");
    appView.getSettings().setRenderPriority(RenderPriority.HIGH);
    appView.getSettings()
            .setPluginState(WebSettings.PluginState.ON_DEMAND);
}

Второй и последний, но решающий бит: я читал исходный код для класса WebView и нашел этот маленький крошечный комментарий о переделке силы. Существует static final boolean , которое при установке в true заставит просмотр всегда перерисовывать. Я не большой синтаксис Java, но я не думаю, что вы можете напрямую изменить статический конечный атрибут класса. Итак, что я в итоге сделал, я расширил класс следующим образом:

import org.apache.cordova.CordovaWebView;

import android.content.Context;
import android.graphics.Canvas;

public class MyWebView extends CordovaWebView {
    public static final String TAG = "MyWebView";

    public MyWebView(Context context) {
        super(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        // Warning! This will cause the WebView to continuously be redrawn
        // and will drain the devices battery while the view is displayed!
        invalidate();
    }

}

Имейте в виду, я использую Cordova / PhoneGap, поэтому мне пришлось перейти от CordovaWebView . Если вы видите в методе onDraw, есть вызов invalidate . Это заставит просмотр постоянно перерисовываться. Однако я настоятельно рекомендую добавить в логику только перерисовку, когда вам это нужно.

Есть один последний шаг, если вы используете Кордову. Вы должны сказать PhoneGap, чтобы использовать ваш новый класс WebView вместо своего собственного класса WebView . В своем классе MainActivity добавьте следующее:

public void init(){
    CordovaWebView webView = new MyWebView(MainActivity.this);
    super.init(webView, new CordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}

Это оно! Попробуйте запустить приложение и посмотрите, все ли намного более гладко. Прежде чем делать все эти изменения, страницы выглядели бы белыми, никаких изменений CSS не было бы применено до тех пор, пока после повторного нажатия на экран анимации не были бы чересчурными или даже не заметными. Я должен упомянуть, что анимация по-прежнему изменчивая, но гораздо менее прерывистая, чем раньше.

Если у кого-то есть что добавить, просто прокомментируйте это. Я всегда открыт для оптимизации; и я полностью понимаю, что могут быть лучшие способы сделать то, что я только что рекомендовал.

Если мое выше решение не сработало для вас, не могли бы вы описать свою конкретную ситуацию и какие результаты вы видите с помощью Androids WebView ?

Наконец, я включил этот ответ в качестве «вики сообщества» , поэтому любой и каждый, не стесняйтесь вносить коррективы.

Благодаря!

Редактировать:

С помощью самой последней версии PhoneGap вам нужно, чтобы ваш метод init () выглядел следующим образом:

public void init(){
    CordovaWebView webView = new MyWebView(MainActivity.this);
    super.init(webView, new IceCreamCordovaWebViewClient(this, webView), new CordovaChromeClient(this, webView));
}



Я реализовал решение kyle и решил проблему. Howwer я заметил огромный утечка батареи на android 4.0.4, когда приложение было открыто. Также после изменения у меня были пользователи, жалующиеся на то, что клавиатура swiftKey больше не работает с моим приложением.

Каждое изменение в моем приложении инициируется действием пользователя, поэтому я придумал модифицированную версию, которая вызывает только invalidate () после touchEvent:

    Handler handler = new Handler();
    public boolean onTouchEvent (MotionEvent event){
        super.onTouchEvent(event);
        handler.postDelayed(triggerInvalidate, 60);
            handler.postDelayed(triggerInvalidate, 300);
        return true;
    }

    private Runnable triggerInvalidate=new Runnable(){
        public void run(){
            invalidate();
        }
    };

Никогда не программировалось с Java, поэтому могло бы быть лучшее решение для этого.




re: проблема с перерисованием, вы можете принудительно выполнить перерисовку, прочитав свойство из элемента

так скажите, что вы это делаете:

$('#myElement').addClass('foo'); // youre not seeing this take effect

если вы сделаете это позже:

$('#myElement').width();

это заставит перерисовать.

Таким образом, вы можете быть избирательным, а не перерисовывать всю страницу все время, что дорого




buttonLayoutParams.bottomMargin
buttonLayoutParams.topMargin
buttonLayoutParams.leftMargin
buttonLayoutParams.rightMargin

может использоваться для установки полей





android html css cordova