简体   繁体   中英

How should I handle HTTP response codes when using AsyncTask?

I am creating an android app which takes user input, attempts to make a connection to the API url with the specified input and retrieve data and display it. Now I've been able to do everything above but there is a potential chance that if a user enters something and it doesn't exist my app will crash because of a NPE (Null Pointer Exception).

The API I am using shows me a list of response errors that can occur but I'm not sure how I should handle or implement a feature that takes these response errors into account.

Currently my extended AsyncTask class has these parameters: String, Void, JSONObject and the following code is what I have in my doInBackground method.

URL url = new URL(params[0]);
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.connect();

int statusCode = urlConnection.getResponseCode();
switch (statusCode) {
    case 400:
    return "Error 400 - Bad request.";
    case 401:
    return "Error 401 - Unauthorized request.";
}

I can't return a String because my AsyncTask param returns a JSONObject. I can change it so it does return a String but I believe it's not the proper logical way of handling the response errors.

Now if the API response code was a 404 (No data found), I don't want the app to crash because it can't return the JSONObject, instead I would like it to continue on to the next fragment and display minimal information.

So how do I go about handling response errors when my method returns a JSONObject?

You have a couple options (I say #1 is your best bet)

1) Create a custom JSON object to carry the statuscode from the background part to the UI (or other calling thread). Then just check if the JSON returned from the asynctask is one of the 'HTTP result JSONs' instead of whatever the normal results are. (essentially wrap your 'exceptions'/etc. from the background processing in JSON and use JSON to transport your return message for processing in either condition.)

2) You can throw an exception (but personally I think this is bad design, Its generally better to catch exceptions and then handle them in the onPostExecute() (Via flags like #1)

3) You can set a flag somewhere outside the asyncTask as to what the return code was (But this is generally NOT thread safe. Meaning it might be troublesome if your user causes two tasks to be ran at once and they return in different order (or at same time) and you might not get the 'right' value for each's return.)

4) you can do like https://stackoverflow.com/a/6312491/5673694 says to do. But there is 1 bad issue and 1 'ehh' issue...

The bad issue: Her implementation HAS A MEMORY LEAK issue with it. Inner classes in Java have an inherit reference to their outer class instance when they are instantiated. This means that if your async task is still running that your parent class/(activity most likely) won't be able to be Garbage Collected if you for some reason back out of your application/a phone call comes in/etc... So your Application can eat up memory from the system when it shouldn't for quite a long time. (however long your asyncTask runs(infinitely possibly)) To fix this, make the inner class static, and use a WeakRefernce<> to the Class Instance. (This should be done for ALL inner classes in Android where they work with background tasks, such as Handlers, etc.) This Memory Leak issue isn't well documented, but exists and we discuss it in the MOOC that my PhD adviser is the Instructor and I'm Staff https://www.coursera.org/course/posacommunication

the 'ehh' issue(And this is more of a 'be warned' issue)... you can make the AsyncTask store the Exception, but this has the problem of potentially causing problems if you ever make it a static in your AsyncTask class (Statics and Generics in Java don't work the same way as they do in C++, in C++ you get different class implementations for each variation of a templated class, but in Java there is only 1 class file so therefore statics are 'shared' between all different versions.) (Note: just above says 'static class' and here I'm talking about 'static variables within that class')

You can return null when the statusCode is not 200:

            URL url = new URL(params[0]);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            int statusCode = urlConnection.getResponseCode();

            if(statusCode!= 200){

                return null;

            }

Then in your postExecute you can check that condition:

protected void onPostExecute(JSONObject result) {

    if (result == null) {

        // Inform the user something weird happened

    }
    else{

        // Do your normal condition with your JSON object
    }

You can also try another approach: instead of returning a JSON object, you can return a ArrayList:

            ArrayList<Object>  result = new ArrayList<Object>();

            URL url = new URL(params[0]);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestMethod("GET");
            urlConnection.connect();

            int statusCode = urlConnection.getResponseCode();


            switch (statusCode) {

                case 200:
                   // Your code to build your JSON object
                   JSONObject yourJsonObject = ...
                   result.add("Ok");
                   result.add(yourJsonObject);
                   break;
                case 400:
                   result.add("Error 400 - Bad request.");
                   result.add(null);
                   break;
                case 401:
                   result.add("Error 401 - Unauthorized request.");
                   result.add(null);
                   break;
            }

And then in your postExecute check that ArrayList object:

protected void onPostExecute(ArrayList<Object> result) {

    String message = (String) result.get(0);
    JSONObject yourJsonObject = (JSONObject) result.get(1);


    if (result == yourJsonObject) {

        // Inform the user something weird happened
        // Example: Toast the message

    }
    else{

        // Do your normal condition with your JSON object

    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM