Тестирование Android - Как синхронизировать AsyncTask

Я делаю простое приложение Venues с API Foursquare. В Activity у меня есть кнопка, которая при щелчке делает HTTP GET в AsyncTask к сервису, чтобы занять трендовые места вокруг текущего местоположения пользователя. Если GET завершается успешно, в действие добавляется фрагмент, содержащий ListView с результатом.

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

Вот код:

public void testBtnFindVenues_clickShouldInstantiateVenueListFragment() {
    TouchUtils.clickView(this, this.btnFindVenues);
    assertNotNull("VenueListFragment is null", this.getVenueListFragment());
}

private Fragment getVenueListFragment() {
    FragmentManager fragmentManager = this.activity
            .getSupportFragmentManager();
    VenueListFragment venueListFragment = (VenueListFragment) fragmentManager
            .findFragmentByTag(this.activity
                    .getString(R.string.fragment_tag_venue_list));

    return venueListFragment;
}

Как я могу сделать утверждение быть выполненным после выполнения AsyncTask

РЕДАКТИРОВАТЬ: вот AsyncTask

protected class HttpGetJsonTask extends AsyncTask<Void, Void, ResponsePair> {
    private String requestUrl;
    private IOnSuccess onSuccess;
    private IOnError onError;

    public HttpGetJsonTask(String requestUrl) {
        this.requestUrl = requestUrl;
    }

    public void setOnSuccess(IOnSuccess onSuccess) {
        this.onSuccess = onSuccess;
    }

    public void setOnError(IOnError onError) {
        this.onError = onError;
    }

    @Override
    protected ResponsePair doInBackground(Void... params) {
        HttpClient client = new DefaultHttpClient();
        HttpGet get = new HttpGet(this.requestUrl);
        get.addHeader("content-type", "application/json");

        ResponsePair responsePair = new ResponsePair();

        try {
            HttpResponse response = client.execute(get);
            String jsonData = HttpRequester.this
                    .getResponseContentAsString(response);
            int statusCode = response.getStatusLine().getStatusCode();

            responsePair.setJsonData(jsonData);
            responsePair.setStatusCode(statusCode);

            return responsePair;
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return responsePair;
    }

    @Override
    protected void onPostExecute(ResponsePair responsePair) {
        super.onPostExecute(responsePair);

        HttpRequester.this.executeEvents(this.onSuccess, this.onError,
                responsePair);
    }
}

private void executeEvents(IOnSuccess onSuccess, IOnError onError,
        ResponsePair responsePair) {
    String jsonData = responsePair.getJsonData();
    int statusCode = responsePair.getStatusCode();

    if (statusCode / 100 == 4 || statusCode / 100 == 5 || statusCode == 0) {
        onError.performAction(jsonData);
    } else {
        onSuccess.performAction(jsonData);
    }
}

private String getResponseContentAsString(HttpResponse response) {
    String stringContent = null;
    InputStream inputStream = null;
    InputStreamReader reader = null;
    BufferedReader bufferedReader = null;

    try {
        inputStream = response.getEntity().getContent();
        reader = new InputStreamReader(inputStream);
        bufferedReader = new BufferedReader(reader);

        StringBuilder stringContentBuilder = new StringBuilder();
        String line = bufferedReader.readLine();

        while (line != null) {
            stringContentBuilder.append(line);
            line = bufferedReader.readLine();
        }

        stringContent = stringContentBuilder.toString();
    } catch (IOException ex) {
        ex.printStackTrace();
    } finally {
        try {
            bufferedReader.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    return stringContent;
}

Вот настройка для кнопки и транзакции VenueListFragment

private void setUpBtnFindVenues() {
    this.btnFindVenues = (Button) this.findViewById(R.id.btn_findVenues);
    this.btnFindVenues.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View v) {
            if (!NetworkUtils
                    .isNetworkConnectionEnabled(VenueListActivity.this)) {
                MessageNotifier.displayMessage(VenueListActivity.this,
                        R.string.toast_network_connection_not_found);

                return;
            }

            IOnSuccess onSuccess = new IOnSuccess() {
                @Override
                public void performAction(String data) {
                    int index = data.indexOf("{\"venues\"");

                    data = data.substring(index, data.length() - 1);
                    Gson gson = new Gson();
                    ResponseModel response = gson.fromJson(data,
                            ResponseModel.class);
                    VenueListActivity.this.venues = response.getVenues();

                    if (VenueListActivity.this.venues.size() == 0) {
                        MessageNotifier.displayMessage(
                                VenueListActivity.this,
                                R.string.toast_not_venues_within_radius);
                    }

                    VenueListActivity.this
                            .setUpVenueList(VenueListActivity.this.venues);
                }
            };

            IOnError onError = new IOnError() {
                @Override
                public void performAction(String data) {
                    MessageNotifier.displayMessage(VenueListActivity.this,
                            R.string.toast_problem_on_server);
                }
            };

            // Get the user's location
            Location location = VenueListActivity.this.locationTracker
                    .getLocation();

            if (location == null) {
                MessageNotifier.displayMessage(VenueListActivity.this,
                        R.string.toast_location_not_found);
            } else {
                // Build the route parameters HashMap
                Map<String, String> routeParams = new HashMap<String, String>();
                double latitude = location.getLatitude();
                double longitude = location.getLongitude();

                Log.d("denis", "Latitude: " + Double.toString(latitude));
                Log.d("denis", "Longitude: " + Double.toString(longitude));
                routeParams.put("ll",
                        String.format("%s,%s", latitude, longitude));

                int radius = (VenueListActivity.this.seekBarRadius
                        .getProgress() + MIN_RADIUS) * SEEK_BAR_PROGRESS_MULTIPLIER;
                routeParams.put("radius", Integer.toString(radius));

                AppUtils.getData().venues()
                        .getTrendingVenues(routeParams, onSuccess, onError);
            }
        }
    });
}

