Android WebView not loading second page from cache

15,204

Solution 1

This is not the exact answer to your question, as you are asking about webview cache. But, it can achieve the same result.

// saving page from web to file 
File file = new File(this.getExternalFilesDir(null), "fileName.html");
FileUtils.copyURLToFile(new URL("http://www.bmimobile.co.uk/why-bmi.php"), file);


// loading saved file in webview
webview.loadUrl("file://" + file.getPath());

This is a more flexible approach, as you have control over loading, saving, and much more.

Solution 2

Its little Silly that this works. There is a redirect in URL from

http://www.bmimobile.co.uk/ to http://www.bmimobile.co.uk/index.php

You Should try

webView.loadUrl("http://www.bmimobile.co.uk/why-bmi.php", getHeaders()); webView.loadUrl("http://www.bmimobile.co.uk/index.php", getHeaders());

Solution 3

Perhaps a solution to your problem would be to make an HTTP get request alongside your webview loading.

The result of the get request could be stored in a string persistenly in sharedpreferences, and it will be the HTML that your php renders.

in your android lifecycle, you can determine if the app is offline, and if it is offline you can load the last saved version of the site from string

webview.loadData(yourSavedString, "text/html", "UTF-8");

although if there are images you will have to make extra considerations, but if the images are not dynamic you can store them in your app's asset folder and replace the URL in the saved string with the asset locations.

although it does not solve why your webview is not caching, it will accomplish the same end goal or viewing the page offline

Solution 4

Another very flexible and powerful option can be using HTML5 to manage the caching in your app..

Have a look at http://diveintohtml5.info/offline.html

You can simply enable caching in your app and manage the caching from the web end itself.

Best Regards

Aman Gautam

Share:
15,204
turtleboy
Author by

turtleboy

linkedin

Updated on June 05, 2022

