Ответ 1
Хорошо, это то, что я придумал, с которым на самом деле работает очень хорошо, и обрабатывает изменения ориентации экрана во время фоновой работы. Вот мой обновленный HttpAsyncTaskLoader.
public class HttpAsyncTaskLoader<T extends ApiResponse> extends AsyncTaskLoader {
private ApiClient mClient ;
protected ApiRequest mRequest;
private ApiResponse mResponse;
private volatile boolean isExecuting = false;
public HttpAsyncTaskLoader(Context context, ApiClient client, ApiRequest request) {
super(context);
mClient = client;
mRequest = request;
}
/** Subclasses should call this from loadInBackground */
protected ApiResponse executeRequest(ApiRequest request) {
HttpResponse response = null;
ResponseError error = null;
JSONObject responseJson = null;
try {
isExecuting = true;
Log.d(TAG, "executing api");
response = mClient.execute(request);
Log.d(TAG, "got a response");
isExecuting = false;
responseJson = new JSONObject(EntityUtils.toString(response.getEntity()));
Log.d(TAG, "parsed response to json");
} catch (IOException e) {
error = new ResponseError(e);
} catch (URISyntaxException e) {
error = new ResponseError(e);
} catch (JSONException e) {
error = new ResponseError(e);
} finally {
mClient.getConnectionManager().closeExpiredConnections();
isExecuting = false;
mResponse = new ApiResponse(getContext().getResources(), response, responseJson, error);
}
return mResponse;
}
protected void onStartLoading() {
super.onStartLoading();
if (takeContentChanged() || mResponse == null) {
forceLoad();
}
if (getResponse() != null) {
deliverResult(getResponse());
}
}
/**
* Subclasses should also override this so the correct object
* gets delivered in all cases (see onStartLoading above)
*/
public ApiResponse getResponse() {
return mResponse;
}
@Override
public void onCanceled(Object data) {
super.onCanceled(data);
if (isExecuting) {
mClient.getConnectionManager().shutdown();
}
}
@Override
public ApiResponse loadInBackground() {
return executeRequest(mRequest);
}
}
Обратите внимание, что в приведенном выше примере метод onCanceled принимает объект. Я получил ошибки компиляции, если попытался использовать ApiResponse. как тип. Кроме того, вы должны реализовать onStartLoading, как я сделал выше (вызов forceLoad, если объект result равен null), иначе loadInBackground не получит вызов
Затем приведен пример подкласса HttpAsyncTaskLoader:
public class LoginAsyncTaskLoader extends HttpAsyncTaskLoader {
private LoginResponse mLoginResponse;
public LoginAsyncTaskLoader(Context context, ApiClient client, ApiRequest request) {
super(context, client, request);
}
@Override
public LoginResponse loadInBackground() {
ApiResponse apiResponse = executeRequest(mRequest);
mLoginResponse = new LoginResponse(apiResponse.getResources(), apiResponse.response, apiResponse.responseJson, apiResponse.getError());
return mLoginResponse;
}
@Override
public ApiResponse getResponse() {
return mLoginResponse;
}
}
Вот активность, которая использует этот загрузчик:
public class LoginActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<LoginResponse> {
private String username,password;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.login);
Loader loader = getSupportLoaderManager().getLoader(0);
if (loader != null) {
getSupportLoaderManager().initLoader(0, null, this);
}
}
public void loginSubmit(View button) {
Bundle data = new Bundle();
data.putString("username", getUsername());
data.putString("password", getPassword());
getSupportLoaderManager().restartLoader(0, data, this);
}
@Override
public Loader<LoginResponse> onCreateLoader(int i, Bundle bundle) {
//might want to start a progress bar
ApiClient client = new ApiClient();
LoginApi loginApi = new LoginApi(bundle.getString("username"), bundle.getString("password"));
return new LoginAsyncTaskLoader(this, apiClient, loginApi);
}
@Override
public void onLoadFinished(Loader<LoginResponse> loginLoader,
LoginResponse loginResponse)
{
//handle result, maybe send to a new activity if response doesn't have an error
}
@Override
public void onLoaderReset(Loader<LoginResponse> responseAndJsonHolderLoader)
{
//not sure if anything needs to be done here to do
}
}
Обратите внимание, что пока этот загрузчик не запускается до тех пор, пока пользователь не нажмет кнопку входа в систему, вы должны подключиться к загрузчику с помощью initLoader в onCreate в случае, если он уже выполняется, иначе, когда вы перевернете ориентацию, вы не получите уведомление о том, что задача завершена.
Интересно, что это работает хорошо и не требует использования TaskFragment. Я действительно не видел, чтобы кто-то еще делал это для http-материала, поэтому, возможно, есть некоторые стороны, но, похоже, все работает нормально.