webView not displaying website when offline

2019-04-07 22:16发布

I have an app that registers with GCM for push notifications. That code works fine and is not the source of my problem. Once registered, the app simply displays a website in a WebView. So far so good all this works if the device's network adapter is switched on.

If the network adapter is switched off then the webview should load from cache. This part is not working. I have followed the tutorial below and taken parts from it in a bit to save the website pages in a cache saved on the sdcard.

If i run the app the web site is displayed. If i then turn off the network adapter and visit the site, it will not display. I check the cache directory on the sdcard and parts of the site have been written to the cache.

Why doesn't the site load from cache when off-line?

Is it possible to keep the webpages it the cache until say the app is uninstalled or android decides otherwise?

tutorial

The tutorial shows you how to create a directory on the sdcard and write to it. The directories do exist but the webview is not restored from this cache in offline mode.

below is how i call the mainactivity that displays the webview.

Intent i = new Intent(getApplicationContext(), MainActivity.class);
                //i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                i.putExtra("name", "hardcoded client name");
                i.putExtra("email", "hardcoded email");
                startActivity(i);
                finish();

.

Here is the full MainActivity. You can ignore the first part as that's the code that handle the GCM push notification stuff, that all works. I need to know why the webview will not load from cache.

   import static com.bmi.bmitestapp.CommonUtilities.DISPLAY_MESSAGE_ACTION;
import static com.bmi.bmitestapp.CommonUtilities.EXTRA_MESSAGE;
import static com.bmi.bmitestapp.CommonUtilities.SENDER_ID;

import java.io.File;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.TextView;
import android.widget.Toast;
import android.webkit.*;


import com.google.android.gcm.GCMRegistrar;

public class MainActivity extends Activity {
    private static final String TAG = MainActivity.class.getSimpleName();
    // label to display gcm messages
    TextView lblMessage;
    WebView webView;
    // Asyntask
    AsyncTask<Void, Void, Void> mRegisterTask;

    // Alert dialog manager
    AlertDialogManager alert = new AlertDialogManager();

    // Connection detector
    ConnectionDetector cd;

    public static String name;
    public static String email;

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

        Log.e(TAG, "in onCreate in mainactivity");
        cd = new ConnectionDetector(getApplicationContext());

        // Check if Internet present
//        if (!cd.isConnectingToInternet()) {
//            // Internet Connection is not present
//            alert.showAlertDialog(MainActivity.this,
//                    "Internet Connection Error",
//                    "Please connect to working Internet connection", false);
//            // stop executing code by return
//            return;
//        }

        // Getting name, email from intent
        Intent i = getIntent();

        name = i.getStringExtra("name");
        email = i.getStringExtra("email");     

        // Make sure the device has the proper dependencies.
        GCMRegistrar.checkDevice(this);

        // Make sure the manifest was properly set - comment out this line
        // while developing the app, then uncomment it when it's ready.
        GCMRegistrar.checkManifest(this);

        lblMessage = (TextView) findViewById(R.id.lblMessage);

        registerReceiver(mHandleMessageReceiver, new IntentFilter(
                DISPLAY_MESSAGE_ACTION));

        // Get GCM registration id
        final String regId = GCMRegistrar.getRegistrationId(this);

        // Check if regid already presents
        if (regId.equals("")) {
            // Registration is not present, register now with GCM
            GCMRegistrar.register(this, SENDER_ID);
        } else {
            // Device is already registered on GCM
            if (GCMRegistrar.isRegisteredOnServer(this)) {
                // Skips registration.
                Toast.makeText(getApplicationContext(), "Already registered with GCM", Toast.LENGTH_LONG).show();
            } else {
                // Try to register again, but not in the UI thread.
                // It's also necessary to cancel the thread onDestroy(),
                // hence the use of AsyncTask instead of a raw thread.
                final Context context = this;
                mRegisterTask = new AsyncTask<Void, Void, Void>() {

                    @Override
                    protected Void doInBackground(Void... params) {
                        // Register on our server
                        // On server creates a new user
                        ServerUtilities.register(context, name, email, regId);
                        return null;
                    }

                    @Override
                    protected void onPostExecute(Void result) {
                        mRegisterTask = null;
                    }

                };
                mRegisterTask.execute(null, null, null);
            }
        }

