Тестирование 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
метод.