Android, parameterization of an AsyncTask with Activity function - android

I have a small problem in my own android app. I have one class that extends AsyncTask, where in onPostExecute I want to call some method of the Activity from within this task was called. But the problem is that I want three different instances (and maybe some day more) of this task, each of them I want to call different method on my Activity (but all of these methods have the same list of arguments, for now). Is there any elegant way to solve it? Or I just have to create three different classes that differ in one line - name of the calling method in onPostExecute?
I heard that in Java we cannot pass function handle as a paremeter, so it seems really hard. Can anyone help?

I think you should create interface (which contain method with needed arguments), create in Activity three inner classes implementing this interface and pass instance of appropriate class to AsyncTask via contructor.

Related

Xamarin, Android: Call just one function from another method

in my app, there are 5 classes and 1 activity. This activity has, as you all know, an OnDestroy() method. In this method I need to remove a test provider which is set up in another class called "mockingclass".
In "mockingclass" I have a method similar to this:
public void mocker()
{
xxx
location.RemoveTestProvider(location.GpsProvider);
xxx
}
While xxx stands for many other functions in this method, when the app is being destroyed I need to call ONLY for that ONE function in within this whole method.
Is there any way to do that at all? If not, what would be your suggestions?
THANKS!
Obviously you can't choose a single line from method to be executed. You need to extract it separate method which will be called separately. Maybe you should look at some injection? Let this call be injected as an delegate for example. In that way you could manipulate what should be called depending on situation.

"...MovieDetail is not an enclosing class" error on Android

I have an activity with two AsyncTasks defined. While building out a two pane tablet UI I moved a lot of the logic to a fragment class. The AsyncTasks are still in the original activity class. I am trying to instantiate and execute the tasks using the qualified names but get a ..is not an enclosing class error. I am instantiating the tasks like so:
MovieDetail.FetchTrailersTask fetchTrailersTask = new MovieDetail.FetchTrailersTask();
I've also tried getActivity.new [package_name].MovieDetail.FetchTrailersTask();
This didn't work either.
I solved this by moving the AsyncTasks to the fragment class. I don't think there was a reason to, but in the event I wanted/needed to leave them in the activity class, I couldn't find a way to do so.

Android SoftReference To Custom class Containing an AyncTask

I've just started to use SoftReference in my Fragment implementation, which sets setRetainInstance to True, and I have a question concerning..
Overview:
What I'm doing is creating a list of soft references in order to be able to have more than one AsyncTask running and still keep references.
BUT, my list keeps references to custom class objects which wrap an AsyncTask but not one themselves.
Question:
Will the behavior of SoftReference stay the same?
Will Android still "couple" my fragment and all those AsyncTask, or am I missing the
whole idea by doing this?
Code Example:
public class myFragment extends Fragment{
List<SoftReference<MyClass>> myList;
...
}
public class MyClass{
private AsyncTask task;
...
}
Edit: I changed the question to a SoftReference question after NKN's comment about WeakReference being "too weak". Thx for that..
The question still remains though:)
If I understood your idea correctly, you want to have an array of AsyncTask instances which you control. In that case, as they probably are enough critical data to store them into that SoftReference and endangering their content because of the Garbage Collector, I'd personally change the SoftReference approach to get advantage of the AsyncTask structure.
I'd declare that ArrayList but directly of MyClass instances (not SoftReferences). You can implement a method in your MyClass class like setTaskId(int), and before executing any task, you would call it with, e.g., the index in your ArrayList of that instance.
You'd then call the execute() method, and once you've terminated processing that AsyncTask, the onPostExecute() method would be called, from which you'd call a method within your Fragment to say this instance of AsyncTask has already ended, and you could simply use yourArrayList.delete(on_that_id).
In your question you mention you do this to have several AsyncTasks. You may hay as much as you want, but read this before doing it because the execute() method of AsyncTask has suffered drastical changes within version changes and you might need to adequate your code to them.
--- EDIT ---
Using AsyncTasks within Fragments has an additional complication, by the time an AsyncTask finished, precisely as you comment, it might have been detached. So you'll have to implement additional logic mechanisms to check whether it is attached via isDetached(). Keep also in mind that isDetached() only works if you detached your Fragment explicitly, otherwise you'll need isAdded().
You don't need to use it all the time, just keep in mind Fragment lifecycles and call it whenever you'd need to make an action that involves Fragments being attached and so.
To simplify it a little, you could move the AsyncTask initialization and logic to the parent activity, so if a Fragment is detached it may act properly (like, e.g., discarding the results if the fragment is no longer attached, or whatever you need).

