Android Webview - Vider complètement le cache

111

J'ai une WebView dans l'une de mes activités, et lorsqu'elle charge une page Web, la page recueille des données d'arrière-plan de Facebook.

Ce que je vois cependant, c'est que la page affichée dans l'application est la même à chaque fois que l'application est ouverte et actualisée.

J'ai essayé de configurer WebView pour ne pas utiliser le cache et effacer le cache et l'historique de WebView.

J'ai également suivi la suggestion ici: Comment vider le cache pour WebView?

Mais rien de tout cela ne fonctionne, est-ce que quelqu'un a des idées sur le fait que je peux surmonter ce problème parce que c'est une partie vitale de mon application.

    mWebView.setWebChromeClient(new WebChromeClient()
    {
           public void onProgressChanged(WebView view, int progress)
           {
               if(progress >= 100)
               {
                   mProgressBar.setVisibility(ProgressBar.INVISIBLE);
               }
               else
               {
                   mProgressBar.setVisibility(ProgressBar.VISIBLE);
               }
           }
    });
    mWebView.setWebViewClient(new SignInFBWebViewClient(mUIHandler));
    mWebView.getSettings().setJavaScriptEnabled(true);
    mWebView.clearHistory();
    mWebView.clearFormData();
    mWebView.clearCache(true);

    WebSettings webSettings = mWebView.getSettings();
    webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);

    Time time = new Time();
    time.setToNow();

    mWebView.loadUrl(mSocialProxy.getSignInURL()+"?time="+time.format("%Y%m%d%H%M%S"));

J'ai donc implémenté la première suggestion (bien que changé le code pour être récursif)

private void clearApplicationCache() {
    File dir = getCacheDir();

    if (dir != null && dir.isDirectory()) {
        try {
            ArrayList<File> stack = new ArrayList<File>();

            // Initialise the list
            File[] children = dir.listFiles();
            for (File child : children) {
                stack.add(child);
            }

            while (stack.size() > 0) {
                Log.v(TAG, LOG_START + "Clearing the stack - " + stack.size());
                File f = stack.get(stack.size() - 1);
                if (f.isDirectory() == true) {
                    boolean empty = f.delete();

                    if (empty == false) {
                        File[] files = f.listFiles();
                        if (files.length != 0) {
                            for (File tmp : files) {
                                stack.add(tmp);
                            }
                        }
                    } else {
                        stack.remove(stack.size() - 1);
                    }
                } else {
                    f.delete();
                    stack.remove(stack.size() - 1);
                }
            }
        } catch (Exception e) {
            Log.e(TAG, LOG_START + "Failed to clean the cache");
        }
    }
}

Cependant, cela n'a toujours pas changé ce que la page affiche. Sur mon navigateur de bureau, j'obtiens un code html différent de la page Web produite dans WebView, donc je sais que WebView doit être mis en cache quelque part.

Sur le canal IRC, on m'a indiqué un correctif pour supprimer la mise en cache d'une connexion URL, mais je ne vois pas encore comment l'appliquer à une WebView.

http://www.androidsnippets.org/snippets/45/

Si je supprime mon application et la réinstalle, je peux remettre la page Web à jour, c'est-à-dire une version non mise en cache. Le principal problème est que les modifications sont apportées aux liens dans la page Web, de sorte que le front-end de la page Web est complètement inchangé.

Matt Gaunt
la source
1
mWebView.getSettings().setAppCacheEnabled(false);n'a pas fonctionné?
Paul

Réponses:

45

L'extrait de code modifié ci-dessus publié par Gaunt Face contient une erreur en ce sens que si un répertoire ne parvient pas à être supprimé car l'un de ses fichiers ne peut pas être supprimé, le code continuera à réessayer dans une boucle infinie. Je l'ai réécrit pour qu'il soit vraiment récursif et j'ai ajouté un paramètre numDays afin que vous puissiez contrôler l'âge des fichiers élagués:

//helper method for clearCache() , recursive
//returns number of deleted files
static int clearCacheFolder(final File dir, final int numDays) {

    int deletedFiles = 0;
    if (dir!= null && dir.isDirectory()) {
        try {
            for (File child:dir.listFiles()) {

                //first delete subdirectories recursively
                if (child.isDirectory()) {
                    deletedFiles += clearCacheFolder(child, numDays);
                }

                //then delete the files and subdirectories in this dir
                //only empty directories can be deleted, so subdirs have been done first
                if (child.lastModified() < new Date().getTime() - numDays * DateUtils.DAY_IN_MILLIS) {
                    if (child.delete()) {
                        deletedFiles++;
                    }
                }
            }
        }
        catch(Exception e) {
            Log.e(TAG, String.format("Failed to clean the cache, error %s", e.getMessage()));
        }
    }
    return deletedFiles;
}

/*
 * Delete the files older than numDays days from the application cache
 * 0 means all files.
 */
public static void clearCache(final Context context, final int numDays) {
    Log.i(TAG, String.format("Starting cache prune, deleting files older than %d days", numDays));
    int numDeletedFiles = clearCacheFolder(context.getCacheDir(), numDays);
    Log.i(TAG, String.format("Cache pruning completed, %d files deleted", numDeletedFiles));
}

J'espère que cela sera utile à d'autres personnes :)

Markjan
la source
Merci beaucoup! vous avez sauvé ma journée :)
Kris
Grande routine, nous a sauvé beaucoup d'agonie.
Mr Ed
Puis-je utiliser ce code dans une application pour vider le cache de certaines applications installées sur mon téléphone?
Si8
Si tout le répertoire doit être supprimé, Runtime.getRuntime (). Exec ("rm -rf" + dirName + "\ n"); être plus facile?
source.rar
@ source.rar Oui, mais vous ne pouvez pas conserver les fichiers de moins de x jours, ce que vous souhaitez généralement pour un dossier de cache.
markjan
205

J'ai trouvé une solution même élégante et simple pour vider le cache

WebView obj;
obj.clearCache(true);

http://developer.android.com/reference/android/webkit/WebView.html#clearCache%28boolean%29

J'ai essayé de trouver le moyen de vider le cache, mais tout ce que nous pouvions faire à partir des méthodes mentionnées ci-dessus était de supprimer les fichiers locaux, mais cela ne nettoie jamais la RAM.

L'API clearCache libère la RAM utilisée par la vue Web et oblige donc à recharger la page Web.

Akshat
la source
11
La meilleure réponse ici.
user486134
La meilleure réponse et je me demande pourquoi elle n'est pas acceptée..Kudos Akshat :)
Karthik
1
Pas de chance pour moi. Je me demande si quelque chose a changé? Je peux charger une WebView avec google.com et la WebView pense toujours que je suis connecté, même après clearCache (true);
lostintranslation
2
@lostintranslation Pour cela, vous souhaitez probablement supprimer les cookies. Même si je suis sûr que vous l'avez découvert maintenant.
NineToeNerd
Besoin d'allouer l'objet? WebView obj = nouveau WebView (ceci); obj.clearCache (vrai); Bref, très bien pour moi, voté pour!
Giorgio Barchiesi
45

J'ai trouvé le correctif que vous recherchiez:

context.deleteDatabase("webview.db");
context.deleteDatabase("webviewCache.db");

Pour une raison quelconque, Android crée un mauvais cache de l'URL qu'il renvoie par accident au lieu des nouvelles données dont vous avez besoin. Bien sûr, vous pouvez simplement supprimer les entrées de la base de données, mais dans mon cas, j'essaie d'accéder à une seule URL, il est donc plus facile de supprimer toute la base de données.

Et ne vous inquiétez pas, ces bases de données sont simplement associées à votre application, vous ne videz donc pas le cache de tout le téléphone.

Scott
la source
Merci, c'est une astuce incroyablement soignée. Il mérite d'être plus largement connu.
Philip Sheard
2
Cela lève une mauvaise exception en nid d'abeille: 06-14 22: 33: 34.349: ERREUR / SQLiteDatabase (20382): Impossible d'ouvrir la base de données. le fermer. 06-14 22: 33: 34.349: ERREUR / SQLiteDatabase (20382): android.database.sqlite.SQLiteDiskIOException: erreur d'E / S de disque 06-14 22: 33: 34.349: ERREUR / SQLiteDatabase (20382): sur android.database. sqlite.SQLiteDatabase.native_setLocale (Méthode native)
Rafael Sanches
Cheers Rafael, j'aimerais penser que c'est parce que le problème d'origine a été résolu dans Honeycomb. Est-ce que quelqu'un sait si c'est le cas?
Scott
il suffit de mettre 2 lignes dans onBackpress () ou sur le bouton retour, aucun historique ne reste dans la pile arrière grâce à un gain de temps considérable.
CrazyMind
36

Pour effacer tous les caches de vues Web lorsque vous vous déconnectez de votre APP:

CookieSyncManager.createInstance(this);         
CookieManager cookieManager = CookieManager.getInstance();        
cookieManager.removeAllCookie();

Pour Lollipop et plus:

