I have typical AsyncTask that I want to properly decouple from my Activity classes and UI logic.
I think of doing it this way:
Make listener interface
public interface MyTaskListener {
void onTaskProgress(...);
void onTaskDone(...);
}
Make my Activity implement MyTaskListener and pass this reference on task creation.
Call listener methods inonPreExecute(), onProgressUpdate() and onPostExecute().
But may be I'm reinvetning the wheel and Android framework has something better already implemented? I think of something like EventBus pattern where all interested parties can register for particular event types that I can fire from my AsyncTask.
The interface is most clean way of doing this, because your task class is 'sealed', knows nothing about surrounding environment (does not access any stuff from outer class which quite tempting when you use inner classes) and communicates back with generic channel.
Related
In my old app, this is the way how I perform time-consuming I/O operations in AppWidgetProvider's onUpdate function.
public class MyAppWidgetProvider extends AppWidgetProvider {
private static ExecutorService thread_executor = java.util.concurrent.Executors.newFixedThreadPool(1);
#Override
public void onUpdate(
Runnable runnable = ...
thread_executor.execute(runnable);
I don't think that is a good way, especially comes to Android 8.
I like LiveData concept, as we need not handling threading explicitly. Yet, it enables us to perform time-consuming operation, without blocking Main thread.
I was wondering, is it possible to use LiveData, and attach an Observer to perform time-consuming I/O operation (Like reading from SQLite database), within AppWidgetProvider?
I'm not really sure how to do that, as I have no idea how I can get an LifecycleOwner in AppWidgetProvider, to observe LiveData.
Yes, it is possible for you to use LiveData from within an AppWidgetProvider. There are two ways (that I know) for you to get a LifecycleOwner:
You can call ProcessLifecycleOwner.get().
You can replicate the example from this answer.
Both methods work, it's up to you to choose which one you want to use.
BUT:
You don't need a LifecycleOwner, you can use liveData.observeForever(Observer). In fact, it might introduce some bugs if you use a LifecycleOwner: When the owner moves to the DESTROYED state, your observer won't be called 1.
You shouldn't forget to call liveData.removeObserver(Observer).
I'm try to use event bus lib, I could not understand it's functionality and see multiple examples. Is it use only services class or use activity and fragment then is use activity what situation we use event bus in activity or fragment.
Instead of interface we can simply use EventBus .we can pass messages from one class to one or more classes. EventBus in 3 steps
Define
Register and unregister
Post Event
Define events:
public static class MessageEvent { /* your getter and setter */ }
Prepare subscribers: Declare and annotate your subscribing method, optionally specify a thread mode:
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(MessageEvent event) {
/* event fire here when you post event from other class or fragment */
};
Register and unregister your subscriber. For example on Android, activities and fragments should usually register according to their life cycle:
#Override
public void onStart() {
super.onStart();
EventBus.getDefault().register(this);//Register
}
unRegister
#Override
public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this);//unregister
}
Post events:
EventBus.getDefault().post(new MessageEvent());//post event
You can consider EventBus as a lightweight communication channel for passing data within activities, or services, or fragments or between any of them.
Think of EventBus as an underlying layer in your app which is independent of any active activities or services or fragments and their lifecycle.
The main concept on which an EventBus works is that you subscribe to events in either an activity or fragment or service or any components like that and whenever the EventBus has a specific event of the type you subscribed, it notifies your subscribed method in that component and you can perform any task there based on the event that you have received.
Triggering an event is easy and you can do it from any area of your app by just passing a specific event (which is basically a POJO class, let's say MyEvent) to the EventBus, and the bus will handle the rest and correctly deliver it to the appropriate receiver/s.
I would recommend you to try out EventBus 3 from GreenRobot, and go through their documentation here to incorporate their library n your code. I have been using the same without any problems.
EventBus 3 by GreenRobot
Hope this helps.
Mostly you shouldn't. In general its a hack for when you misarchitected your program and can't easily pass data from one point to another due to how your app is encapsulated and what objects are known at what levels. It can cause real spaghetti code where its difficult to figure out what code will actually be called when an event occurs. You shouldn't be writing your code around having an event bus, it should be a last resort if you can't refactor things to work the correct way.
One of the advantages of events is that you can pass objects around to 'somewhere', and you don't need to know where it is picked up. This makes it easy to push your activity or fragment state to a controller class, and then use events sent from this controller back to the activity or fragment.
Because of events, the controller doesn't need to know if the receiving end is an activity or a fragment. This makes it very easy to switch one for the other. On the other hand this also makes it easy to put the controller somewhere else. Like first you have it as an instance in the application class, and then you move it to a service.
I wrote an article with a very concrete example on how you can use events to deal with the Android life cycle as described above: https://medium.com/#JuliusHuijnk/beating-the-android-life-cycle-d00a2f3ed88
I have a class (like a helper class) -not an activity- which manages soap requests. I use this class to send soap requests that comes from activities by method doInBAckground and catch all return values from webservice by onpostexecute. Everything is ok but my problem starts at this point because I could not pass return value asynctask class to main class.
You can have some utility class available as singleton (ok, singleton is dangerous pattern
but it use is justified in android until we get sane and usabel dependency injection ) and pass result there.
Advandatges:
- no messing with intents / serialisability
- pass data or call some methid or do whatever you like
- all your activities share the same instance of singleton service.
Disadvantages:
- singleton pattern is considered dangerous
You may even go further and make your service singleton - you will start methods of it as async tasks, and then your activity may query results over dedicated methods.
Or you may go a step further - register your activity as listener in async service, and call method in this activity when ready (note: as this will be not a UI thread, you will be unable to do something with UI unless you use runOnUiThread()
Have you tried implementing the AsyncTask as an inner class of your Activity?
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.
I'm pretty much a noob when it comes to Android development. I have an Activity that has a method that pretty much just sets the text of a TextView to whatever text is provided as an argument. I have a second class, which is a Runnable, and I want to be able to give it the Activity (or obtain the Activity somehow), so it can call said method when it needs to.
This Runnable will eventually connect with a server, so it can update the application with information from the server. I've done client/server Java stuff before, so that's not the issue. I just need to figure out how to communicate between this Runnable and the Activity.
Originally, I was going to just pass the Activity itself in, but I read that it would create problems if I did. Instead, I was supposed to pass in an ApplicationContext via getApplicationContext(). I did that, but now I don't know what to do with the ApplicationContext. I tried casting it to the my Activity class, but the program just crashes.
How do I accomplish what I'm aiming at?
There are a few specific ways in Android to handle threading like AsyncTasks etc., you should read up on how to do 'painless' threading here. If it's just a one-off task where you connect to the server, get the value, set it in the TextView and then finish, I think an AsyncTask would be your best option. Continuing background processes are more suited to being services.
you can pass your activity to the constructor of your second Class like this :
public SecondClass(YourActivity _yourActivity){
this.activity = _yourActivity;
//do stuff
}
and in your Activity , you can instanciate your class like this :
SecondClass instance = new SecondClass(this);
NOTE : in your SecondClass , if you want to change the UI of your application , you can use the method runOnUiThread(Runnable);