Inner AsyncTask vs AsyncTask on seperate alone class - android

This is more like an opinion and subjective question :
Which one is better, using inner class for an asynctask ?
Or,
A one on a seperate class and send it the views that need to be updated onPostExecute, and move them inside the constructor
?

I think it depends on your app architecture.
If the thread is used, for example, only within specific Activity, you can create it as an inner class.
But if you want to create something centralized, for example you want to create one class which will open thread for all http requests in the app, it is more reasonable to create separate class.

I prefer inner classes because it's easy to access to context scope (class fields or final local variables, method parameters) without passing fields values to constructors or to ASyncTask.execute(...)
Subclassing is useful when you create reusable code for example I have a ProgressBarAsyncTask wrapping create/show/progress so inner classes implement only the doInBackground where the business logic changes case by case (download, update database, call webservice)

Related

How can I access my activity's ViewModel from within a service?

I am building an app that needs to detect certain objects in photos. I first load and keep all the photos I'd like to inspect into my room Database and connect it to my view with a ViewHolder.
When the user clicks a button, I want the detection process to begin, and I want to use a jobIntentService for that (As there might be thousands of photos there).
My problem is - how do I access the view holder from within the Service? I need it both to actually get a hold of the files and also so I can update each file's record once detection has been made.
I've tried to ask for the activity as one of the attributes, but I am getting this error
Unable to instantiate service tech.levanter.anyvision.services.DetectJobIntentService: java.lang.InstantiationException: java.lang.Class<tech.levanter.anyvision.services.DetectJobIntentService> has no zero argument constructor
Would appreciate any input, thanks
ViewModels holds particular significance for Activities and Fragments (e.g. they retain data during config changes). So a Service doesn't really need it. Hence you can resolve the issue in one of two ways.
Approach 1:
If your MyViewModel is just a wrapper for accessing LiveData from your Repository class, then you can just use your Repository class inside your Service.
Approach 2:
If your ViewModel is doing more than just wrapping calls to the Repository and you want your Service class to have access to the same logic defined in your ViewModel, then use an intermediate ViewModelContent class. Instead of putting everything in your MyViewModel class, put them in a "ViewModelContent" class. Then use your MyViewModel class as an accessor wrapper around ViewModelContent. Then your Service can instantiate ViewModelContent as you would any other class.
class MyViewModel(application: Application) : AndroidViewModel(application) {
init{
viewModelContent = ViewModelContent(...)
}
}
Approach 1 will usually be cleaner than Approach 2.

Two activities access same variable

I was wondering if I have 2 activities that needs to update and access the same object . What would be the best way to do it? Should I use Application class? Or perhaps Static variable.. Etc?
Another option I can think of is putting it in a base class that both activities inherit. I will initialize the object from shared preferences during OnResume
If your object holds some kind of preference value, don't put it into a super-class. Make it static and/or use the singleton pattern and separate it from your application logic. This provides you with a more modular structure that will be easier to work with. The application class is probably overkill; singletons do the job most of the time. (The Android docs simply states: "There is normally no need to subclass Application.")
You can add it to a super-class, if it is a logical part of it though.
Don't forget to synchronize your object if it's going to be accessed by another/several thread(s).
There are different method to perform such requirement. Singleton is one of them. The other one is extending the application class. If you want a reference outlining all of these methods please see:
What's the best way to share data between activities?

Where should AsyncTask be?

I am new to android programming. I would like to get some advices about AsyncTask. I have created a main activity and one fragment in which i will display content. The use for AsyncTask in my program is to download data from internet. So, the question would be: where it should be? In the fragment's class or activity's?
You have three choices:
You can make it an inner class inside of the Fragment. This is probably OK if this asynchronous task is only specific to the fragment and you won't ever reuse it
You can make it an inner class inside of the Activity. The is better if you have one activity that controls many Fragments that may reuse the same asynchronous task.
You can make it a class of its own if you plan to reuse it in man places in your application or even if you just want it neater. If you do plan on reusing it but the places that are reusing it may need some slight differences, then you might want to abstract it to make it flexible.
Hope that helps.

Android, parameterization of an AsyncTask with Activity function

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.

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