Trying to use a Loader with AsyncTask. (Android) - android

I am trying to use a Loader with an AsyncTask, however the call to execute the Loader in the DoinBackground method gives me an error: The method initLoader(int, Bundle, LoaderManager.LoaderCallbacks) in the type LoaderManager is not applicable for the arguments (int, null, LoaderClass.MagicCall)
Here is my code:
private class MagicCall extends AsyncTask<Void, Void, String> {
ProgressDialog Asycdialog = new ProgressDialog(LoaderClass.this);
#Override
protected void onPreExecute() {
Asycdialog.setMessage("Working");
Asycdialog.show();
super.onPreExecute();
}
protected String doInBackground(Void... args) {
getLoaderManager().initLoader(0, null, this);
String Z = Integer.toString(insertNameBD());
return Z;
}
#Override
protected void onPostExecute(String result) {
//hide the dialog
Asycdialog.dismiss();
t3.setText(result);
super.onPostExecute(result);
}
}

you should do like this
class FooLoader extends AsyncTaskLoader {
public FooLoader(Context context, Bundle args) {
super(context);
// do some initializations here
}
public String loadInBackground() {
String result = "";
// ...
// do long running tasks here
// ...
return result;
}
}
class FooLoaderClient implements LoaderManager.LoaderCallbacks {
Activity context;
// to be used for support library:
// FragmentActivity context2;
public Loader onCreateLoader(int id, Bundle args) {
// init loader depending on id
return new FooLoader(context, args);
}
public void onLoadFinished(Loader loader, String data) {
// ...
// update UI here
//
}
public void onLoaderReset(Loader loader) {
// ...
}
public void useLoader() {
Bundle args = new Bundle();
// ...
// fill in args
// ...
Loader loader =
context.getLoaderManager().initLoader(0, args, this);
// with support library:
// Loader loader =
// context2.getSupportLoaderManager().initLoader(0, args, this);
// call forceLoad() to start processing
loader.forceLoad();
}
}

You should not use a Loader in an AsyncTask! The answer above is correct as there is an AsynTaskLoader which extends loader and provides additional methods which override the default Loader properties.
You can extend AsynTaskLoader to provide your own implementation and control sevral other loader specific features.

Related

Getting Results Back To Main From BackgroundWorker onPostExecute

Sorry for asking this but I recently started develop android and new to Java.
Currently I am able to "Toast" onPostExecute results in "BackgroundWorkerLocation.java". What I need is to somehow pass these results back to "MainActivty.java" from where I execute this class.
MainActivity.java
String type = "get_location";
String tLatitude = String.valueOf(latitude);
String tLongitude = String.valueOf(longitude);
BackgroundWorkerLocation backgroundWorkerLocation = new BackgroundWorkerLocation(getApplicationContext());
backgroundWorkerLocation.execute(type, tLatitude, tLongitude);
// I need "Results" here
BackgroundWorkerLocation.java
public class BackgroundWorkerLocation extends AsyncTask<String,Void,String> {
Context context;
BackgroundWorkerLocation(Context ctx){
context = ctx;
}
#Override
protected String doInBackground(String... params) {
// Some background work
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Currently I am able to Toast "RESULT" here
}
#Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
You'll need to create an interface that you can use as a callback:
interface MyCallback {
void onResult(String result);
}
In your activity you create an anonymous implementation of this callback.
Pass it into your ASyncTask.
String type = "get_location";
String tLatitude = String.valueOf(latitude);
String tLongitude = String.valueOf(longitude);
BackgroundWorkerLocation backgroundWorkerLocation = new BackgroundWorkerLocation(getApplicationContext(), new MyCallback() {
#Override
public void onResult(String result) {
// I need "Results" here
}
});
backgroundWorkerLocation.execute(type, tLatitude, tLongitude);
When the ASyncTask completes, you call the "onResult" method of the callback.
public class BackgroundWorkerLocation extends AsyncTask<String,Void,String> {
Context context;
private final MyCallback myCallback;
BackgroundWorkerLocation(Context ctx, MyCallback myCallback){
context = ctx;
this.myCallback = myCallback;
}
#Override
protected String doInBackground(String... params) {
// Some background work
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Currently I am able to Toast "RESULT" here
myCallback.onResult(result);
}
}
This is how you can share data between two classes.
Note that because the callback implementation is anonymous, it has a reference to your Activity, therefore if your task lives longer than your activity it can cause a memory leak. (your next problem :-))

Refreshing a Loader without discarding previous data

