1

我正在尝试使用 HTTPClient 调用 URL,修改内容,然后使用 webview.loadDataWithBaseURL() 设置数据,但是我遇到了线程问题。

如果我在主 UI 线程上进行 HTTPGet 调用,我会收到一个带有 android.os.NetworkOnMainThreadException 的致命错误。

如果我在新线程中进行调用,并将值设置为该线程中的 webView,我会在日志中收到警告:“必须在 UI 线程上调用所有 WebView 方法。WebView 的未来版本可能不支持使用在其他线程上。”

如果我在一个单独的线程中进行调用并将其设置在一个类变量中并发布到主线程上的 webView,那么 loadDataWithBaseURL() 永远不会得到我在一个单独的线程中调用的数据,因为它似乎在另一个线程完成调用之前发生。

所以问题是:如何在单独的线程中获取内容,并将它们加载到主线程的 webView 中?

public class Browser extends Activity {
public final String CLASS_TAG = "ScoutBrowser";
public WebView webView;
final Activity activity = this;
public String webContent;


/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.getWindow().requestFeature(Window.FEATURE_PROGRESS);
    setContentView(R.layout.activity_browser);

    webView = getWebView();


    Log.i(CLASS_TAG, "Loaded App...");
}

private WebView getWebView() {
    WebView view = (WebView) findViewById(R.id.webView);

    view.setWebChromeClient(new WebChromeClient() {

        public void onProgressChanged(WebView view, int progress) {
            activity.setTitle("Loading...");
            activity.setProgress(progress * 100);
            if (progress == 100)
                activity.setTitle(R.string.app_name);
        }
    });

    view.setWebViewClient(new MyViewerClient());
    view.getSettings().setJavaScriptEnabled(true);
    webContent = "<html><body>initialized...</body></html>";
    new Thread(new Runnable() {
           public void run() {
               webContent = callURL();
               WebView view = (WebView) findViewById(R.id.webView);
               view.loadDataWithBaseURL("http://www.somewebsite.com", webContent, "text/html", null, null);

           }
    }).start(); 

    //view.loadDataWithBaseURL("http://www.somewebsite.com", webContent, "text/html", null, null);


    return view;
}

public String callURL(){
    String content = "<html><body>loading...</body></html>";

    //Creates web clientclient
    DefaultHttpClient httpclient = new DefaultHttpClient();

    // Create a local instance of cookie store
    CookieStore cookieStore = new BasicCookieStore();

    // Create local HTTP context
    HttpContext localContext = new BasicHttpContext();
    // Bind custom cookie store to the local context
    localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

    HttpGet httpget = new HttpGet("http://www.somewebsite.com/"); 

    //System.out.println("executing request " + httpget.getURI());
    Log.d(CLASS_TAG,"executing request " + httpget.getURI());


    // Pass local context as a parameter
    try {
        HttpResponse response = httpclient.execute(httpget, localContext);

        int code = response.getStatusLine().getStatusCode();
        String reason = response.getStatusLine().getReasonPhrase();
        HttpEntity entity = response.getEntity();
        if (entity != null) {
            InputStream instream = entity.getContent();

            content = convertInputStream(instream);
            //tv.setText(content);

        }

        Log.d(CLASS_TAG,"Response Code: "+code+" - "+reason);


    } catch (ClientProtocolException e) {
        Log.e(CLASS_TAG,"ProtocolException",e);
    } catch (IOException e) {
        Log.e(CLASS_TAG,"IOException",e);
    }
    Log.d(CLASS_TAG, webContent);
    return content;
}

public String convertInputStream(InputStream is) throws IOException{
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder sb = new StringBuilder();
        String line = null;
        while ((line = reader.readLine()) != null) {
          sb.append(line);
        }
        is.close();
        return sb.toString();
}

}

4

1 回答 1

2

从新线程中的 run 方法,使用以下方法之一将其发布回 UI 线程:http: //developer.android.com/guide/components/processes-and-threads.html

其他选项是保留一个指向您的线程的变量并在其上调用 join(),或者使用 FutureTask。

于 2013-01-31T01:01:06.773 回答