private void setUpVenueList(List<VenueModel> venues) {
    Gson gson = new Gson();

    Bundle arguments = new Bundle();
    arguments.putBoolean(BundleKey.IS_TWO_PANE, this.isTwoPane);
    arguments.putString(BundleKey.VENUES, gson.toJson(venues));

    VenueListFragment fragment = new VenueListFragment();
    fragment.setArguments(arguments);

    FragmentManager fragmentManager = this.getSupportFragmentManager();
    FragmentTransaction transaction = fragmentManager.beginTransaction();

    transaction.replace(R.id.frameLayout_venueListContainer, fragment,
            this.getString(R.string.fragment_tag_venue_list));

    transaction.commit();
}

Вот метод в DataUnitOfWork

public void getTrendingVenues(Map<String, String> routeParams,
        IOnSuccess onSuccess, IOnError onError) {
    if (!routeParams.containsKey("ll")) {
        throw new IllegalArgumentException("The routeParams Map does not contain the \"ll\" route parameter (it is required)");
    }

    StringBuilder urlBuilder = new StringBuilder();
    urlBuilder.append(this.rootUrl);
    urlBuilder.append(String.format("%s%s", "trending", MainPersister.CLIENT_ROUTE_PARAMS));

    Set<String> keys = routeParams.keySet();
    for (String key : keys) {
        urlBuilder.append(String.format("&%s=%s", key, routeParams.get(key)));
    }

    HttpGetJsonTask get = new HttpGetJsonTask(urlBuilder.toString());
    get.setOnSuccess(onSuccess);
    get.setOnError(onError);

    get.execute();
}

1 ответ

doInBackground работает на другом потоке, но onPostExecute работает в вызывающем потоке. Убедитесь, что код, который заполняет пользовательский интерфейс после AsyncTask делается в onPostExecute метод.

Другие вопросы по тегам