I'm writing an Android application that uses an AsyncTaskLoader handled by a LoaderManager to acquire some data. The data can be modified upstream when the app is open, but as loading the data is time-consuming I check if it has been modified first.
I cache the result and the last-modified field, and my loadInBackground() method first checks if the upstream data has been modified before loading the actual data. Checking the upstream last-modified field is also time-consuming, and therefore must be done inside the AsyncTaskLoader, not on the UI thread.
public class DataActivity extends Activity implements LoaderManager.LoaderCallbacks<LoadedData> {
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
getLoaderManager().initLoader(0, null, this);
}
private void reloadData() { // called from various locations
getLoaderManager().restartLoader(0, null, this);
}
#Override
public Loader<LoadedData> onCreateLoader(int i, Bundle bundle) {
return new DataLoader(this);
}
#Override
public void onLoadFinished(Loader<LoadedData> loader, LoadedData result) {
setActivityLoadingState(false);
updateShownData(result);
}
#Override
public void onLoaderReset(Loader<LoadedData> loader) {}
private static class DataLoader extends AsyncTaskLoader<LoadedData> {
private LoadedData lastData;
private int lastModified = -1;
GameListLoader(DataActivity activity) {
super(activity);
}
#Override
public LoadedData loadInBackground() {
int currentModified = getUpstreamLastModified();
if (currentModified == lastModified)
return lastData;
LoadedData currentData = getUpstreamData();
lastData = currentData;
lastModified = currentModified;
return currentData;
}
#Override
protected void onStartLoading() {
forceLoad();
setActivityLoadingState(true);
}
}
}
Now, I noticed that the LoaderManager.restartLoader method creates a new Loader every time, which discards my cache entirely, and loads the data every time.
Is there a way to ask the AsyncTaskLoader to refresh (i.e. call its startLoading, as I have onStartLoading calling forceLoad) from the LoaderManager? Or should I not be using LoaderManager or AsyncTaskLoader at all?

async task does not work properly

Hi i have a function to get users from website database
my function
private void get_users() {
try {
url = "my address";
dbGetData3 = new DbGetData();
new Thread(new Runnable() {
public void run() {
data = dbGetData3.getDataFromDB(url);
runOnUiThread(new Runnable() {
#Override
public void run() {
userha = parseJSON3(data);
}
});
}
}).start();
Toast.makeText(context, "please wait ", Toast.LENGTH_LONG)
.show();
} catch (Exception e) {
toast(9);
}
Now i want add a loading progress bar while fetch data finished.
I use AsyncTask like this:
private class LongOperation extends AsyncTask<String, Void, String> {
protected void onPreExecute() {
progressDialog = new ProgressDialog(Login.this);
progressDialog.setTitle("Processing...");
progressDialog.setMessage("Please wait...");
progressDialog.setCancelable(true);
progressDialog.show();
}
protected String doInBackground(String... params) {
try {
get_users();
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(String result) {
progressDialog.dismiss();
}
}
and i use this code for excute
mytask = new LongOperation();
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB)
mytask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
else
mytask.execute();
imageView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
onCreate(savedInstanceState);
}
});
but progress dialog dose not show for me (get user worked)
i change my code like this:
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB){
mytask.onPreExecute();
mytask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
else
{
mytask.onPreExecute();
mytask.execute();
}
then my progress dialog allways show
i test other code in stackoverflow like
AsyncTask doInBackground does not run
AsyncTask called from Handler will not execute doInBackground
Android SDK AsyncTask doInBackground not running (subclass)
but that not work for me
please help me tankyou
Consdier using a LoaderManager and an AsyncTaskLoader for this sort of stuff.
AsyncTasks are a pain in the ass as because you have to manage their lifecycle with screen-rotations etc. With a LoaderManager all of that is in the past.
Below is an example of a loader which loads a list of "items".
public class ItemsLoader extends AsyncTaskLoader<List<Item>> {
private static final String TAG = "ItemsLoader";
private List<Item> mItems;
private ItemUpdatedReceiver mObserver;
private int mSomeParam;
public static class ItemUpdatedReceiver extends BroadcastReceiver {
private static final String TAG = "ItemLoader";
final ItemsLoader mLoader;
public ItemUpdatedReceiver(ItemsLoader mLoader) {
this.mLoader = mLoader;
// listen for changes to the account we're using
IntentFilter filter = new IntentFilter(GlobalConstants.ACTION_ITEMS_UPDATED);
LocalBroadcastManager.getInstance(mLoader.getContext()).registerReceiver(this, filter);
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (GlobalConstants.ACTION_ITEMS_UPDATED.equals(action)) {
mLoader.onContentChanged();
}
}
}
public void setSomeParam(int someParam){
mSomeParam = someParam;
onContentChanged();
}
public ItemsLoader(Context context, int someParam) {
super(context);
mSomeParam = someParam;
onContentChanged();
}
#Override
public List<Item> loadInBackground() {
// do whatever you need to do here
ArrayList<Item> Items = new ArrayList<>();
return Items;
}
/**
* Called when there is new data to deliever to the client.
*
* #param data
*/
#Override
public void deliverResult(List<Item> data) {
if (isReset()) {
// an async query came in while the loader is stopped, we don't need the result
//release resources if needed
onReleaseResources(data);
}
List<Item> oldItems = mItems;
mItems = data;
if (isStarted()) {
// If the Loader is currently started, we can immediately
// deliver its results.
super.deliverResult(mItems);
}
// At this point we can release the resources associated with
// 'oldApps' if needed; now that the new result is delivered we
// know that it is no longer in use.
if (oldItems != null) {
onReleaseResources(oldItems);
}
}
#Override
protected void onStartLoading() {
super.onStartLoading();
if (mItems != null) {
// If we currently have a result available, deliver it
// immediately.
deliverResult(mItems);
}
// start listening for changes
if (mObserver == null) {
mObserver = new ItemUpdatedReceiver(this);
}
if (takeContentChanged() || mItems == null) {
// If the data has changed since the last time it was loaded
// or is not currently available, start a load.
forceLoad();
}
}
/**
* Handles a request to stop the Loader.
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
/**
* Handles a request to cancel a load.
*/
#Override
public void onCanceled(List<Item> items) {
super.onCanceled(items);
// At this point we can release the resources associated with 'profile'
// if needed.
onReleaseResources(items);
}
#Override
protected void onReset() {
super.onReset();
// Ensure the laoder is stopped
onStopLoading();
// At this point we can release the resources if needed.
if (mItems != null) {
onReleaseResources(mItems);
mItems = null;
}
// Stop monitoring for changes.
if (mObserver != null) {
LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(mObserver);
mObserver = null;
}
}
/**
* Helper function to take care of releasing resources associated
* with an actively loaded data set.
*/
private void onReleaseResources(List<Item> data) {
// For a simple List<> there is nothing to do. For something
// like a Cursor, we would close it here.
}
}
To use this class, in your activity you must extend LoaderManager.LoaderCallbacks> and override the methods:
public Loader<List<Item>> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created. This
// sample only has one Loader, so we don't care about the ID.
// start the loading dialog here
return new ItemsLoader(context);
}
public void onLoadFinished(Loader<List<Item>> loader, List<Item>data) {
// do something with your data, hide the progress dialog
}
public void onLoaderReset(Loader<Cursor> loader) {
// set the old data to null
}
To actually start loading:
getLoaderManager().initLoader(LOADER_ID, null, this);