            webView = (WebView)findViewById(R.id.webView1);
            // Initialize the WebView
            webView.getSettings().setSupportZoom(true);
            webView.getSettings().setBuiltInZoomControls(true);
            webView.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
            webView.setScrollbarFadingEnabled(true);
            webView.getSettings().setLoadsImagesAutomatically(true);





            webView.getSettings().setDomStorageEnabled(true);

            // Set cache size to 8 mb by default. should be more than enough
            webView.getSettings().setAppCacheMaxSize(1024*1024*8);

            // This next one is crazy. It's the DEFAULT location for your app's cache
            // But it didn't work for me without this line.
            // UPDATE: no hardcoded path. Thanks to Kevin Hawkins
            String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath();
            Log.e(TAG, "appCachePath = " + appCachePath);
            webView.getSettings().setAppCachePath(appCachePath);
            webView.getSettings().setAllowFileAccess(true);
            webView.getSettings().setAppCacheEnabled(true);




            // Load the URLs inside the WebView, not in the external web browser
            webView.setWebViewClient(new WebViewClient());   

            if (savedInstanceState == null)
                        {



        if(isNetworkAvailable() == true){
            Log.e(TAG, "we have a network connection");
            webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);

            webView.loadUrl("http://bmi.cubecore.co.uk");


        } else {
            Log.e(TAG, "we don't have a network connection");
            webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ONLY);

            webView.loadUrl("http://bmi.cubecore.co.uk");
        }


                        } 

    }      //end of oncreate


    private boolean isNetworkAvailable() {
        ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
        return activeNetworkInfo != null;
    }


    /**
     * Receiving push messages
     * */
    private final BroadcastReceiver mHandleMessageReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String newMessage = intent.getExtras().getString(EXTRA_MESSAGE);
            // Waking up mobile if it is sleeping
            WakeLocker.acquire(getApplicationContext());

            /**
             * Take appropriate action on this message
             * depending upon your app requirement
             * For now i am just displaying it on the screen
             * */

            // Showing received message
            lblMessage.append(newMessage + "\n");
            Toast.makeText(getApplicationContext(), "New Message: " + newMessage, Toast.LENGTH_LONG).show();

            // Releasing wake lock
            WakeLocker.release();
        }
    };

    @Override
    protected void onDestroy() {
        super.onDestroy();

        // Clear the cache (this clears the WebViews cache for the entire application)
        //webView.clearCache(false);

        if (mRegisterTask != null) {
            mRegisterTask.cancel(true);
        }
        try {
            unregisterReceiver(mHandleMessageReceiver);
            GCMRegistrar.onDestroy(this);
        } catch (Exception e) {
            Log.e("UnRegister Receiver Error", "> " + e.getMessage());
        }



    }



    @Override
    public void onBackPressed() {
        super.onBackPressed();


    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.e(TAG, "in onResume in mainactivity");

    }



    @Override
    public File getCacheDir()
    {
        // NOTE: this method is used in Android 2.1
Log.e(TAG, "getcachedir");
        return getApplicationContext().getCacheDir();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);

        // Save the state of the WebView
        webView.saveState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState)
    {
        super.onRestoreInstanceState(savedInstanceState);

        // Restore the state of the WebView
        webView.restoreState(savedInstanceState);
    }

}

.

Here's the code from the tutorial above that writes to the sdcard.

package com.bmi.bmitestapp;

import java.io.File;

import android.app.Application;
import android.os.Environment;
import android.util.Log;

public class ApplicationExt extends Application
{
    private static final String TAG = ApplicationExt.class.getSimpleName();
    // NOTE: the content of this path will be deleted
    //       when the application is uninstalled (Android 2.2 and higher)
    protected File extStorageAppBasePath;

    protected File extStorageAppCachePath;

    @Override
    public void onCreate()
    {
        super.onCreate();
         Log.e(TAG, "inside appext");
        // Check if the external storage is writeable
        if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
        {

            // Retrieve the base path for the application in the external storage
            File externalStorageDir = Environment.getExternalStorageDirectory();

            if (externalStorageDir != null)
            {
                // {SD_PATH}/Android/data/com.devahead.androidwebviewcacheonsd
                extStorageAppBasePath = new File(externalStorageDir.getAbsolutePath() +
                    File.separator + "Android" + File.separator + "data" +
                    File.separator + getPackageName());
            }

            if (extStorageAppBasePath != null)
            {
                // {SD_PATH}/Android/data/com.devahead.androidwebviewcacheonsd/cache
                extStorageAppCachePath = new File(extStorageAppBasePath.getAbsolutePath() +
                    File.separator + "cache");

                boolean isCachePathAvailable = true;

                if (!extStorageAppCachePath.exists())
                {
                    // Create the cache path on the external storage
                    isCachePathAvailable = extStorageAppCachePath.mkdirs();
                }

                if (!isCachePathAvailable)
                {
                    // Unable to create the cache path
                    extStorageAppCachePath = null;
                }
            }
        }
    }

