Asynctaskloader For Http Requests To Handle Orientation Changes, Using Generics, Inheritance
Solution 1:
Ok this is what I came up with which actually seems to work pretty good and handles screen orientation changes during the background work. Here is my updated HttpAsyncTaskLoader.
publicclassHttpAsyncTaskLoader<T extendsApiResponse> extendsAsyncTaskLoader {
privateApiClient mClient ;
protectedApiRequest mRequest;
privateApiResponse mResponse;
private volatile boolean isExecuting = false;
publicHttpAsyncTaskLoader(Context context, ApiClient client, ApiRequest request) {
super(context);
mClient = client;
mRequest = request;
}
/** Subclasses should call this from loadInBackground */protectedApiResponseexecuteRequest(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 = newJSONObject(EntityUtils.toString(response.getEntity()));
Log.d(TAG, "parsed response to json");
} catch (IOException e) {
error = newResponseError(e);
} catch (URISyntaxException e) {
error = newResponseError(e);
} catch (JSONException e) {
error = newResponseError(e);
} finally {
mClient.getConnectionManager().closeExpiredConnections();
isExecuting = false;
mResponse = newApiResponse(getContext().getResources(), response, responseJson, error);
}
return mResponse;
}
protectedvoidonStartLoading() {
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)
*/publicApiResponsegetResponse() {
return mResponse;
}
@OverridepublicvoidonCanceled(Object data) {
super.onCanceled(data);
if (isExecuting) {
mClient.getConnectionManager().shutdown();
}
}
@OverridepublicApiResponseloadInBackground() {
returnexecuteRequest(mRequest);
}
}
Note that in the above example the onCanceled method takes an Object. I got compile errors if I attempted to use ApiResponse. as the type. Also, you must implement onStartLoading like I did above (calling forceLoad if the result object is null) or else loadInBackground won't get called
Then here is an example of a subclass of HttpAsyncTaskLoader:
publicclassLoginAsyncTaskLoaderextendsHttpAsyncTaskLoader {
private LoginResponse mLoginResponse;
publicLoginAsyncTaskLoader(Context context, ApiClient client, ApiRequest request) {
super(context, client, request);
}
@Overridepublic LoginResponse loadInBackground() {
ApiResponseapiResponse= executeRequest(mRequest);
mLoginResponse = newLoginResponse(apiResponse.getResources(), apiResponse.response, apiResponse.responseJson, apiResponse.getError());
return mLoginResponse;
}
@Overridepublic ApiResponse getResponse() {
return mLoginResponse;
}
}
Here is an Activity that uses this loader:
publicclassLoginActivityextendsFragmentActivityimplementsLoaderManager.LoaderCallbacks<LoginResponse> {
private String username,password;
@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stubsuper.onCreate(savedInstanceState);
setContentView(R.layout.login);
Loaderloader= getSupportLoaderManager().getLoader(0);
if (loader != null) {
getSupportLoaderManager().initLoader(0, null, this);
}
}
publicvoidloginSubmit(View button) {
Bundledata=newBundle();
data.putString("username", getUsername());
data.putString("password", getPassword());
getSupportLoaderManager().restartLoader(0, data, this);
}
@Overridepublic Loader<LoginResponse> onCreateLoader(int i, Bundle bundle) {
//might want to start a progress barApiClientclient=newApiClient();
LoginApiloginApi=newLoginApi(bundle.getString("username"), bundle.getString("password"));
returnnewLoginAsyncTaskLoader(this, apiClient, loginApi);
}
@OverridepublicvoidonLoadFinished(Loader<LoginResponse> loginLoader,
LoginResponse loginResponse)
{
//handle result, maybe send to a new activity if response doesn't have an error
}
@OverridepublicvoidonLoaderReset(Loader<LoginResponse> responseAndJsonHolderLoader)
{
//not sure if anything needs to be done here to do
}
}
Note that while this loader doesn't start until the user presses the Login button, You must reconnect to the loader using initLoader in onCreate in case it was already in progress, otherwise when you flip orientations you won't get notified that the task finished.
Interesting that this seems to work good and doesn't require using a TaskFragment. I haven't really seen anyone else do this for http stuff so maybe there are some down sides but it seems to work just fine.
Solution 2:
Are you not interested in trying to implement libraries dedicated to this kind of problems? You Have Volley by Google and Robospice for example.
http://arnab.ch/blog/2013/08/asynchronous-http-requests-in-android-using-volley/
Post a Comment for "Asynctaskloader For Http Requests To Handle Orientation Changes, Using Generics, Inheritance"