What is the best way to use a fragment with httpconnection?

I'm doing the refactoring of an application that uses AsyncTask to make HTTP calls to a web service.
Now use a simple Activity, at the moment when I needs to invoke the service using a AsyncTask in this way:
private class MyAsyncTask extends AsyncTask {<String, Void, Boolean>
private ProgressDialog progressDialog;
private xmlHandler handler;
# Override
protected void OnPreExecute () {
progressDialog = new ProgressDialog (home.This);
progressDialog
. SetMessage (getString (R.string.home_loadinfo_attendere));
progressDialog.setCancelable (false);
progressDialog.show ();
}
# Override
protected Boolean doInBackground (String... params) {
try {
xmlHandler handler = new XmlHandler();
return Service
. GetInstance ()
. CallService (
ServiceType.GETINFO,
Home.This, handler, null);
} Catch (Exception e) {
e.printStackTrace ();
return false;
}
}
# Override
protected void OnPostExecute (Boolean success) {
progressDialog.dismiss ();
String message = null;
if (success | | (handler == null))
message = getString (R.string.server_result_msg500);
else {
switch (handler.getStatusCode ()) {
case 200:
doStuffWithHandler(handler);
return;
case 500:
message = getString (R.string.server_result_msg500);
break;
case 520:
message = getString (R.string.server_result_msg520);
break;
default:
message = getString (R.string.server_result_msg500);
break;
}
}
if (message! = null) {
AlertDialog.Builder builder = new AlertDialog.Builder (home.This);
builder.setTitle (R.string.home_loadinfo_error_title)
. SetMessage (message)
. SetCancelable (true)
. SetNegativeButton (R.string.close_title,
new DialogInterface.OnClickListener () {
# Override
public void onClick (DialogInterface dialog,
int id) {
dialog.cancel ();
}
});
AlertDialog alert = builder.create ();
Alert.show ();
}
}
}
doStuffWithHandler(handler){
// populate interface with data from service
}
I want to do the same but using Android compatibility libraries and FragmentActivity. I read a little about loader but I did not understand how I could use them in this same way, Could you please tell me if this is the right way (FragmentActivity, Fragment and Loader) and how to implement it also addresses giving me examples?
You could create a Loader, something like this:
public abstract class MyLoader extends AsyncTaskLoader<String> {
public MyLoader(Context context) {
super(context);
}
private String result;
protected String error;
#Override
public final String loadInBackground() {
try {
error = null;
// Load your data from the server using HTTP
...
result = ...
...
return result;
}
catch (Exception e) {
Logger.e("ResourceLoader", "Loading resource failed.", e);
error = e.getMessage();
}
return null;
}
#Override
protected void onStartLoading() {
if (!TextUtils.isEmpty(error)) {
deliverResult(result);
}
if (takeContentChanged()) {
forceLoad();
}
}
#Override
public void deliverResult(String data) {
if (isReset()) {
return;
}
result = data;
if (isStarted()) {
try {
super.deliverResult(data);
}
catch(Exception e) {
Log.e("ResourceLoader", "Caught exception while delivering result.", e);
}
}
}
public String getError() {
return error;
}
}
In your Fragment, you can initialize this loader:
public class MyLoaderFragment extends Fragment implements LoaderCallbacks<String> {
....
....
String message;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
....
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getLoaderManager().initLoader(0, getArguments(), this);
}
#Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new MyLoader(getActivity());
}
#Override
public void onLoadFinished(Loader<String> loader, String result) {
// Here you have the result in 'result'.
message = result;
...
}
....
}
And instead of just returning a simple 'String' result, you can return any object you like. Just adjust the MyLoader and LoaderCallbacks implementation accordingly.
You can use Asynctask in Fragment exactly as you did in your Activity, few things change, like:
progressDialog = new ProgressDialog (home.This);
change to:
progressDialog = new ProgressDialog (getApplication());
return Service
. GetInstance ()
. CallService (
ServiceType.GETINFO,
Home.This, handler, null);
change to:
return Service
. GetInstance ()
. CallService (
ServiceType.GETINFO,
getApplication(), handler, null);
Anything special to implements Asynctask in Fragment.
I think you need to read more about Fragment itself.

