I know how to save states and restore them, but I just get confused when I have to do work with the Web services and to update UI. For times I was using the AsyncTask but then I came to point where I loose my activity/fragment context for example when I rotate the device. So in this way, I am thinking how other apps are handling such situations.
If I use the IntentService and call my web service from there, then I came to think that for each web service I have to make IntentService differently, and update the UI of each activity and fragment I have to make the BroadcastReceiver for each activity and fragments.
So what is a good practice for calling web service from the activity and the fragments?
How can I Update UI when the service return arrives (or call next service based on first services results)?
If you want your data to be instantly available through configuration changes (which you do), then you probably want to use Loaders.
It gives the developer a mechanism of loading data asynchronously for an activity or fragment. Since loaders are specifically designed to solve the issue of async loading, one does not have to spend too much time designing async tasks to handle all different scenarios efficiently.
Good article about Loaders https://medium.com/google-developers/making-loading-data-on-android-lifecycle-aware-897e12760832
Try using retrofit. It's a great networking libraries for Android apps and it's easy to use.
The entire network call + JSON/XML parsing is completely handled by it (with help from Gson for JSON parsing). Documentation is great and the community is huge.
check out this sample.
I noticed a comment you made:
...and my webservices are soap and I cant change them
The way I'm currently calling my web service, which is also SOAP, is via an Intent. I do this by passing in the data that I'm submitting to the Web service with putExtra then receiving it on my WebService, as you probably do right now. I then get the result from that web call and process it inside an AsyncTask, the async task will then utilize EventBus to post to Results as needed which are received on my MainThread via ThreadMode.Main.
So with that said, I highly recommend the use of a library called EventBus from Greenrobot.
You greatly simplify communication between Activities and Fragments, You can get started immediately using a default EventBus instance available from anywhere in your code. For example, you can do the following.
EventBus.getDefault().post(new ModelForOtherActivityToSee(data));
In the model, you can include anything you want, and react accordingly when received.
The best part is that when received, EventBus handles how the data will be executed by either running ASYNC, MAIN, BACKGROUND
ASYNC - Event handler methods are called in a separate thread. This is always independent from the posting thread and the main thread. Posting events never wait for event handler methods using this mode. Event handler methods should use this mode if their execution might take some time, e.g. for network access. Avoid triggering a large number of long-running asynchronous handler methods at the same time to limit the number of concurrent threads. EventBus uses a thread pool to efficiently reuse threads from completed asynchronous event handler notifications.
Background - Subscribers will be called in a background thread. If posting thread is not the main thread, event handler methods will be called directly in the posting thread. If the posting thread is the main thread, EventBus uses a single background thread that will deliver all its events sequentially. Event handlers using this mode should try to return quickly to avoid blocking the background thread.
MAIN -Subscribers will be called in Android’s main thread (sometimes referred to as UI thread). If the posting thread is the main thread, event handler methods will be called directly (synchronously like described for ThreadMode.POSTING). Event handlers using this mode must return quickly to avoid blocking the main thread.
An example of receiving an event broadcasted from EventBus:
//ThreadMode can be ASYNC, MAIN, BACKGROUND
#Subscribe(threadMode = ThreadMode.MAIN)
public void onMessageEvent(ModelForOtherActivityToSee eventModel) {
/* Do something with eventModel received, this runs on UI thread */
};
Full example on how to use EventBus:
1 - Open your build.gradle for the app and set your dependency for EventBus:
dependencies { compile 'org.greenrobot:eventbus:3.0.0'}
2 - Create your first model to use in publishing an EventBus, I will use a very simplistic example of a model:
package com.myapp.models.eventbusmodels;
public final class EventBusMyModel {
private final String dataRaw
public EventBusMyModel(final String rawData) {
this.dataRaw = rawData;
}
public String getRawData() {
return this.dataRaw;
}
}
3 - Now all that's left is pushing out a broadcast by using from anywhere.
EventBus.post(new EventBusModel("My Data here"));
4 - To enable Activities/Fragments to receive events from EventBus you must attach and detach, this is what I mean. From inside an Activity on the onResume() and onStop() overrides:
public class SomeActivity {
#Override
protected void onResume() {
if(!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
}
#Override
protected void onStop() {
if(EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
super.onStop();
}
}
5 - The final thing to do is receive that broadcast, you can receive it in Any Fragment, Activity, or in all your fragments/activities. Here's an example from inside the SomeActivity:
#Subscribe(threadMode = ThreadMode.MAIN)
public void eventThisNameDoesNotMatter(final EventBusMyModel resultModel) {
String receivedData = resultModel.getRawData();
//Do whatever with receivedData. Since we are on ThreadMode.MAIN, this is on the UI thread.
}
Related
I have some fragments loaded in a ViewPager, where each "page" is loaded from a row in a cursor. Each fragment shows an image (JPEG) on the device. When the user dismisses the fragment (i.e swipe/page change, hits back/up, or just closes the app entirely) I want to invoke a method which opens the JPEG file for writing and does an update of its metadata. The actual work is eventually handled by the Apache Commons Imaging library.
I've implemented this by invoking my saveToFile() method from each fragment's life cycle onStop() handler. Does this mean the entire file operation ends up running on the UI thread? Should I definitely set up an AsyncTask for this?
Say the file write for some reason suddenly (for some jpeg) should take a long time, eg 2 minutes. What would then happen? Would the UI just wait (freeze) at this page/fragment before resuming? Or would the process (write to file) carry on "in the background" somehow? Or would the process just be killed, stopped short mid-process?
The way I have this wired up currently (onStop invoking saveToFile(), which calls up the imaging library and then updates the file) seems to work as it should. Even if I end the app, I still see my Toast text popping up, saying "Writing to file..." Seemingly, the process is never disturbed, and I can't say I'm experiencing any UI lag.
onStop() handler. Does this mean the entire file operation ends up
running on the UI thread? Should I definitely set up an AsyncTask for
this?
YES
An AsyncTask has several parts: a doInBackground method that does, in fact, run on a separate thread and the onPostExecute method that runs on the UI thread.
You can also use some sort of observer pattern such as EventBus to run async and post results to the UI.
Say the file write for some reason suddenly (for some jpeg) should
take a long time, eg 2 minutes. What would then happen? Would the UI
just wait (freeze)
The application will crash because Android will forcefully close it due to ANR (Application Not Responding).
Refer to the official documentation for details on this: https://developer.android.com/training/articles/perf-anr.html
Android applications normally run entirely on a single thread by
default the "UI thread" or "main thread"). This means anything your
application is doing in the UI thread that takes a long time to
complete can trigger the ANR dialog because your application is not
giving itself a chance to handle the input event or intent broadcasts.
Therefore, any method that runs in the UI thread should do as little
work as possible on that thread. In particular, activities should do
as little as possible to set up in key life-cycle methods such as
onCreate() and onResume(). Potentially long running operations such as
network or database operations, or computationally expensive
calculations such as resizing bitmaps should be done in a worker
thread (or in the case of databases operations, via an asynchronous
request).
The most effective way to create a worker thread for longer operations
is with the AsyncTask class.
Here is what I recommend though. Use the above mentioned, EventBus and create a BaseActivity which will automatically save the data for you onClose() by firing an event that runs Async. You then extend that base activity in all the places where you need autosave capabilities.
Here's what I mean with an example that uses EventBus.
public abstract class BaseActivity extends Activity{
#Override
protected void onResume(){
if(!EventBus.getDefault().isRegistered(this))
EventBus.getDefault().register(this);
super.onResume();
}
#Override
protected void onDestroy() {
if(EventBus.getDefault().isRegistered(this))
EventBus.getDefault().unregister(this);
super.onDestroy();
}
#Override
protected void onStop() {
super.onStop();
//We fire event and pass the current parent class that inherited this base.
EventBus.getDefault().post(new EventBusProcessMySaveData(this.getClass()));
}
}
//Your model class to use with EventBus
public final class EventBusProcessMySaveData{
private final Class className;
public EventBusProcessMySaveData(final Class className){
this.className = className;
}
public Class getClassName(){
return this.className;
}
}
public class MyMainActivity extends BaseActivity{
//Do you standard setup here onCreate() and such...
//Handle Event for Saving Operation, async.
//This will fire everytime theres an onClose() IN ANY activity that
//extends BaseActivity, but will only process if the class names match.
#Subscribe(threadMode = ThreadMode.ASYNC)
public void methodNameDoesNotReallyMatterHere(final EventBusProcessMySaveData model){
//We make sure this is the intended receiving end by comparing current class name
//with received class name.
if(model.getClassName().equals(this.getClass())){
//Do whatever you need to do that's CPUintensive here.
}
}
}
I'm refactoring an app I made some time ago. Back then I was taking my first steps into Android and the easy way to go was to avoid orientation changes, for almost all my CRUD operations I used the AsyncTask class, didn't implement a Content Provider or used Fragments.
Now I have made some changes:
I use Fragments to encapsulate functionality
All accesses to my database are done through a Content Provider
I use CursorLoaders to retrieve my data taking advantage of the content observation and automatic background loading the LoaderFramework brings.
The only problem I have now is that I'm not quite sure how to handle the rest of the CRUD operations (Create,Update, and Delete).
I've found that I can use the AsyncQueryHandler class, but there's not enough information online.
One thing I like the Loader Framework, is that is aware of the Activity or Fragment lifecycle, but what about the AsyncQueryHandler?
What happens to the operations that were started with startDelete, startInsert, startUpdate when the Activity/Fragment undergoes a configuration change? Or when I press the back button? Or worse yet, if the activity is destroyed?
What is the expected behavior of this kind of operations in such cases? Should they be cancelled or should they continue to do their work?
All the operations I've mentioned above are not that complex. For real complex operations I've used Services or IntentServices, but since I don't consider a good idea to run SQLite operations on the main thread I want to use a better solution, but first I need to know how that solution should react to the Activity/Fragment lifecycle events.
Any comments or suggestions would me greatly appreciated.
Thanks.
If you use AsyncQueryHandler you have to take into consideration that this abstract wrapper is created and executes provider operations on the thread that it was started on. If you call this from UI thread the callbacks will be sent to the UI thread. If you call this from another working thread, the callbacks will be sent to that working thread.
This is not bound to the lifecycle of the fragment or the activity, ContentProviders don't have an lifecycle.
The AsyncQueryHandler at an basic level, creates an Message object which is added to the MessageQueue of an single background thread. No matter from which activity/fragment you use the AsyncQueryHandler all the Message objects will end up on the same MessageQueue.
Once the background thread processes an request it will send the response back to the instance of the AsyncQueryHandler from which the request was initially made.
My recommendation is to use the Loaders from Android. These are directly tied to the lifecycle of the activity/fragment. You can have multiple Loaders in a LoaderManager(one LoaderManager per activity/fragment) which allows to do more complex operations. Your activity/fragment will automatically be notified when the content has changed(very useful when you want to combine it with your custom methods for CRUD operations or if you need to use long running services). Another very important feature they have is that they will always reconnect to the last Loader, thus you will avoid re-querying your content.
I recommend you search for some tutorials for implementing Loaders in Android. You can start with these:
Loaders - part 1
Loaders - part 2
Loaders - part 3
Loaders - part 4
Answer for your last comments:
I suggest to use the EventBus library (https://github.com/greenrobot/EventBus) to make the communication between your AsyncTasks/Thread and your other components.
You can start by creating an abstract AsyncTask/Thread and on top of that to make your specific command.
For example:
public abstract class AbstractThread extends Thread {
#Override
public void run() {
super.run();
command();
}
abstract void command();
}
In the abstract class you could make some DB initialization, verification or anything else that might make sense for your application.
public class InserTask extends AbstractThread{
#Override
void command() {
//TODO: Add logic for the insert task
}
}
public class UpdateTask extends AbstractThread{
#Override
void command() {
//TODO: Add logic for the update task
}
}
In these specific classes, just add your logic of the CRUD operation.
To have control over these threads, like when they should be stopped, paused, resumed you could create and ThreadPool manager which controls your threads. You can read more how to achieve this here: Thread Pool
I have a Handler on the UI thread (created using new Handler(Looper.getMainLooper())) which has a sequence of messages sent to it as soon as the application starts (specifically, after the Application class' onCreate). What I have noticed is that this Handler doesn't seem to receive messages until around the time of the onCreate of the very first Activity. Prior to that point, messages sent to it appear to be lost.
Is this because the UI thread's Looper is not yet ready to execute messages until the first Activity is visible?
Supplementary information
I'm just adding this information in relation to comments below -- it's not part of the specific question.
This Handler is used as part of a mechanism that allows various long-running tasks to cause progress information to appear over the current Activity, using my own version of Eclipse's IProgressMonitor.
When the application starts, a piece of initialisation work is done. This work is a long-running task which involves building data structures based on contents of a file. This piece of initialisation work might have to be repeated later on during use of the application, depending on user operations.
In this application I have my own implementation of IProgressMonitor, an idea based on the class from the Eclipse Platform API. With this, various long-running tasks in the application, including the initialisation work, can grab simply grab an IProgressMonitor from a manager class, and call progress update methods on it (like done(), percentDone(), and so on). If any Activity is visible, this causes visible progress notifications to be visible (using the Crouton library).
The actual implementation behind the IProgressMonitor uses a Handler to transfer the done(), percentDone() etc. updates onto the UI thread. Then, the manager class gets the updates via the Handler and it causes visible status updates if an Activity is visible (and has registered with the manager).
What has brought me to the above question is that when the application starts and the initialisation happens for the first time, calls on the IProgressManager don't seem to find their way through to the manager via the UI-Thread Handler until the first Activity is visible. This doesn't matter whatsoever from a functionality point of view because without a visible Activity the manager can't display anything anyway. But I am just curious about the cause.
the messages are not "lost" as you said, they are delivered, just later. That's because even thou you have have several Handler object, the queue the messages are going to is just one, the Lopper queue. And when your activity is launch, the Android system already queue-up all the other stuff it has to do in order to show the activity to the user.
On a side note: If it's not used for any UI related stuff, DO NOT PUT IT ON THE UI THREAD! Makes sense right?
Some options, might vary depending on what they're doing exactly:
use lazy initialisation, meaning, only init those components first time the user actively needs them.
create a HandlerThread with low priority to perform those operations that are not UI related. Maybe even delay them for a couple of seconds to let the whole UI be built first, before executing any of them.
edit based on your extra information:
I do not advise on the approach you're taking in building this and the reason is: that's not what Handlers are for and the Android framework have its own implementations for long running tasks and how to communicate back with the currently active Activity
"This work is a long-running task" in Android, long running tasks, specially tasks that have nothing to do with the UI, should be delegate to a Service Probably you should look into a IntentService that automatically have a HandlerThread that executes long tasks in a background thread the order they are received and auto-destroy when there's nothing more to execute.
To get update information about on going tasks that are being executed on the service there're two possible approaches.
1 - more complex, but more complete approach, You bind the Activity to the Service and direct call methods on it like setListener. That involves some ServiceConnection callbacks, but also allows a close interaction between activity and Service.
2 - a simpler unidirectional approach is to have dispatch updates to the LocalBroadcastManager and make the activity listen to them, I'll show you a quick example below:
service code, for example to send a progress update on build data structure job
Intent i = new Intent(MY_APP_UPDATE);
i.putExtra("serviceType", BUILDING_DATA_STRUCTURE);
i.putExtra("updateType", ON_UPDATE);
i.putExtra("updateValue", progress_percent);
LocalBroadcastManager.getInstance(this).sendBroadcast(i);
then on your activity you create a BroadcastReceiver inner class and onResume/onPause you listen for updates.
private BroadcastReceiver myReceiver = new BroadcastReceiver(){
#Override public void onReceive (Context context, Intent intent){
int serviceType = intent.getIntExtra("serviceType", 0);
int updateType = intent.getIntExtra("updateType", 0);
int updateValue = intent.getIntExtra("updateValue", 0);
// here you can properly handle the updates being sure that your activity isResumed
}
}
then onResume/onPause you register/unregister
LocalBroadcastManager.getInstance(this).registerReceiver(myReceiver, new IntentFilter(MY_APP_UPDATE));
LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver);
but all that is because I like to play inside the Framework rules and builtin features as they tend to be slightly more hassle free than re-inventing the wheel.
I have a situation where I have multiple activities that deal with a single global list of objects.
From activity A, I can start an asynctask which sends an HTTP Get request to retrieve an XML message then parses the XML file into a series of objects.
My aim is to be able to refresh all views, only if the underlying data structure changes.
This should ideally mean that I can launch activity A, call an asynctask, move onto activity B, C D etc, and when the asynctask completes (no matter what activity I am on) the current view should be updated.
I've looked into broadcast listeners but I am not sure I am on the right direction with this, would it be possible for somebody to explain if this is possible?
Thanks
Since AsyncTask instances are dependent of the caller Activity, I think this is not the correct approach. In your case, as you need to recover the result within any Activity, I'd use an unbound Service so it might be accessed whenever you want, wherever you want.
You might also use a local BroadcastReceiver which would send a signal to all of your Activitys and, those registering the action that sent your AsyncTask/Service, would perform the necessary actions you may need. Be careful as if your Activity has not been started, obviously that Activity won't be able to process what you've sent since that receiver should be unregistered.
Just post a runnable to the handler of the current Activity.
Your activities can implement a common interface, where a function "updateUI" or whatever exists, and that way your runnable can be one line, and be agnostic as to the current active instance.
As you probably know the postexecute part of the asynctask runs on the UI thread of the activity that launches it. Since that activity may be dead, just post to the handler in the "doinbackground" part of the async task and keep postexecute blank.
interface Updateable{
public Handler getHandler();
public void updateUI();
}
From Async Thread
final Updateable curr_activity = ...
Handler handle = curr_activity.getHandler();
handle.post(new Runnable() {
#Override
public void run() {
curr_activity.updateUI();
}
});
I've just started looking at GreenRobot's EventBus for Android and have a question about threading.
I have a long-running process that I'd like to run on a background thread which, when completed, updates the UI.
So something like:
public void onEventBackgroundThread(MyEvent event) {
doSomeLongRunningProcess();
updateUI();
}
Obviously updateUI() can't be called here because it would also run in the background.
So what would be the recommended way to handle this? Fire another event from within my onEventBackgroundThread() which will run on the UI thread? Or fire it from the long-running-process itself? Or is there a better pattern?
I would probably fire another event when you get the result.
public void onEventBackgroundThread(MyEvent event) {
doSomeLongRunningProcess();
EventBus.getDefault().post(new MyEventResult());
}
Be aware though: reading the docs, you find this:
BackgroundThread: Subscriber will be called in a background thread. If
posting thread is not the main thread, event handler methods will be
called directly in the posting thread. If the posting thread is the
main thread, EventBus uses a single background thread that will
deliver all its events sequentially. Event handlers using this mode
should try to return quickly to avoid blocking the background thread.
If you take a long time in this method, other EventBus callbacks will be delayed which will probably translate to an unresponsive application.
You probably want to use onEventAsync:
Async: Event handler methods are called in a separate thread. This is
always independent from the posting thread and the main thread.
Posting events never wait for event handler methods using this mode.
Event handler methods should use this mode if their execution might
take some time, e.g. for network access. Avoid triggering a large
number of long running asynchronous handler methods at the same time
to limit the number of concurrent threads. EventBus uses a thread pool
to efficiently reuse threads from completed asynchronous event handler
notifications.
I'd suggest firing another event which will be handled by onEventMainThread method.
This has a positive impact of the updateUI not being called at all if the receiver is already unregistered (e.g. activity unregistered because it was destroyed).