Is this the best way to implement AsyncTask? Or are there better ways?

I am trying to write a AsyncTask generic package. Till now, what I've done is call one activity from another send the instance in the Intent to that Activity. This activity is part of the AsyncTask which calls the AsyncLoader.execute() file. I am doing this so that I don't lose any data that the parent Activity sets on the layout.
The other way to do it would be to call the Intent and return the data from the AsyncActivity to the parent Activity. But, both of these methods are slower than implementing the AsyncTask in the parent activity.
But, that clutters up the code. Thus, is there a better way of implementing it?
It sounds like your tight-coupling between the activity and the AsyncTask is causing you issues that you're trying to overcome with a weird workaround.
In my experience the best way to design activities that need an AsyncTask is:
Keep your AsyncTask out of your activity, i.e. make a separate class
that extends AsyncTask. This allows you to reuse the AsyncTask
between multiple activities and make it easier to test.
If you need to return data back to your activity, use the listener and implement the listener on your activity. Then pass your listener to a class that creates the AsyncTask.
Passing of data between intents should be kept to a minimum, if you need to reuse the same AsyncTask from a separate activity you should follow the steps above and execute the task again. If you're going to be calling this through the lifecycle of the app, then consider using a service instead.

If AsyncTask is not an inner class... - some questions

1) I don't underestand why the samples of Android almost use AsyncTasks as private inner classes. I know it is convenient to make it inner class but it makes our class file longer and hard to read. ShelvesActivity of Shelves sample application have even 845 lines. Don't you think it is a bad design or bad construction?
2) If I make my ScanStorageTask external class, what do I have to pass to it? entire Activity or only used widgets?
Example: If I must use a WebView, a Button and a ProgressBar in ScanStorageTask.
I use this:
ScanStorageTask task = new ScanStorageTask(this); // "this" is activity reference, then get the webView, button, progressBar from it.
or this:
ScanStorageTask task = new ScanStorageTask(webView, button, progressBar);
There's nothing wrong with doing it externally, and it actually might be a better design. Passing UI elements around is the kind of tight coupling that can get you into trouble when you have a really large code base anyway.
Why not do it externally and use the "listener" pattern that the UI controls employ? Make your ScanStorageTask its own class, create an OnCompleteListener interface with an onComplete method, and pass that to your ScanStorageTask instance (expose a setOnCompleteListener method or something to that effect). Then, onPostExecute can just do this:
if(onCompleteListener != null)
onCompleteListener.onComplete(data);
That way, you define your UI updates inside your activity based on the data. It's better separation of concerns and will keep your lines of code per class down, as that seems to be what you'd prefer. If you don't already have this, make a class that represents the data you need to pass in and get out, and that's what you pass in to the task as a param to the execute method and what onPostExecute passes to onComplete.
Inner classes allow you to manipulate the UI of an outer Activity inside onPreExecute(), onPostExecute() and onProgressUpdate() without passing the whole UI structure(s) to the AsyncTask. You are just able to use the activites functions for that.
This is useful since manipulating the UI isn't the main purpose of an AsyncTask. It's doing non-UI background work. And for that, what you usually have to pass is some arguments to do this job (e.g. supplying a URL to download a file).
When you declare your AsyncTask external, you basically can't access your UIs resources inside onPreExecute() (no arguments are passed to this at all), and very hard inside the other two UI functions.
I'd say AsyncTask is just made for beeing used as an inner class to do work and update the UI-thread. See the description:
AsyncTask enables proper and easy use of the UI thread. This class
allows to perform background operations and publish results on the UI
thread without having to manipulate threads and/or handlers.
(from the class documentation)
I had the same problem in may application. I wanted to establish a communitation with a PC using a Socket and I wanted my code to be reusable from several Activities/Fragments.
In the first place I tried not to use an inner class but it is very convenient when you have to update the UI so I found an alternative solution :
I created an outer AsyncTask class wich in charge to communicate with the pc and I created inner classes in each of my activites/fragments with only an override of the onPostExecute() method. this way I can reuse my code AND update the UI.
If you just want to get the result of the task and if responsiveness is not essential for your application, you can use the get() method of the AsyncTask class.
Personally I belive that if you use class only at one point, then it's most readable to also define it there - hence the anon inner class.
It does not matter. From design perspective I'd only pass data that is actually needed. However you need to be aware on one possible pitfall - when activity instance gets deactivated (hidden or orientation changed) and your background thread still runs and tries to show some changes, then you can get various errors or nothing s shown at all.

Categories

Resources