    @Override
    public File getCacheDir()
    {
        // NOTE: this method is used in Android 2.2 and higher

        if (extStorageAppCachePath != null)
        {
            // Use the external storage for the cache
            Log.e(TAG, "extStorageAppCachePath = " + extStorageAppCachePath);
            return extStorageAppCachePath;
        }
        else
        {
            // /data/data/com.devahead.androidwebviewcacheonsd/cache
            return super.getCacheDir();
        }
    }
}

I thought i'd include a little logging. This is the logging from a fresh install with the network adapter ON.

01-29 14:13:10.220: D/dalvikvm(16904): Late-enabling CheckJNI
01-29 14:13:10.470: E/ApplicationExt(16904): inside appext
01-29 14:13:10.720: E/RegisterActivity(16904): in onresume in registeractivity
01-29 14:13:10.880: D/libEGL(16904): loaded /system/lib/egl/libEGL_tegra.so
01-29 14:13:11.000: D/libEGL(16904): loaded /system/lib/egl/libGLESv1_CM_tegra.so
01-29 14:13:11.030: D/libEGL(16904): loaded /system/lib/egl/libGLESv2_tegra.so
01-29 14:13:11.070: D/OpenGLRenderer(16904): Enabling debug mode 0
01-29 14:13:18.390: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:18.390: D/webview(16904): [InitTabEffectPivot] >> nScreenWidth = 720
01-29 14:13:18.390: D/webview(16904): [InitTabEffectPivot] >> nScreenHeight = 1280
01-29 14:13:18.390: D/SqliteDatabaseCpp(16904): Registering sqlite logging func: /data/data/com.bmi.bmitestapp/databases/webview.db
01-29 14:13:18.390: D/SqliteDatabaseCpp(16904): DB info: open db, path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, flag = 6, cannot stat file, errno = 2, message = No such file or directory
01-29 14:13:18.400: E/MainActivity(16904): in onCreate in mainactivity
01-29 14:13:18.400: D/SqliteDatabaseCpp(16904): DB info: path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, handle: 0x1f9a858, type: w, r/w: (0,1), mode: delete, disk free size: 1276 M
01-29 14:13:18.400: D/GCMRegistrar(16904): resetting backoff for com.bmi.bmitestapp
01-29 14:13:18.420: V/GCMRegistrar(16904): Registering app com.bmi.bmitestapp of senders 598080744593
01-29 14:13:18.430: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:18.430: E/MainActivity(16904): appCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:18.430: E/MainActivity(16904): we have a network connection
01-29 14:13:18.430: E/MainActivity(16904): in onResume in mainactivity
01-29 14:13:18.490: W/webcore(16904): java.lang.Throwable: EventHub.removeMessages(int what = 107) is not supported before the WebViewCore is set up.
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.WebViewCore$EventHub.removeMessages(WebViewCore.java:1974)
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.WebViewCore$EventHub.access$9100(WebViewCore.java:1008)
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.WebViewCore.removeMessages(WebViewCore.java:2215)
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.WebView.sendOurVisibleRect(WebView.java:3285)
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.ZoomManager.setZoomScale(ZoomManager.java:772)
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.ZoomManager.access$1900(ZoomManager.java:59)
01-29 14:13:18.490: W/webcore(16904):   at android.webkit.ZoomManager$PostScale.run(ZoomManager.java:1345)
01-29 14:13:18.490: W/webcore(16904):   at android.os.Handler.handleCallback(Handler.java:608)
01-29 14:13:18.490: W/webcore(16904):   at android.os.Handler.dispatchMessage(Handler.java:92)
01-29 14:13:18.490: W/webcore(16904):   at android.os.Looper.loop(Looper.java:156)
01-29 14:13:18.490: W/webcore(16904):   at android.app.ActivityThread.main(ActivityThread.java:5045)
01-29 14:13:18.490: W/webcore(16904):   at java.lang.reflect.Method.invokeNative(Native Method)
01-29 14:13:18.490: W/webcore(16904):   at java.lang.reflect.Method.invoke(Method.java:511)
01-29 14:13:18.490: W/webcore(16904):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-29 14:13:18.490: W/webcore(16904):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-29 14:13:18.490: W/webcore(16904):   at dalvik.system.NativeStart.main(Native Method)
01-29 14:13:18.500: W/webcore(16904): java.lang.Throwable: EventHub.removeMessages(int what = 105) is not supported before the WebViewCore is set up.
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.WebViewCore$EventHub.removeMessages(WebViewCore.java:1974)
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.WebViewCore$EventHub.access$9100(WebViewCore.java:1008)
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.WebViewCore.removeMessages(WebViewCore.java:2215)
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.WebView.sendViewSizeZoom(WebView.java:3520)
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.ZoomManager.setZoomScale(ZoomManager.java:778)
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.ZoomManager.access$1900(ZoomManager.java:59)
01-29 14:13:18.500: W/webcore(16904):   at android.webkit.ZoomManager$PostScale.run(ZoomManager.java:1345)
01-29 14:13:18.500: W/webcore(16904):   at android.os.Handler.handleCallback(Handler.java:608)
01-29 14:13:18.500: W/webcore(16904):   at android.os.Handler.dispatchMessage(Handler.java:92)
01-29 14:13:18.500: W/webcore(16904):   at android.os.Looper.loop(Looper.java:156)
01-29 14:13:18.500: W/webcore(16904):   at android.app.ActivityThread.main(ActivityThread.java:5045)
01-29 14:13:18.500: W/webcore(16904):   at java.lang.reflect.Method.invokeNative(Native Method)
01-29 14:13:18.500: W/webcore(16904):   at java.lang.reflect.Method.invoke(Method.java:511)
01-29 14:13:18.500: W/webcore(16904):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
01-29 14:13:18.500: W/webcore(16904):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
01-29 14:13:18.500: W/webcore(16904):   at dalvik.system.NativeStart.main(Native Method)
01-29 14:13:18.530: D/OpenGLRenderer(16904): Flushing caches (mode 0)
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: CacheGroups
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: Caches
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: Origins
01-29 14:13:18.570: I/SqliteDatabaseCpp(16904): sqlite returned: error code = 1, msg = no such table: DeletedCacheResources
01-29 14:13:18.850: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:13:19.330: I/PRIME(16904): <CallBackProxy> Send to WebViewClient.
01-29 14:13:19.370: V/GCMBroadcastReceiver(16904): onReceive: com.google.android.c2dm.intent.REGISTRATION
01-29 14:13:19.370: V/GCMBroadcastReceiver(16904): GCM IntentService class: com.bmi.bmitestapp.GCMIntentService
01-29 14:13:19.370: V/GCMBaseIntentService(16904): Acquiring wakelock
01-29 14:13:19.460: V/GCMBaseIntentService(16904): Intent service name: GCMIntentService-598080744593-1
01-29 14:13:19.470: E/GCMRegistrar(16904): internal error: retry receiver class not set yet
01-29 14:13:19.480: V/GCMRegistrar(16904): Registering receiver
01-29 14:13:19.480: D/GCMBaseIntentService(16904): handleRegistration: registrationId = APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w, error = null, unregistered = null
01-29 14:13:19.480: D/GCMRegistrar(16904): resetting backoff for com.bmi.bmitestapp
01-29 14:13:19.480: V/GCMRegistrar(16904): Saving regId on app version 1
01-29 14:13:19.490: I/GCMIntentService(16904): Device registered: regId = APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w
01-29 14:13:19.490: D/NAME(16904): hardcoded client name
01-29 14:13:19.490: I/bmi GCM(16904): registering device (regId = APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w)
01-29 14:13:19.490: D/bmi GCM(16904): Attempt #1 to register
01-29 14:13:19.500: V/bmi GCM(16904): Posting 'email=hardcoded email&regId=APA91bFytZvnkmsEVHSnw5VRxIwfPRmPsSRVrgRNRa5ww3oqCfnLEZMaBBNtQtlZoK4RD4VQXfAfKDsQUa53PwQBH_rwuI_gEEdHQhxadpBVmJ7L3Dxy90Bzryg_aCWx20-cdZ32cbiiaGR3zUMjpqZizYQbnARN4w&name=hardcoded client name' to http://mobilewebexpert.co.uk/pushtest/register.php
01-29 14:13:19.500: E/URL(16904): > http://mobilewebexpert.co.uk/pushtest/register.php
01-29 14:13:20.610: V/GCMRegistrar(16904): Setting registeredOnServer status as true until 2013-02-05 14:13:20.617
01-29 14:13:20.620: V/GCMBaseIntentService(16904): Releasing wakelock
01-29 14:13:21.470: D/skia(16904): notifyPluginsOnFrameLoad not postponed
01-29 14:13:21.570: D/SQLiteDatabase(16904): Create pool connection
01-29 14:13:21.570: D/SqliteDatabaseCpp(16904): DB info: open db, path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, flag = 1, file size = 12288
01-29 14:13:21.570: D/SqliteDatabaseCpp(16904): DB info: path = /data/data/com.bmi.bmitestapp/databases , key = sefraes, handle: 0x2797350, type: r, r/w: (1,1), mode: wal, disk free size: 1276 M

