The Android WebView display is consistently showing a blank white screen, failing to reflect CSS or HTML modifications, and exhibiting choppy animations

There seems to be a strange inconsistency when I make changes to CSS classes. Sometimes, after adding a down class name to a button using a touch event, the changes do not appear on the button or anywhere else on the page. It's frustrating how unpredictable this behavior can be. Additionally, there are instances where elements on the page show up white with no content at all. This issue is extremely bothersome!

Answer №1

Important Note:
A more effective solution is now available for Android 4.4+. It involves using a replacement for WebView called CrossWalk. This new tool utilizes the latest Chromium-kit and has shown great results. For further details, visit: crosswalk-project.org

In addition, it seems that starting from Android 4.4, the workaround involving invalidate() may no longer be necessary. Alternative solutions are recommended instead. Consider using invalidate() only as a last resort.


I am sharing my own findings to assist others facing similar challenges.

I experimented with various methods to improve performance, including the commonly suggested -

webkit-transform: translate3d(0,0,0);
However, even this did not yield satisfactory results.

Allow me to share what did prove to be successful.

Firstly, ensure you are using the most recent API version. I am utilizing API 15. In your AndroidManifest.xml, make sure to enable hardware acceleration. If your API version does not support this feature, proceed to the next step.

If hardware acceleration is supported in your API version, activate it by adjusting your manifest file accordingly:

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

Additionally, confirm that your manifest specifies the minimum supported API level matching the one you are using. Since I am on API 15, here is how my manifest is configured:

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

(Update: Modify these values in your build.gradle)

Within your primary CSS file for content displayed in a WebView, incorporate the following style:

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

You can extend this styling to other element types present in your page, excluding images, ul, li, etc. Applying this style universally proved to be the most effective approach through trial and error. For larger DOM trees, you might need to be more specific. The exact specifications are still unclear.

Upon initializing your WebView, configure certain settings:

@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);
}

Prior to concluding, an important discovery while examining the source code for the WebView class revealed a comment regarding forceful redrawing. Within the class, there exists a static final boolean attribute that, when set to true, triggers constant redrawing of the view. As Java does not permit direct alteration of static final attributes, I resorted to extending the class as follows:

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);
        // Caution! This will lead to continuous redraws of the WebView, potentially draining the device's battery during view display!
        invalidate();
    }

}

Please note that being a Cordova/PhoneGap user, I had to extend from CordovaWebView. Notably, the onDraw method calls invalidate, prompting constant redrawing of the view. It is advisable to implement logic ensuring redraws occur only when necessary.

A final requirement, if employing Cordova, involves instructing PhoneGap to utilize your custom WebView class instead of its default counterpart. In your MainActivity class, include the following:

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

That concludes the process! Test your application to observe enhanced performance. Prior to implementing these changes, pages may have appeared white initially, CSS alterations delayed until screen interaction, and animations exhibiting choppy behavior or inconsistency. While animation smoothness remains somewhat compromised, the improvement is significant compared to before.

If there are additional insights to contribute or better alternatives to suggest, feel free to leave a comment. Optimization suggestions are welcomed, acknowledging potential room for enhancement in the proposed approach.

If the aforementioned solution does not address your situation, kindly describe your specific scenario and any issues encountered with Android's WebView.

Finally, this answer has been designated as a "community wiki", permitting adjustments from all users. Contributions are encouraged!

Thank you!


Update:

With the most recent version of PhoneGap, your init() method should resemble this structure:

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

Answer №2

After implementing Kyle's solution, I was able to successfully resolve the issue at hand. However, I soon noticed a significant drain on the battery of Android 4.0.4 when my app was in use. Additionally, following the update, users began reporting issues with the SwiftKey keyboard not functioning properly with my application.

Since all changes in my app are initiated by user actions, I decided to create a modified version that only triggers invalidate() after a touch event:

    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();
        }
    };

As someone who has not had much experience with Java programming, I acknowledge that there may be more optimal solutions available for this task.

Answer №3

Regarding the issue with redrawing, one way to trigger a redraw is by accessing a property of the element

For example, after adding a class to an element like this:

$('#myElement').addClass('foo'); // changes not visible immediately

If you follow it up with:

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

it will prompt a refresh.

This method allows for targeted redrawing instead of refreshing the entire page constantly, which can be resource-intensive

Answer №4

This problem was specific to Samsung devices in my case. I managed to resolve it by turning off Hardware Acceleration for WebViews:

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Hopefully this solution works for you too.

Answer №5

It has been noted in various sources that overriding View.onDraw() and invoking View.invalidate can negatively impact battery life and decrease app performance. Another approach is to manually trigger an invalidate call every x milliseconds, like this:

/**
 * Due to a bug in 4.2.2, there are cases where the webView fails to draw its contents after data loading.
 * This method forces a redraw. It doesn't work in the webView's onPageFinished callback for unknown reasons
 */
private void forceWebViewRedraw()
{
    mWebView.post(new Runnable() {
        @Override
        public void run()
        {
            mWebView.invalidate();
            if(!isFinishing())
                mWebView.postDelayed(this, 1000);
        }
    });
}

I attempted placing an invalidate call in WebViewClient.onPageLoaded(), but it did not seem to resolve the issue. While there may be better solutions available, this simple approach works for my use case (demonstrating a Twitter login).

Answer №6

Take a look at my response on Dealing with WebView rendering issues on Android 4.2.2. The method involves exporting @Olivier's function to JavaScript to facilitate triggering invalidates from JS in specific areas... Unfortunately, it feels like yet another hack!

Answer №7

The issue arose for me due to displaying and hiding a loading animation on onPageStarted and onPageFinished events.

While injecting JS for menus and other elements from the original website, I noticed that using JS injection on onPageFinished triggered the webview to render content. Below is an example of code you can include at the end of onPageFinished to address this:

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