CookieSyncManager.createInstance(this);         
CookieManager cookieManager = CookieManager.getInstance();        
cookieManager.removeAllCookies(ValueCallback);
amalBit
la source
1
sauve ma vie et ma journée.
Uday Nayak
2
Fonctionne bien si vous n'avez pas accès à la vue Web dans votre activité. Notez également que cette API est obsolète, utilisez donc plutôt l'API "removeAllCookies (ValueCallback)" sur les appareils L +.
Akshat
que dois-je remplacer par ValueCallBack?
Qaisar Khan Bangash
@QaisarKhanBangash new ValueCallback <Boolean> () {atOverride public void onReceiveValue (valeur booléenne) {}}
amalBit
3

Cela devrait effacer le cache de vos applications, qui devrait être l'emplacement de votre cache de vues Web

File dir = getActivity().getCacheDir();

if (dir != null && dir.isDirectory()) {
    try {
        File[] children = dir.listFiles();
        if (children.length > 0) {
            for (int i = 0; i < children.length; i++) {
                File[] temp = children[i].listFiles();
                for (int x = 0; x < temp.length; x++) {
                    temp[x].delete();
                }
            }
        }
    } catch (Exception e) {
        Log.e("Cache", "failed cache clean");
    }
}
jqpubliq
la source
J'ai essayé (code légèrement modifié) et j'ai toujours obtenu les mêmes résultats -> Expliqué ci
Matt Gaunt
3

La seule solution qui fonctionne pour moi

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
    CookieManager.getInstance().removeAllCookies(null);
    CookieManager.getInstance().flush();
} 
Ketan Ramani
la source
2

Utiliser simplement le code ci-dessous dans Kotlin fonctionne pour moi

WebView(applicationContext).clearCache(true)
Ercan
la source
2

Pour effacer le cookie et le cache de Webview,

    // Clear all the Application Cache, Web SQL Database and the HTML5 Web Storage
    WebStorage.getInstance().deleteAllData();

    // Clear all the cookies
    CookieManager.getInstance().removeAllCookies(null);
    CookieManager.getInstance().flush();

    webView.clearCache(true);
    webView.clearFormData();
    webView.clearHistory();
    webView.clearSslPreferences();
Srinivasan
la source
0

Assurez-vous que vous utilisez la méthode ci-dessous pour que les données du formulaire ne soient pas affichées comme autopop lorsque vous cliquez sur les champs de saisie.

getSettings().setSaveFormData(false);
Raghu
la source
0
CookieSyncManager.createInstance(this);         
CookieManager cookieManager = CookieManager.getInstance();        
cookieManager.removeAllCookie();
WaqasArshad
la source
0
CookieSyncManager.createInstance(this);    
CookieManager cookieManager = CookieManager.getInstance(); 
cookieManager.removeAllCookie();

Il peut effacer le compte Google dans ma vue Web

Dũng Phạm Tiến
la source
2
CookieSyncManager est obsolète
Développeur
-1

cas d'utilisation: la liste des éléments est affichée dans la vue du recycleur, chaque fois qu'un élément clique, elle masque la vue du recycleur et affiche la vue Web avec l'URL de l'élément.

problème: j'ai un problème similaire dans lequel une fois que j'ouvre une vue url_oneWeb, puis j'essaie d'en ouvrir une autre url_twodans la vue Web, elle s'affiche url_oneen arrière-plan jusqu'à ce qu'elle url_twosoit chargée.

solution: donc pour résoudre ce que j'ai fait, c'est charger une chaîne vide ""comme urljuste avant de la cacher url_oneet de la charger url_two.

production: chaque fois que je charge une nouvelle URL dans la vue Web, aucune autre page Web ne s'affiche en arrière-plan.

code

public void showWebView(String url){
        webView.loadUrl(url);
        recyclerView.setVisibility(View.GONE);
        webView.setVisibility(View.VISIBLE);
    }

public void onListItemClick(String url){
   showWebView(url);
}

public void hideWebView(){
        // loading blank url so it overrides last open url
        webView.loadUrl("");
        webView.setVisibility(View.GONE);
        recyclerView.setVisibility(View.GONE);
   }


 @Override
public void onBackPressed() {
    if(webView.getVisibility() == View.VISIBLE){
        hideWebView();
    }else{
        super.onBackPressed();
    }
}
Abhishek Garg
la source
Comment cela est-il lié à la question?
Zun
@Zun merci d'avoir voté contre, et j'apprécie vraiment les commentaires, et ma réponse à votre question est que je suis coincé dans un scénario similaire, mais j'ai un peu différent, mais la sortie des deux est la même, donc avant d'écrire ma réponse J'ai également écrit un cas utilisateur, il obtiendra un effet similaire à celui demandé en question, sans avoir besoin de gérer les cookies.
Abhishek Garg