Как вернуть разные объекты через Asynctask в Android - PullRequest
3 голосов
/ 11 августа 2011

Я подумал, что это, должно быть, общий вопрос, но я неожиданно не смог найти ответ, поэтому, возможно, вся моя структура ужасна ...

У меня есть действие, которое загружает значения / состояния игры из веб-службы через AsyncTask. Эти значения используются для обновления пользовательского представления.

После создания представления различные события из представления запускают AsyncTask для загрузки другой информации.

Это функционально, но проблема в том, что теперь у меня есть полдюжины классов AsyncTask в упражнении с почти идентичным кодом. Единственное отличие - это тип возвращаемого объекта (который основан на json из веб-службы) и метод, который вызывается из onPostExecute().

Как я могу использовать только два AsyncTask (один для post и один для get), не зная, какой тип объекта json будет возвращен веб-сервисом?

Аналогичным образом, как я могу определить тип объекта, возвращаемого веб-службой? При возникновении проблемы веб-служба возвращает строку json, соответствующую объекту ErrorMessage, а не (например) объекту GameData.

Должен ли я как-то использовать switch и instanceof в onPostExecute()? Возможно, обратные вызовы?

Ответы [ 2 ]

2 голосов
/ 11 августа 2011

Вы можете использовать абстрактный базовый класс, который расширяет ваши родственные классы.

Пример кода:

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;
    }
}

и, например, используйте его так:

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.
    }
} 

Это только из головы. Я не мог относиться к вашей конкретной проблеме, хотя идей здесь должно быть достаточно, чтобы вы начали работать над своей новой структурой.

1 голос
/ 12 августа 2011

Это слишком долго для комментария, поэтому я пишу ответ. Однако это был совет @Pompe de velo, который заставил меня пойти по этому пути, поэтому я принимаю этот ответ. Я также пропустил некоторую информацию из моего вопроса, которая могла бы быть полезной.

Во всяком случае, на данный момент я не вижу каких-либо серьезных недостатков в этом подходе, но время (или, возможно, другой пользователь SO;]) покажет ...

По сути, я назначил константу для каждого типа объекта, который будет пытаться получить действие. Часть, которую я пропустил, заключалась в том, что сервер возвращает объект ошибки только с кодом состояния 4xx-5xx http. Другими словами, я уверен, что получу ожидаемый объект или объект ошибки, и я могу определить, что я получил из кода состояния. Затем switch отправляет фактическую строку json соответствующему методу, который может манипулировать ответом по мере необходимости.

Упрощенный псевдокод ...

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);
    // .......
}

Я думаю, что это гораздо меньше того, что говорил @Pompe de velo, однако я просто делаю свой a_parameter_match на основе кода состояния, а не чего-то внутри json.

Если это ошибочно, я хотел бы узнать, почему!

...