1

我有一个从网络获取 xml 文件的应用程序,对其进行解析以检索我必须缓存的网站网页的路径。例如

/services/orthopaedics.php

. 我可以成功下载所有需要缓存的页面的路径。目前我在 AsyncTask 中执行此操作。Web 服务调用的结果(页面路径)存储在 AsyncTask 的 doInBackground 方法中的 contentsValues 中。然后我在 onPostExecute() 方法中遍历这些内容值,我可以在 webview 的 loadUrl() 方法中一一加载网页。这个 webview 是不可见的,因为它只用于缓存目的。

问题在于,由于不可见的 webview 正在加载用户可以看到的另一个 webview,并且要显示站点的索引页面,因此加载速度很慢。在不可见的 webview 停止加载缓存之前,会出现一个白屏。在 phoe 上大约需要 4 秒,这是可以接受的,但在 android 平板电脑上大约需要 30 秒。

我知道对 webview 的调用必须在 UI 线程上,这就是为什么我在 onPostExecute 方法中加载网页(不可见的 webview)。是否可以在 doInBacground 方法中以某种方式将页面加载到缓存中,但将 webview.loadUrl() 放在 runOnUiThread(new Runnable) 中?

我将在下面给出我的意思的简化示例。

private class AsyncCacheSite extends AsyncTask<String, ContentValues, ContentValues>{

        ProgressDialog progressDialog;

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            Log.e(TAG, "about to load main page");
            webView.loadUrl(mobileWebsiteUrl, getHeaders());

            progressDialog = new ProgressDialog(MainActivity.this);
            progressDialog.setTitle("Connecting to Server");
            progressDialog.setMessage("Caching website for offline use...");
            progressDialog.setIndeterminate(true);
            progressDialog.show();
        }

        @Override
        protected ContentValues doInBackground(String... params) {
            ContentValues cv = null;

            try {
                //call the service to get the xml file containing paths
                cv = ws.checkForUpdates();


            } catch (Exception e) {
               e.printStackTrace();
            }

//iterate through the xml file geting the paths
.......
.......
.......
runOnUiThread(new Runnable() {

                            @Override
                            public void run() {
                                // TODO Auto-generated method stub
loadUrlIntoCache(page);

                            }
                        })


            return null; 

        }



        @Override
        protected void onPostExecute(ContentValues result) {
            super.onPostExecute(result);



            progressDialog.dismiss();


    }//end of postExecute

 }//end of asyncTask



public void loadUrlIntoCache(String pageUrl){

        WebView wv2 = new WebView(MainActivity.this);

        wv2.getSettings().setSupportZoom(true);
        wv2.getSettings().setBuiltInZoomControls(true);
        wv2.setScrollBarStyle(WebView.SCROLLBARS_OUTSIDE_OVERLAY);
        wv2.setScrollbarFadingEnabled(true);
        wv2.getSettings().setLoadsImagesAutomatically(true);
        wv2.getSettings().setDomStorageEnabled(true);
        wv2.getSettings().setAppCacheEnabled(true);
        // Set cache size to 8 mb by default. should be more than enough
        wv2.getSettings().setAppCacheMaxSize(1024*1024*32);
        // 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();

        wv2.getSettings().setAppCachePath(appCachePath);
        wv2.getSettings().setAllowFileAccess(true);
        wv2.getSettings().setJavaScriptEnabled(true);
       // wv2.setWebViewClient(new WebViewClient());

////////////////////////////////////////////////////////////////////////////////////////
/////the webviewclient below is the code you gave me to overcome the redirecting issue//
////////////////////////////////////////////////////////////////////////////////////////
webView.setWebViewClient(new WebViewClient() {
public boolean shouldOverrideUrlLoading(WebView view, String url){
// do your handling codes here, which url is the requested url
// probably you need to open that url rather than redirect:
view.loadUrl(url);
return false; // then it is not handled by default action
}
});

        wv2.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT);
        wv2.setVisibility(View.GONE); 

        wv2.loadUrl(mobileWebsiteUrl + pageUrl, getHeaders());
        Log.e(TAG, "loading " + mobileWebsiteUrl + pageUrl);



    }
4

3 回答 3

3

我认为唯一的解决方案是在 doInBackground 中使用 http 请求加载数据,然后在 publishProgress 中使用 loadData

于 2013-02-26T18:18:27.780 回答
2

遗憾的是,您无法从 AsyncTask 中“加载” URL。必须从主线程调用所有“WebView”方法。

您所能做的就是在第二个线程中更新进度对话框。检查这个答案Webview with asynctask on Android

于 2014-10-23T15:59:21.730 回答
0

WebView 需要从 UI 线程调用。如果您碰巧可以访问主循环器,则可以通过 UI 线程处理程序创建、设置和加载页面。

    //Code for creating an instance of Webview inside AsyncTask
    WebView wv = null;
    final Object lock = new Object();
    final int TIMEOUT_MS = 3000;
    AtomicReference<WebView> holder = new AtomicReference<>(); //use to pass the created webview back to worker thread.
    Handler mainHandler = new Handler(Looper.getMainLooper());
    try {
        synchronized (lock) {
            while (wv == null) {
                mainHandler.post(() -> {
                    synchronized (lock) {
                        WebView localWebView = new WebView(context);
                        setWebViewCache(context, localWebView); //configure the cache to your desired location.
                        holder.set(localWebView); //use this line to pass out the created instance from the UI thread back to your async task.
                        lock.notify();
                    }
                });
                lock.wait(TIMEOUT_MS);
                wv = holder.get();
            }
        }
    } catch (InterruptedException ie) {
        Log.e(TAG, "creating prefetch webview times out");
    }

接下来,您要使用 AsyncTask 中所需的 URL 加载 Webview。

  synchronized (lock) {
            mainHandler.post(() -> {
                wv.setWebViewClient(new WebViewClient() {
                    @Override
                    public void onPageFinished(WebView view, String url) {
                        super.onPageFinished(view, url);
                        //override with behavior you want after load finishes, make sure to notify the workerthread to proceed.
                        synchronized (lock) {
                            lock.notify();
                        }
                    }
                });
                wv.loadData(html, mimeType, encoding); //here load the url you want
            });
            lock.wait(TIMEOUT_MS);
        }

希望我的代码可以提供帮助。

于 2019-08-20T00:12:04.257 回答