How to Return Different Objects via Asynctask in Android
I figured this must be a common question, but I surprisingly couldn't find an answer, so maybe my entire structure is terribad...
I have an activity which downloads values/states of a game from a web service via AsyncTask. These values are used to update a custom view.
Once the view is created, various events from the view launch an AsyncTask to download other information.
This is functional, but the problem is I now have half a dozen AsyncTask classes in the activity with almost identical code. The only difference is the type of object that is returned (which is based on the json from the web service) and the method that is called fro开发者_StackOverflow中文版m onPostExecute()
.
How can I use just two AsyncTask (one for post and one for get) without knowing what type of json object will be returned by the web service?
In a similar vein, how can I determine the type of object returned by the web service? The web service, if there is a problem, will return a json string that correlates to an ErrorMessage object rather than (for example) a GameData object.
Should I be using switch
and instanceof
in onPostExecute()
somehow? Callbacks maybe?
You can use an abstract base class, which your related classes extends.
Sample code:
public abstract class IBaseObject {
protected String error;
public IBaseObject(String param) {
error = param;
}
public abstract String getError();
}
public class ObjectOne extends IBaseObject {
private String objectParam;
public ObjectOne(String error, String objectSpecificParam) {
super(error);
objectParam = objectSpecificParam;
}
@Override
public String getError() {
return error;
}
}
and for example, use it like this:
private class GetTask extends AsyncTask<String, Void, IBaseObject> {
protected IBaseObject doInBackground(String... url) {
// Get your data.
// Construct your corresponding object given by specific
// parameters from your JSON response.
if (a_parameter_match) {
return new ObjectOne(some_json_params...);
} else {
return new ObjectTwo(some_json_params...);
}
}
protected void onPostExecute(IBaseObject object) {
object.getError(); // Or whatever you need here.
}
}
This is just from the top of my head. I couldn't relate to your specific problem, although the ideas here should be enough to get you started on your new structure.
This is too long for a comment, so I'm writing an answer. However it was the advice of @Pompe de velo that got me on this track, so I am accepting that answer. I also left out some information from my question that could have been useful.
Anyway, as of right now I do not see any major downsides to this approach, but time ( or maybe another SO user ;] ) will tell...
Essentially I have assigned a constant to every type of object that the activity will try to get. The part that I left out was that the server only returns an error object on a 4xx-5xx http status code. In other words, I am certain to either get the object I am expecting or an error object and I can determine which I got from the status code. Then a switch
sends the actual json string to the appropriate method that can manipulate the response as necessary.
Simplified pseudocode...
private void getGameData(){
new MyAsyncTask(this, MyAsyncTask.OBJ_GAME_DATA).execute();
}
static class MyAsyncTask extends AsyncTask<String, Integer, String> {
private int outputObjectType;
protected static final int OBJ_GAME_DATA = 0;
protected static final int OBJ_OTHER_DATA = 1;
protected static final int OBJ_DIFFERENT_DATA = 2;
protected static final int OBJ_SERVER_ERROR = 3;
MyAsyncTask(MyActivity activity, int expectedObject){
outputObjectType = expectedObject;
}
doInBackground(){
if(httpStatusCode >= 400){
outputObjectType = MyAsyncTask.OBJ_SERVER_ERROR;
}
return jsonStringFromServer;
}
onPostExecute(String json){
switch(outputObjectType){
case MyAsyncTask.OBJ_SERVER_ERROR:
serverError(json);
break;
case MyAsyncTask.OBJ_GAME_DATA:
processGameData(json);
break;
// ....
}
}
}
private void serverError(String json){
ServerError se = new Gson().fromJson(json, ServerError.class);
Log.d(TAG, se.getErrorMessage());
}
private void processGameData(String json){
GameData gd = new Gson().fromJson(json, GameData.class);
// .......
}
I think this is more less what @Pompe de velo was saying, however I am just making my a_parameter_match
based on the status code rather than something within the json.
If this is flawed, I'd love to learn why !
精彩评论