Comments

  • turtleboy
    turtleboy about 2 years

    I have an Android app that simply houses a website. I would like the app to cache the pages of the website for offline use.

    I'm doing a simple test to see if the cache is working but unfortunately it is failing to load a page i have previously loaded in online mode, when offline. To make things clearer i load the following 2 pages when in online mode.

    webView.loadUrl("http://www.bmimobile.co.uk/why-bmi.php", getHeaders());
    webView.loadUrl("http://www.bmimobile.co.uk/", getHeaders());
    

    .

    I am hoping that the "why-bmi.php" page is loaded into the cache as well as the subsequent page http://www.bmimobile.co.uk/. The latter page has a link on it which refers to the first page. If i then come out of the app and turn the network adapter off then go back into the app the "http://www.bmimobile.co.uk/" page DOES display but when i click the "why-bmi" link that page DOES NOT display. I short toast message displays saying "error loading page".

    Can anyone tell me why the webview is not caching loaded page for later offline use?

    Here's the main activity and i've extended the Application object defining the appcachepath.

    Thanks in advance

    Matt

    package uk.bmi.mobile;
    
    import java.io.File;
    import java.util.HashMap;
    import java.util.Map;
    import android.app.Activity;
    import android.content.Context;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    import android.os.Bundle;
    import android.util.Log;
    import android.webkit.WebSettings;
    import android.webkit.WebView;
    import android.webkit.WebViewClient;
    
    
    
    public class MainActivity extends Activity {
    
    
        private WebView webView;
        private static final String TAG = MainActivity.class.getSimpleName();
        ApplicationExt bmiAppObj;
    
    
        //instruct server to set it's headers to make resources cachable
        private Map<String, String> getHeaders() {
            Map<String, String> headers = new HashMap<String, String>();
            headers.put("IS_ALEX_APP", "1");
            return headers;
        }
    
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            Log.e(TAG, "in onCreate in mainactivity");
    
    
    
        }      //end of oncreate
    
    
        private boolean isNetworkAvailable() {
            ConnectivityManager connectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
            return activeNetworkInfo != null;
        }
    
    
    
        @Override
        protected void onResume() {
            super.onResume();
    
            Log.e(TAG, "in onResume in mainactivity");
            webView = (WebView)findViewById(R.id.webView1);
            bmiAppObj = (ApplicationExt)getApplication();
    
    
            if(isNetworkAvailable() == true){
    
                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);
                webView.getSettings().setAppCacheEnabled(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().setJavaScriptEnabled(true);
    
                // Load the URLs inside the WebView, not in the external web browser
                webView.setWebViewClient(new WebViewClient());  
                webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
    
    
                webView.loadUrl("http://www.bmimobile.co.uk/why-bmi.php", getHeaders());
                webView.loadUrl("http://www.bmimobile.co.uk/", getHeaders());
    
    
                }else{
    
                    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);
                    webView.getSettings().setAppCacheEnabled(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().setJavaScriptEnabled(true);
    
    
    
                    // Load the URLs inside the WebView, not in the external web browser
                    webView.setWebViewClient(new WebViewClient());  
    
    
    
                    webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ONLY);
    
                    webView.loadUrl("http://www.bmimobile.co.uk/", getHeaders());
    
    
                }
    
    
        }
    
    
    
    
    
    
        @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);
        }
    
    
    
    }//end of mainActivity
    

    .

    package uk.bmi.mobile;
    
    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;
    
        Webservice webservice;
        BmiDB bmiDb;
    
        @Override
        public void onCreate()
        {
            super.onCreate();
             Log.e(TAG, "inside appext");
    
             webservice = new Webservice(this);
             bmiDb = new BmiDB(this);
            // 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;
                    }
                }
            }
        }//end of onCreate
    
        @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();
            }
        }
    }
    

    .This is the logging when the app is first loaded in online mode

    02-16 08:38:52.744: I/NONPRIME(8871): <CallBackProxy> Send to WebViewClient.
    02-16 08:38:56.314: D/skia(8871): ----- started: [1 325] http://www.bmimobile.co.uk/images/mobile/bg-index.png
    02-16 08:38:56.499: D/skia(8871): ----- started: [1 64] http://www.bmimobile.co.uk/CubeCore/modules/cubeMobile/images/bg-black-bar.png
    02-16 08:38:56.509: D/skia(8871): ----- started: [26 20] http://www.bmimobile.co.uk/images/mobile/home-icon.png
    02-16 08:38:56.529: D/skia(8871): ----- started: [275 189] http://www.bmimobile.co.uk/images/mobile/home-img.png
    02-16 08:38:56.549: D/skia(8871): ----- started: [320 450] http://www.bmimobile.co.uk/images/mobile/welcome/bg-welcome.jpg
    02-16 08:38:56.554: D/skia(8871): ----- started: [270 38] http://www.bmimobile.co.uk/images/mobile/welcome/next.png
    02-16 08:38:56.584: D/skia(8871): ----- started: [16 17] http://www.bmimobile.co.uk/images/mobile/why.png
    02-16 08:38:56.584: D/skia(8871): ----- started: [18 17] http://www.bmimobile.co.uk/images/mobile/services.png
    02-16 08:38:56.584: D/skia(8871): ----- started: [20 15] http://www.bmimobile.co.uk/images/mobile/visit.png
    02-16 08:38:56.589: D/skia(8871): ----- started: [20 15] http://www.bmimobile.co.uk/images/mobile/consultants.png
    02-16 08:38:56.589: D/skia(8871): ----- started: [13 19] http://www.bmimobile.co.uk/images/mobile/contact.png
    

    .

    This is the logging when i've come out of the app turned off the network adapter then gone back into app in offline mode.

    02-16 08:41:37.799: E/MainActivity(8871): in onResume in mainactivity
    02-16 08:41:37.804: E/ApplicationExt(8871): extStorageAppCachePath = /storage/sdcard0/Android/data/uk.bmi.mobile/cache
    02-16 08:41:37.804: E/MainActivity(8871): appCachePath = /storage/sdcard0/Android/data/uk.bmi.mobile/cache
    02-16 08:41:37.834: W/dalvikvm(8871): disableGcForExternalAlloc: false
    

    [edit1] Actually on closer inspection of the logging, it seems to have changed when loaded in online mode. below is the logcat in omline mode. There seems to be a problem with the cache storage.

    02-19 15:16:10.497: E/ApplicationExt(5467): inside appext
    02-19 15:16:10.687: E/ApplicationExt(5467): extStorageAppCachePath = /storage/sdcard0/Android/data/uk.bmi.mobile/cache
    02-19 15:16:10.722: E/MainActivity(5467): in onCreate in mainactivity
    02-19 15:16:10.727: E/MainActivity(5467): in onResume in mainactivity
    02-19 15:16:10.737: E/ApplicationExt(5467): extStorageAppCachePath = /storage/sdcard0/Android/data/uk.bmi.mobile/cache
    02-19 15:16:10.737: E/MainActivity(5467): appCachePath = /storage/sdcard0/Android/data/uk.bmi.mobile/cache
    02-19 15:16:10.792: E/(5467): file /data/data/com.nvidia.NvCPLSvc/files/driverlist.txt: not found!
    02-19 15:16:10.792: I/(5467): Attempting to load EGL implementation /system/lib//egl/libEGL_tegra_impl
    02-19 15:16:10.807: I/(5467): Loaded EGL implementation /system/lib//egl/libEGL_tegra_impl
    02-19 15:16:10.842: I/(5467): Loading GLESv2 implementation /system/lib//egl/libGLESv2_tegra_impl
    02-19 15:16:10.882: E/SQLiteLog(5467): (1) no such table: CacheGroups
    02-19 15:16:10.882: D/WebKit(5467): ERROR: 
    02-19 15:16:10.882: D/WebKit(5467): Application Cache Storage: failed to execute statement "DELETE FROM CacheGroups" error "no such table: CacheGroups"
    02-19 15:16:10.882: D/WebKit(5467): external/webkit/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp(558) : bool WebCore::ApplicationCacheStorage::executeSQLCommand(const WTF::String&)
    02-19 15:16:10.882: E/SQLiteLog(5467): (1) no such table: Caches
    02-19 15:16:10.882: D/WebKit(5467): ERROR: 
    02-19 15:16:10.882: D/WebKit(5467): Application Cache Storage: failed to execute statement "DELETE FROM Caches" error "no such table: Caches"
    02-19 15:16:10.882: D/WebKit(5467): external/webkit/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp(558) : bool WebCore::ApplicationCacheStorage::executeSQLCommand(const WTF::String&)
    02-19 15:16:10.882: E/SQLiteLog(5467): (1) no such table: Origins
    02-19 15:16:10.882: D/WebKit(5467): ERROR: 
    02-19 15:16:10.882: D/WebKit(5467): Application Cache Storage: failed to execute statement "DELETE FROM Origins" error "no such table: Origins"
    02-19 15:16:10.882: D/WebKit(5467): external/webkit/Source/WebCore/loader/appcache/ApplicationCacheStorage.cpp(558) : bool WebCore::ApplicationCacheStorage::executeSQLCommand(const WTF::String&)
    02-19 15:16:10.882: E/SQLiteLog(5467): (1) no such table: DeletedCacheResources
    02-19 15:16:10.992: E/ApplicationExt(5467): extStorageAppCachePath = /storage/sdcard0/Android/data/uk.bmi.mobile/cache
    02-19 15:16:11.022: W/dalvikvm(5467): disableGcForExternalAlloc: false
    02-19 15:16:13.787: I/NONPRIME(5467): <CallBackProxy> Send to WebViewClient.
    02-19 15:16:21.427: D/skia(5467): ----- started: [1 325] http://www.bmimobile.co.uk/images/mobile/bg-index.png
    02-19 15:16:21.517: D/skia(5467): ----- started: [1 64] http://www.bmimobile.co.uk/CubeCore/modules/cubeMobile/images/bg-black-bar.png
    02-19 15:16:21.542: D/skia(5467): ----- started: [26 20] http://www.bmimobile.co.uk/images/mobile/home-icon.png
    02-19 15:16:21.577: D/skia(5467): ----- started: [275 189] http://www.bmimobile.co.uk/images/mobile/home-img.png
    02-19 15:16:21.597: D/skia(5467): ----- started: [270 38] http://www.bmimobile.co.uk/images/mobile/welcome/next.png
    02-19 15:16:21.677: D/skia(5467): ----- started: [16 17] http://www.bmimobile.co.uk/images/mobile/why.png
    02-19 15:16:21.677: D/skia(5467): ----- started: [20 15] http://www.bmimobile.co.uk/images/mobile/visit.png
    02-19 15:16:21.677: D/skia(5467): ----- started: [18 17] http://www.bmimobile.co.uk/images/mobile/services.png
    02-19 15:16:21.687: D/skia(5467): ----- started: [20 15] http://www.bmimobile.co.uk/images/mobile/consultants.png
    02-19 15:16:21.687: D/skia(5467): ----- started: [13 19] http://www.bmimobile.co.uk/images/mobile/contact.png
    02-19 15:16:21.692: D/skia(5467): ----- started: [320 450] http://www.bmimobile.co.uk/images/mobile/welcome/bg-welcome.jpg
    

    .

    [notes] if i click on the why-bmi button when in online mode then come out of the app, turn the adapter off then click the why-bmi button again then it shows the "error loading page" message.

    If i however change to the following urls, my SO page is displayed. If i click the link to my bounty page(this page), then go offline, the SO page is display as you would expect but if you click the bounty link in offline mode then it DOES display. so there are differences between the SO site and the bmi site.

    if(isNetworkAvailable() == true){
    
                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);
                webView.getSettings().setAppCacheEnabled(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().setJavaScriptEnabled(true);
    
                // Load the URLs inside the WebView, not in the external web browser
                webView.setWebViewClient(new WebViewClient());  
                webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
    
    
                //webView.loadUrl("http://www.bmimobile.co.uk/why-bmi.php", getHeaders());
                //webView.loadUrl("http://www.bmimobile.co.uk/", getHeaders());
    
                webView.loadUrl("http://stackoverflow.com/users/532462/turtleboy?tab=bounties");
                webView.loadUrl("http://stackoverflow.com/users/532462/turtleboy");
                }else{
    
                    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);
                    webView.getSettings().setAppCacheEnabled(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().setJavaScriptEnabled(true);
    
    
    
                    // Load the URLs inside the WebView, not in the external web browser
                    webView.setWebViewClient(new WebViewClient());  
    
    
    
                    webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ONLY);
    
                   // webView.loadUrl("http://www.bmimobile.co.uk/", getHeaders());
                    webView.loadUrl("http://stackoverflow.com/users/532462/turtleboy");
    
    
                }
    
    
        }
    

    [edit2]

        <?xml version="1.0" encoding="utf-8"?>
        <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="uk.bmi.mobile"
            android:versionCode="5"
            android:versionName="1.0.4" >
    
            <!-- GCM requires Android SDK version 2.2 (API level <img src="http://www.androidhive.info/wp-includes/images/smilies/icon_cool.gif" alt="8)" class="wp-smiley"> or above. -->
            <uses-sdk
                android:minSdkVersion="8"
                android:targetSdkVersion="16" />
    
            <!-- GCM connects to Internet Services. -->
            <uses-permission android:name="android.permission.INTERNET" />
    
            <!-- GCM requires a Google account. -->
            <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    
            <!-- Keeps the processor from sleeping when a message is received. -->
            <uses-permission android:name="android.permission.WAKE_LOCK" />
    
            <!-- Creates a custom permission so only this app can receive its messages. -->
            <permission
                android:name="uk.bmi.mobile.permission.C2D_MESSAGE"
                android:protectionLevel="signature" />
    
            <uses-permission android:name="uk.bmi.mobile.permission.C2D_MESSAGE" />
    
            <!-- This app has permission to register and receive data message. -->
            <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
    
            <!-- Network State Permissions to detect Internet status -->
            <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    
            <!-- Permission to vibrate -->
            <uses-permission android:name="android.permission.VIBRATE" />
    
        <uses-permission android:name="android.permisson.ACCESS_WIFI_STATE"/>
        <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
    
            <!-- Main activity. -->
            <application
                android:icon="@drawable/bmi_icon"
                android:label="@string/app_name"
                android:name="uk.bmi.mobile.ApplicationExt" >
                <!-- Register Activity -->
                <activity
                    android:name=".RegisterActivity"
                    android:label="@string/app_name" >
                    <intent-filter>
                        <action android:name="android.intent.action.MAIN" />
    
                        <category android:name="android.intent.category.LAUNCHER" />
                    </intent-filter>
                </activity>
    
                <!-- Main Activity -->
                <activity
                    android:name="uk.bmi.mobile.MainActivity"
                    android:configChanges="orientation|keyboardHidden"
                    android:label="@string/app_name"
                     android:screenOrientation="portrait" >
                </activity>
    
                <receiver
                    android:name="com.google.android.gcm.GCMBroadcastReceiver"
                    android:permission="com.google.android.c2dm.permission.SEND" >
                    <intent-filter>
    
                        <!-- Receives the actual messages. -->
                        <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                        <!-- Receives the registration id. -->
                        <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
    
                        <category android:name="uk.bmi.mobile" />
                    </intent-filter>
                </receiver>
    
                <service android:name="uk.bmi.mobile.GCMIntentService" />
            </application>
    
        </manifest>
    
  • Evgenii Vorobei
    Evgenii Vorobei about 6 years
    FileUtils from <br/>dependencies { compile 'org.apache.commons:commons-io:1.3.2' }
  • Ravi Vaniya
    Ravi Vaniya over 3 years
    what is getHeaders() ?