Passing parameters to Asynctask

I am using Async tasks to get string from the menu activity and load up some stuff..but i am
not able to do so..Am i using it in the right way and am i passing the parameters correctly?
Please see the code snippet. thanks
private class Setup extends AsyncTask<Void, Integer, Void> {
#Override
protected Void doInBackground(Void... params) {
try {
if (!(getIntent().getExtras().isEmpty())) {
Bundle gotid = getIntent().getExtras();
identifier = gotid.getString("key");
}
} catch (Exception e) {
e.getStackTrace();
} finally {
if (identifier.matches("abc")) {
publishProgress(0);
db.insert_fri();
} else if ((identifier.matches("xyz"))) {
publishProgress(1);
db.insert_met();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... i) {
// start the song here
if (i[0] == 0) {
song.setLooping(true);
song.start();
}
}
#Override
protected void onPostExecute(Void res) {
}
#Override
protected void onPreExecute() {
// do something before execution
}
}
Avoid adding a constructor.
Simply pass your paramters in the task execute method
new BackgroundTask().execute(a, b, c); // can have any number of params
Now your background class should look like this
public class BackgroundTask extends AsyncTask<String, Integer, Long> {
#Override
protected Long doInBackground(String... arg0) {
// TODO Auto-generated method stub
String a = arg0[0];
String b = arg0[1];
String c = arg0[2];
//Do the heavy task with a,b,c
return null;
}
//you can keep other methods as well postExecute , preExecute, etc
}
Instead of this i would do
private class Setup extends AsyncTask<String, Integer, Void> {
#Override
protected Void doInBackground(String... params) {
String identifier = params[0];
if (identifier.matches("abc")) {
publishProgress(0);
db.insert_fri();
} else if ((identifier.matches("xyz"))) {
publishProgress(1);
db.insert_met();
}
}
return null;
}
#Override
protected void onProgressUpdate(Integer... i) {
// start the song here
if (i[0] == 0) {
song.setLooping(true);
song.start();
}
}
#Override
protected void onPostExecute(Void res) {
}
#Override
protected void onPreExecute() {
// do something before execution
}
}
and check for "identifier" before invoking the asynctask to prevent overhead of creating a AsyncTask
like this
if (!(getIntent().getExtras().isEmpty())) {
Bundle gotid = getIntent().getExtras();
identifier = gotid.getString("key");
new Setup().execute(identifier);
}
A simple way is to add a constructor:
public Setup(String a, Int b) {
this.a = a;
this.b = b;
}
AsyncTask means doInBackground() returns Void, onProgressUpdate() takes Integer params and doInbackground takes... String params !
So you don't need (and REALLY shouldn't) use Intent, since it is meant to be used for passing arguments through Activities, not Threads.
And as told before, you can make a constructor and a global parameter to your class called "identifier"
public class Setup...
{
private String identifier;
public Setup(String a) {
identifier = a;
}
}
Hoped it could help.
Regards

Categories

Resources