Answer №8

Simply refreshing the webView's cache in the oncreate() method did the trick for me.

webView.clearCache(true);

Answer №9

To optimize hardware performance, make sure to update your manifest file:

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

Additionally, in the onResume() method of your activity, add the following code snippet:

webView.postDelayed(() -> {
    if (!isFinishing() && webView != null) {
        webView.setLayerType(View.LAYER_TYPE_NONE, null);
    }
}, 1000);

Finally, don't forget to include the following line of code in your onPause() method:

webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Avoid refreshing the page and maintaining the most recent data inputted

On my HTML page, I am trying to implement a button that submits a form using a function. I have set up field validations, and when I click the submit button, it shows an error message but clears out the values I entered and refreshes the form. What I want ...

To close the menu, simply tap on anywhere on the screen

Is there a way to modify a script so that it closes the menu when clicking on any part of the screen, not just on an 'li' element? $(function() { $('.drop-down-input').click(function() { $('.drop-down-input.selected').rem ...

The width of the Bootstrap shadow container is not optimized for large viewports

Having recently started using bootstrap (less than six hours of documentation/development time), I encountered an issue where the width of my shadow container extends too far on smaller screen sizes. Any screen size above 991px leaves unwanted white space ...

Is there a way to asynchronously load image src URLs in Vue.js?

Why is the image URL printing in console but not rendering to src attribute? Is there a way to achieve this using async and await in Vue.js? <div v-for="(data, key) in imgURL" :key="key"> <img :src= "fetchImage(data)" /> </div> The i ...

Aligning images of varying sizes

I have implemented a PHP script that automatically resizes images proportionally to fit within a given height and width. For example, if the original picture is 200x100px and the target box is 180x180px, the resized image will be 180x90px. Although this s ...

What could be causing my iframe to not adjust its size according to its content?

My attempt at resizing a cross-site iframe is not working as expected, despite following the guidance provided here. The iframe on my page seems to remain unaltered in size, and I can't figure out what mistake I might be making. The current location ...

Transfer the data from a post request through routes following the MVC pattern

Encountering an issue when attempting to submit a post form with username and password, as an error stating Cannot POST /validateUser is displayed. The structure of my form is as follows: <!DOCTYPE html> <html> <head> <title> ...

Customize default zoom settings with Cascading Style Sheets (CSS)

body{ margin-bottom: 10%; margin-left: 10%; width:80%; color: #264653; position: relative; } #photo{ border-radius: 70%; position: absolute; left: 25%; top: 50px; } .left1{ margin-top: 10%; background-color: #264653; width : 30%; ...

How can I ensure that my style.scss file effectively interacts with my stylesheet by including imports for "variables", "globals", and "header"?

Currently, I am in the process of learning how to utilize Sass and JavaScript through VS Code. Within my project structure, I have an "app" folder where my js folder resides containing script.js, as well as a scss folder holding _globals.scss, _header.scss ...

Is there a way to deactivate other dropdown options?

To simplify the selection process, I would like to disable the options for "Province", "City", and "Barangay". When the user clicks on the "Region" field, the corresponding "Province" options should be enabled. Then, when a specific province is selected, t ...

Rails and Materialize CSS icons encountering unexpected alignment issues

There's an unusual problem I'm facing with Materialize CSS's icons in a table. They don't align properly. I've attached a screenshot for reference (personal details blurred out). Screenshot Link Below is my Slim template code: ...

Achieving Dynamic Center Alignment for One or Two DIVs

My goal is to create a page layout with three DIVS arranged as Left|Center|Right, while still being able to display different combinations such as Center, Left|Center, or Center|Right in the center of a wrapper div. I have been using jQuery toggle to swit ...

The integration of Vue JS is not displaying properly in an Electron application

My electron app is loading Vue JS 2 from my local machine, but when I attach my el to an element, it completely empties the element and replaces its contents with a Vue JS comment. What could be causing this issue? index.html <!DOCTYPE html> <htm ...

TextView - Shift the view to the bottom

A scenario I am currently facing involves a TextView with multiple lines. I am trying to figure out a way to determine the available space at the end of the text in order to ensure that a view fits into that space. For instance: -------------------- | I ...

Tips for accurately relocating elements within a tooltip

Currently, I am working on implementing a like model within a Rails application. In order to display which user liked the bonus, I have incorporated foundation tooltip. Below is the code snippet: - avatars = bonus.like_user_avatars.map { |avatar| image_t ...

Tips for keeping a link in place on an image

Trying to place a link on a 1920x1080 picture and keep it fixed in one spot, regardless of browser size. Any suggestions? <!DOCTYPE html> <link rel="stylesheet" href="../style.css" /> <html> <head> ...

Tips on adjusting section height as window size changes?

Working on a website that is structured into sections. Initially, all links are aligned perfectly upon load. However, resizing the window causes misalignment issues. Check out my progress at: karenrubkiewicz.com/karenportfolio1 Appreciate any help! CSS: ...

After a single click, the functionality of jquery.nav.js seems to be malfunctioning

Encountering an error message: Uncaught TypeError: Cannot read property 'top' of undefined(…) jquery.nav.js:183 In an effort to convert my web app into a Single Page Application (SPA) using the jquery.nav.js library (available at https://githu ...

How to Implement Loading Image with CSS

I have customized the CSS code below to style a div element that showcases a responsive image. .my-img-container { position: relative; &:before { display: block; content: " "; background: url("https://lorempixel.com/300/160/") ...

Ensure that the floated element stretches to 100% height in order to completely fill the page

I'm working on achieving a height of 100% for the left sidebar so that it fills the page regardless of the size of the "main" div. Currently, it stops at the normal page height and doesn't expand further. Is there any way to make this work as i ...