Search code examples
androidandroidhttpclient

android HttpURLConnection catch if nothing could download


I'm using an asynctask to download an xml from an given URL. I get the url from the preferencescreen. N

Now i'm trying to catch some errors so the app doesn't crash but gives a nice toast with the error.

It works already for if the user forgets the 'http://' before the URL. But when the URL is good formed but there is nothing to download the app still crashes and I don't know how to catch this error: i thought the IOException would catch this error but it doesn't.

@Override
protected void onPreExecute() {
    progressDialog = new ProgressDialog(mContext);
    progressDialog.setTitle("XML downloaden");
    progressDialog.setMessage("Downloading xml:");
    progressDialog.setMax(100);
    progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
    progressDialog.show();
}

    @Override
protected Void doInBackground(Void... params) {

    FileOutputStream fos = null;
    InputStream inputStream = null;
    HttpURLConnection conn = null;
    try {
        fos = mContext.openFileOutput("xmlapp.xml", Context.MODE_PRIVATE);

        SharedPreferences prefs = PreferenceManager
                .getDefaultSharedPreferences(mContext);
        String start = prefs.getString("pref_key_url",
                "http://sdesigns.be/eindwerk/web6/");

        URL url;
        url = new URL(start + "source/pages.xml");
        conn = (HttpURLConnection) url.openConnection();

            byte[] buffer = new byte[64];
            if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                int bytesToDownload = conn.getContentLength();
                int bytesDownloaded = 0;
                inputStream = conn.getInputStream();
                int len = 0;
                while ((len = inputStream.read(buffer)) > 0) {
                    fos.write(buffer, 0, len);
                    bytesDownloaded += len;
                    publishProgress((float) bytesDownloaded / bytesToDownload);
                }
                inputStream.close();
                fos.close();
            } 



    } catch (MalformedURLException e) {
        this.e = e;
    } catch (IOException e) {
        this.e = e;
    } 
    finally {
         conn.disconnect();
    }

    return null;
}

@Override
protected void onPostExecute(Void result) {

    if (progressDialog != null) {
        progressDialog.dismiss();
        progressDialog = null;
    }
    if (e == null) {
        List<String> images = new XmlParserSax(mContext).getImagesList();
        DownloadImages di = new DownloadImages(mContext);
        di.execute(images);
    } else {
        Toast.makeText(mContext,
                "Check the url!" + e.toString(),
                Toast.LENGTH_LONG).show(); //show the error
    }

}

EDIT

Stacktrace:

    04-19 10:18:40.904: E/WindowManager(2425): Activity com.example.eindwerkappv1.Preferences has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@41a97848 that was originally added here
04-19 10:18:40.904: E/WindowManager(2425): android.view.WindowLeaked: Activity com.example.eindwerkappv1.Preferences has leaked window com.android.internal.policy.impl.PhoneWindow$DecorView@41a97848 that was originally added here
04-19 10:18:40.904: E/WindowManager(2425):  at android.view.ViewRootImpl.<init>(ViewRootImpl.java:344)
04-19 10:18:40.904: E/WindowManager(2425):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:267)
04-19 10:18:40.904: E/WindowManager(2425):  at android.view.WindowManagerImpl.addView(WindowManagerImpl.java:215)
04-19 10:18:40.904: E/WindowManager(2425):  at android.view.WindowManagerImpl$CompatModeWrapper.addView(WindowManagerImpl.java:140)
04-19 10:18:40.904: E/WindowManager(2425):  at android.view.Window$LocalWindowManager.addView(Window.java:537)
04-19 10:18:40.904: E/WindowManager(2425):  at android.app.Dialog.show(Dialog.java:278)
04-19 10:18:40.904: E/WindowManager(2425):  at com.example.eindwerkappv1.DownloadXml.onPreExecute(DownloadXml.java:38)
04-19 10:18:40.904: E/WindowManager(2425):  at android.os.AsyncTask.executeOnExecutor(AsyncTask.java:561)
04-19 10:18:40.904: E/WindowManager(2425):  at android.os.AsyncTask.execute(AsyncTask.java:511)
04-19 10:18:40.904: E/WindowManager(2425):  at com.example.eindwerkappv1.Preferences$1.onPreferenceClick(Preferences.java:48)
04-19 10:18:40.904: E/WindowManager(2425):  at android.preference.Preference.performClick(Preference.java:941)
04-19 10:18:40.904: E/WindowManager(2425):  at android.preference.PreferenceScreen.onItemClick(PreferenceScreen.java:202)
04-19 10:18:40.904: E/WindowManager(2425):  at android.widget.AdapterView.performItemClick(AdapterView.java:292)
04-19 10:18:40.904: E/WindowManager(2425):  at android.widget.AbsListView.performItemClick(AbsListView.java:1068)
04-19 10:18:40.904: E/WindowManager(2425):  at android.widget.AbsListView$PerformClick.run(AbsListView.java:2525)
04-19 10:18:40.904: E/WindowManager(2425):  at android.widget.AbsListView$1.run(AbsListView.java:3186)
04-19 10:18:40.904: E/WindowManager(2425):  at android.os.Handler.handleCallback(Handler.java:605)
04-19 10:18:40.904: E/WindowManager(2425):  at android.os.Handler.dispatchMessage(Handler.java:92)
04-19 10:18:40.904: E/WindowManager(2425):  at android.os.Looper.loop(Looper.java:137)
04-19 10:18:40.904: E/WindowManager(2425):  at android.app.ActivityThread.main(ActivityThread.java:4441)
04-19 10:18:40.904: E/WindowManager(2425):  at java.lang.reflect.Method.invokeNative(Native Method)
04-19 10:18:40.904: E/WindowManager(2425):  at java.lang.reflect.Method.invoke(Method.java:511)
04-19 10:18:40.904: E/WindowManager(2425):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:823)
04-19 10:18:40.904: E/WindowManager(2425):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:590)
04-19 10:18:40.904: E/WindowManager(2425):  at dalvik.system.NativeStart.main(Native Method)

Solution

  • You may want to account for the possibility of the Socket timing out by using conn.setReadTimeout(10000); before you open the connection, then add a catch clause to handle SocketTimeoutException. Note my choice of 10000ms for the timeout is arbitrary.

    One main problem is you're not properly handling what happens when the server returns a response other than HTTP_OK. Even if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) is false, there will be no exceptions caught. MalformedURLException is thrown only for formatting errors in the URL, and IOException in situations where you try to read from a closed socket, or something similar. There is nothing to catch HTTP_NOT_FOUND. A quick fix to this I guess would be adding an else clause to if(conn.getResponseCode() == HttpURLConnection.HTTP_OK).

    else {
        e = new Exception();
    }
    

    This way, e will not be null in onPostExecute(). This of course is not really good practice, but it will work with your code.

    Edit: The following code worked for me just fine. I had to fill in a few areas you didn't include.

    private class DownloadTask extends AsyncTask<Void, Float, Void> {
        Context mContext;
        ProgressDialog progressDialog;
        Exception e;
    
        DownloadTask(Context context) {
            mContext = context;
        }
    
        @Override
        protected void onPreExecute() {
            progressDialog = new ProgressDialog(mContext);
            progressDialog.setTitle("XML downloaden");
            progressDialog.setMessage("Downloading xml:");
            progressDialog.setMax(100);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.show();
        }
    
        @Override
        protected void onProgressUpdate(Float... values) {
            for( float val : values) {
                progressDialog.setProgress((int)(val*100f));
            }
        }
    
        @Override
        protected Void doInBackground(Void... params) {
    
            FileOutputStream fos = null;
            InputStream inputStream = null;
            HttpURLConnection conn = null;
            try {
                fos = mContext.openFileOutput("xmlapp.xml", Context.MODE_PRIVATE);
    
                SharedPreferences prefs = PreferenceManager
                        .getDefaultSharedPreferences(mContext);
                String start = prefs.getString("pref_key_url",
                        "http://sdesigns.be/eindwerk/web6/");
    
                URL url;
                url = new URL(start);
                conn = (HttpURLConnection) url.openConnection();
                conn.setDoInput(true);
                conn.setRequestMethod("GET");
                conn.setReadTimeout(50000);
                conn.connect();
    
                    byte[] buffer = new byte[64];
                    if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
                        int bytesToDownload = conn.getContentLength();
                        int bytesDownloaded = 0;
                        inputStream = conn.getInputStream();
                        int len = 0;
                        while ((len = inputStream.read(buffer)) > 0) {
                            fos.write(buffer, 0, len);
                            bytesDownloaded += len;
                            publishProgress((float) bytesDownloaded / bytesToDownload);
                        }
                        inputStream.close();
                        fos.close();
                    } else {
                        e = new Exception("URL not found.");
                    }
    
            } catch (Exception e) {
                //since you don't differentiate exceptions and just check if e is null, you might as well just have one catch block
                this.e = e;
            }
            finally {
                try {
                 conn.disconnect();
                } catch (Exception e) {}
                conn = null;
            }
    
            return null;
        }
    
        @Override
        protected void onPostExecute(Void result) {
    
            if (progressDialog != null) {
                progressDialog.dismiss();
                progressDialog = null;
            }
            if (e == null) {
                Toast.makeText(mContext,
                        "Success!",
                        Toast.LENGTH_LONG).show();
                List<String> images = new XmlParserSax(mContext).getImagesList();
                DownloadImages di = new DownloadImages(mContext);
                di.execute(images);
            } else {
                Toast.makeText(mContext,
                        "Check the url!" + e.toString(),
                        Toast.LENGTH_LONG).show(); //show the error
            }
    
        }
    }