Android Loader vs AsyncTask on button click
I have an activity that does not require data from the server on boot - just a simple init for the ui
The user interface has several buttons.
The user clicks on one of them, and the application sends a request to the server (call rest) While the request is being processed, the counter shows (about 10 seconds)
It currently uses AsyncTask - so if the app changes portrait to album - the activity restarts and I lose the process
The second option is to use a Loader - the problem is that it starts when the button is pressed - not when the activity starts
This leads to many exceptions - when the LoaderManager dispatches events to an unloaded element
Is there any solution?
a few comments: - 10 seconds for example - blocking the user to one orientation is not an option - the service is overkill for a simple rest call
source to share
public class TestActivity extends FragmentActivity {
private Button one;
private Button two;
private final int ONE_ID = 0;
private final int TWO_ID = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
one = (Button) findViewById(R.id.one);
two = (Button) findViewById(R.id.two);
one.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getLoaderManager().restartLoader(ONE_ID, null, callbacks);
}
});
two.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
getLoaderManager().restartLoader(ONE_ID, null, callbacks);
}
});
Loader<AsyncTaskLoaderResult<Result>> loader = getLoaderManager().getLoader(ONE_ID);
if (loader != null) {
getLoaderManager().initLoader(ONE_ID, null, callbacks);
}
loader = getLoaderManager().getLoader(TWO_ID);
if (loader != null) {
getLoaderManager().initLoader(TWO_ID, null, callbacks);
}
}
public static class AsyncTaskLoaderResult<E> {
public E data;
public Bundle args;
}
public static class Result {
}
private LoaderManager.LoaderCallbacks<AsyncTaskLoaderResult<Result>> callbacks = new LoaderManager.LoaderCallbacks<AsyncTaskLoaderResult<Result>>() {
@Override
public Loader<AsyncTaskLoaderResult<Result>> onCreateLoader(int id, Bundle args) {
/**
* according different Id, create different AsyncTaskLoader
*/
switch (id) {
case ONE_ID:
return new OneAsyncTaskLoader(TestActivity.this);
case TWO_ID:
return new TwoAsyncTaskLoader(TestActivity.this);
}
return null;
}
@Override
public void onLoadFinished(Loader<AsyncTaskLoaderResult<Result>> loader, AsyncTaskLoaderResult<Result> data) {
/**
* handle result
*/
switch (loader.getId()) {
}
getLoaderManager().destroyLoader(loader.getId());
}
@Override
public void onLoaderReset(Loader<AsyncTaskLoaderResult<Result>> loader) {
}
};
public static class OneAsyncTaskLoader extends AsyncTaskLoader<AsyncTaskLoaderResult<Result>> {
private AsyncTaskLoaderResult<Result> result;
public OneAsyncTaskLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
super.onStartLoading();
if (result != null) {
deliverResult(result);
} else {
forceLoad();
}
}
@Override
public AsyncTaskLoaderResult<Result> loadInBackground() {
/**
* send request to server
*/
result = new AsyncTaskLoaderResult<Result>();
result.data = null; // result.data comes from server response
return result;
}
}
public static class TwoAsyncTaskLoader extends AsyncTaskLoader<AsyncTaskLoaderResult<Result>> {
private AsyncTaskLoaderResult<Result> result;
public TwoAsyncTaskLoader(Context context) {
super(context);
}
@Override
protected void onStartLoading() {
super.onStartLoading();
if (result != null) {
deliverResult(result);
} else {
forceLoad();
}
}
@Override
public AsyncTaskLoaderResult<Result> loadInBackground() {
/**
* send request to server
*/
result = new AsyncTaskLoaderResult<Result>();
result.data = null; // result.data comes from server response
return result;
}
}
}
source to share
First, you can fix the orientation change issue by declaring
android:configChanges="orientation"
But the real problem is that the user looks at the counter for 10 seconds. Most users won't be patient enough for this. I donβt know what your application does, so itβs difficult to give an exact suggestion, but I can say that you need to do your web content in AsyncTask
, but let the user do other things.
You can allow the user to do other things while AsyncTask
completing or putting this code in [Service ( http://developer.android.com/guide/components/services.html ). Anyway, don't force your users to look at screen for 10 seconds of rotation ... they won't be YOUR users for a long time
source to share
If you use AsyncTask
to do this, you can use Service
or use onRetainNonConfigurationInstance instead or Fragment.setRetainInstance
to allow the AsyncTask
configuration changes to live.
Or disable config changes: I've used this in the past with some success.
source to share
Here's a good article on the topic:
http://www.javacodegeeks.com/2013/01/android-loaders-versus-asynctask.html
Anyway, as @codeMagic mentioned, AsyncTask
s android:configChanges="orientation|screenSize"
should be enough for you (it prevents the activity from being recreated when the config changes)
source to share