.

This is the logging after i have turned off the network adapter.

01-29 14:16:57.080: E/RegisterActivity(16904): in onresume in registeractivity
01-29 14:17:03.490: D/webview(16904): [InitTabEffectPivot] >> nScreenWidth = 720
01-29 14:17:03.490: D/webview(16904): [InitTabEffectPivot] >> nScreenHeight = 1280
01-29 14:17:03.490: E/MainActivity(16904): in onCreate in mainactivity
01-29 14:17:03.490: V/GCMRegistrar(16904): Is registered on server: true
01-29 14:17:03.500: E/ApplicationExt(16904): extStorageAppCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:17:03.500: E/MainActivity(16904): appCachePath = /mnt/sdcard/Android/data/com.bmi.bmitestapp/cache
01-29 14:17:03.500: E/MainActivity(16904): we don't have a network connection
01-29 14:17:03.500: E/MainActivity(16904): in onResume in mainactivity
01-29 14:17:03.500: D/chromium(16904): Unknown chromium error: -400
01-29 14:17:03.540: D/skia(16904): notifyPluginsOnFrameLoad not postponed
01-29 14:17:03.580: D/OpenGLRenderer(16904): Flushing caches (mode 0)

One thing i've noticed, it might be nothing, but registeractivity is the activity that calls MainActivity. RegisterActivity just has a button that fires an Intent for MainActivity. After the network adapter is off i have to press the button on registerAcivity, which calls onCreate in MainActivity. It is like it's a new instance of MainActivity?? Could this be effecting the caching of the webview. Effectively the onDestroy of the main activity must have been called along the way.

