Android 使用 AsyncTask 通过 jsoup 获取 url 时应用崩溃

Android app crashes when using AsyncTask for fetching an url with jsoup

所以应用程序在加载时显示了对话框,但随后崩溃了。我决定不使用这些技术的原因是因为我必须加载动态变化的 html,并且我想缓存大量 CSS 文件,所以我认为将它们作为资产包括在内是一个好主意。我使用 Jsoup 是因为我无需下载完整内容即可获得 html 页面。 这是代码:

public class MyWebViewFragment extends Fragment {

ProgressDialog mProgress;
WebView webview;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.web_fragment, container,
            false);

    Bundle bundle = getArguments();

    String url = bundle.getString("url");

    webview = (WebView) rootView.findViewById(R.id.webview1);

    WebSettings settings = webview.getSettings();
    settings.setJavaScriptEnabled(true);

    mProgress = ProgressDialog.show(getActivity(), "Loading",
            "Please wait for a moment...");
    fetchUrl thread = (fetchUrl) new fetchUrl().execute();
    Document doc = thread.getDoc();
    String htmlData = null;
    doc.head().getElementsByTag("link").remove();
    doc.head().appendElement("link").attr("rel", "stylesheet").attr("type", "text/css").attr("href", "style.css");
    htmlData = doc.outerHtml();
    //TODO fetchURL here
    webview.loadDataWithBaseURL("file:///assets/", htmlData, "text/html", "UTF-8", null);

   // webview.loadUrl(url);
    webview.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, String url) {
            //TODO add assets loading he instead of urlLoad
            //view.loadUrl(url);
            return false;
        }

        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            if (mProgress.isShowing()) {
                mProgress.dismiss();
            }
        }
    });

    return rootView;
}

class 扩展 AsybcTask:

    private class fetchUrl extends AsyncTask<Void, Void, Document>{
    Document doc;
    @Override
    protected Document doInBackground(Void... param) {
        try {
          doc = Jsoup.connect("http://example.ch").userAgent("Chrome").get();//use url when ready
        } catch (IOException ex) {
    }
        return doc;   
    }


}

以及错误日志:

--------- beginning of crash
E/AndroidRuntime( 5125): FATAL EXCEPTION: main
E/AndroidRuntime( 5125): Process: com.flexenergy.swapp, PID: 5125
E/AndroidRuntime( 5125): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.flexenergy.swapp/com.flexenergy.swapp.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'org.jsoup.nodes.Element org.jsoup.nodes.Document.head()' on a null object reference
E/AndroidRuntime( 5125):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2325)
E/AndroidRuntime( 5125):    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2390)
E/AndroidRuntime( 5125):    at android.app.ActivityThread.access0(ActivityThread.java:151)
E/AndroidRuntime( 5125):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1303)
E/AndroidRuntime( 5125):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime( 5125):    at android.os.Looper.loop(Looper.java:135)
E/AndroidRuntime( 5125):    at android.app.ActivityThread.main(ActivityThread.java:5257)
E/AndroidRuntime( 5125):    at java.lang.reflect.Method.invoke(Native Method)
E/AndroidRuntime( 5125):    at java.lang.reflect.Method.invoke(Method.java:372)
E/AndroidRuntime( 5125):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
E/AndroidRuntime( 5125):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
E/AndroidRuntime( 5125): Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'org.jsoup.nodes.Element org.jsoup.nodes.Document.head()' on a null object reference
E/AndroidRuntime( 5125):    at com.flexenergy.swapp.MyWebViewFragment.onCreateView(MyWebViewFragment.java:49)
E/AndroidRuntime( 5125):    at android.app.Fragment.performCreateView(Fragment.java:2053)   
E/AndroidRuntime( 5125):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:894)
E/AndroidRuntime( 5125):    at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1067)
E/AndroidRuntime( 5125):    at android.app.BackStackRecord.run(BackStackRecord.java:834)
E/AndroidRuntime( 5125):    at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1452)
E/AndroidRuntime( 5125):    at android.app.Activity.performStart(Activity.java:6005)
E/AndroidRuntime( 5125):    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2288)
E/AndroidRuntime( 5125):    ... 10 more
W/ActivityManager( 1219):   Force finishing activity 1 com.flexenergy.swapp/.MainActivity
I/Choreographer( 1219): Skipped 30 frames!  The application may be doing too much work on its main thread.
E/EGL_emulation(  919): tid 919: eglCreateSyncKHR(1237): error 0x3004 (EGL_BAD_ATTRIBUTE)

AsyncTask 是主线程的并发进程,因此要使用该计算的结果,您需要等到它完成他的工作。

您正在尝试调用 doc.head(),但 doc 是空引用,因为 asyncTask 尚未完成,因此尚未初始化 doc

在 AsyncTask 的 OnPostExecute(result) 方法中用 doc 做你的事情,这样你就可以确保 doc 被正确初始化。