Also another thing has caught my attention.

01-29 14:17:03.580: D/OpenGLRenderer(16904): Flushing caches (mode 0) 

2条回答
啃猪蹄的小仙女
2楼-- · 2019-04-07 22:58

This is not what http cache is intended for. If you want to enable offline access for html pages you should use AppCache. Try these two tutorials:

I would not use AppCache if you are writing a native Android app. Load the documents you want to serve yourself, and load them into the webview with either WebView.loadData(...) or create a ContentProvider and use WebView.loadUrl with a content:// prefix. Using ContentProvider is the best way, but loading a data url should be quick to test.

I hope this will get you started, reply if you need help loading the data from a URL in your app.

查看更多
走好不送
3楼-- · 2019-04-07 22:59

For that particular URL http://bmi.cubecore.co.uk, your WebView's caching is prohibited by that http server, see the response header Cache-Control:

200 OK
... ...
Pragma: no-cache
Server: Apache/2.2.3 (CentOS)
Content-Type: text/html; charset=utf-8
Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Expires: Thu, 19 Nov 1981 08:52:00 GMT

This means the client must always connect and load the URL from http server, never from its local cache. That also explained why Unknown chromium error: -400 occurred when you try to load the page after network adapter is switched off. Unknown chromium error: -400 generally means failed to connect internet for some reason.

There is nothing you can do without login and adjust the http server settings. You can use the following URL exam your cache implementation:

http://stackoverflow.com/questions/14549638/webview-not-displaying-website-when-offline

The response header is:

200 OK
... ...
Last-Modified: Wed, 30 Jan 2013 00:28:59 GMT
Vary: *
Content-Type: text/html; charset=utf-8
Cache-Control: public, max-age=60
Expires: Wed, 30 Jan 2013 00:29:59 GMT

If there is no other issue in your code, your cache implementation should work.

查看更多
登录 后发表回答