My fragment represents dynamic information which is obtained asynchronously. I am interested in how to provide the DAO/DTO to the fragment. Should the fragment maintain a reference to the DTO? What about updates. Should it request updated DTO and be the listener on these async calls or request that the activity make the requests and then update the fragment when the async response arrives?
There isn't really a "best practice" way to do this in Android. There are many ways and many of them are valid.
My recommendation would be to create a service that keeps track of changes in the data and report back to the fragment that requires it. Should be careful with this and make sure the service is only active when required, otherwise we can get background tasks that drain the battery.
The simplest way to register a BroadcastReceiver when the fragment is visible (after onResume, remove in onPause). This is like the intent filters that you can set for activities in the manifest. Here is a nice example: http://www.vogella.com/articles/AndroidBroadcastReceiver/article.htmlz
Once the receiver gets the intent there are 3 possible ways to procede.
Create a DAO and access the data (possibly a bit slow)
Use a ContentProvider and receive the new items in the intent sent to the receiver
If your data is Serializable or Parcelable you can add the new new data to the sent intent. (Possibly the fastest)
UPDATE
There is a useful tool for this kind of task that I forgot to mention: Loaders
They provide a simple way to handle data sources (like content providers).
Related
Is it a good way to use a broadcast receiver for syncing multiple data between activities.
My Scenario:
I have DisplayActivity and CreateEditActivity.
On my DisplayActivity I have created a broadcast receiver
that will listen to changes on my CreateEditActivity, also
this activity contain a list of data. Then when I open
CreateEditActivity all the present data in DisplayActivity
will be passed to the CreateEditActivity, on the CreateEditActivity I can create new data item and if the creation is successful I can pass this item thru broadcast. I know that this would be easier using just fragment and listener also using startActivityForResult does not fit on this process for me., But can I implement this process using broadcast receiver to pass sync data between activities. Hoping for suggestions.
I don't think it's a good idea.
Only one Activity is at the top of the stack at a given time. You should not make the assumption that your other Activity is alive. The system could have killed it. (You can test this by enabling the developer's option "Don't keep activities".)
It would be better to use persistent storage (Room, SharedPreferences or so). You could also try ViewModels(https://developer.android.com/topic/libraries/architecture/viewmodel) to avoid the burden of handling lifecycle events.
If you don't want persistence and your data can implement Parcelable just pass them to the other activity through Bundle.
There are couple of things that are bugging me in the process of downloading data and notifying the UI in Android. I'm using (Intent)Services to download the data, which works good enough.
I'm not sure how to deal with notifying the UI that data has been retrieved though. After some research and discussion in Downloading data using IntentService - Lifecycle Changes, and Which is the best way to communicate between service and activity?, I'm arriving at a point where I'm not sure which method to use anymore.
The alternatives I'm looking at are:
Service + LocalBroadcasts + Databases
An Activity would start the Service
The Service would download the data into a database
The Service would send out the Broadcast with a 'done' notification
The Activity would pick up this Broadcast and retrieve the data from the database using an AsyncTask
The Activity would retrieve the data from the database using an AsyncTask every time it is shown to the user (onResume, for cases it has missed the broadcast due to the user navigating away).
Service + ResultReceivers + Databases
An Activity would start the Service
The Service would download the data into a database
The Service would notify the ResultReceiver that it's done
The Activity would retrieve the data from the database using an AsyncTask
Instead of retrieving the data every time, the ResultReceiver is reused across lifecycle changes, and notifications are not lost.
Service + ResultReceivers + Bundle
An Activity would start the Service
The Service would download the data (optionally into a database)
The Service would notify the ResultReceiver that it's done, and supplies the data in a Bundle.
The Activity would retrieve the data from the Bundle (No AsyncTask needed).
Instead of retrieving the data every time, the ResultReceiver is reused across lifecycle changes, and notifications are not lost.
Options 1 and 2 require the user waiting for the database read/write operations. Option 3 is therefore quicker, but I've seen many sources recommend not using Broadcasts or ResultReceivers to transfer data (I'm not sure exactly why though).
For now, I am sticking with option 3, but I'm not sure if this is actually a proper approach, and if I'm missing something.
Can someone shed some light on this?
While some people (possibly righteously) vote this question to be opinion based, I am looking for pitfalls I am possibly overlooking. Furthermore, I'm looking for the answer as to why using ResultReceivers or Broadcasts for sending result data is recommended against.
Carefully using some sort of DataManager singleton instance, backed up by a database seems to be a robust solution. Using ResultReceivers, the UI gets notified and pulls the data from the DataManager.
I have also found out that using ResultReceivers and Broadcasts to send data has a negative impact on performance, because the objects need to be serialized. This is a costly operation, and GC might kick in because of it.
I have my MainActivity which gives the user a selection of pages to open, all of which involve downloading some data from the internet and displaying it. To save the user waiting when they choose their page I've made an AsyncTask as a subclass of MainActivity which produces an object DATAwhen the download is complete.
How would I pass DATA on to the SecondActivity in the following circumstances:
The user chooses the SecondActivity before the AsyncTask download has completed.
The download completes before the user chooses the SecondActivity.
the AsyncTask doesn't have to be a sub-class of MainActivity its just been tidy to do it that way so far,
thanks for the help!
Here's one way to do this:
Create a reference to your data in your Application. The Android Application is a good place to store global data. Next, populate the data via your AsyncTask (Watch out for the pitfalls of using an AsyncTask). You can now access your data via a call similar to this: ((MyApplication)getApplication).mydata
As you mentioned, two scenarios can come up. Either the data has been populated, or not. To handle this, use an observer that observes changes to the data. Have SecondActivity register as an observer when the data is null. When the data is available your SecondActivity's update method will get called and you can do whatever you please with it. Finally, make sure to unregister from being an observer.
Hope this helps.
Passing information directly between activities works only if it is Parcellable (via Intent). Almost anything could be made Parcellable but it is not always a good idea especially when the amount of data is large.
The next problem is that your AsyncTask most likely keeps the Context of your first activity alive when it is running longer than the activity lasts. Activity instances are quite often recreated when you rotate the device and naive implementations tend to start another asynctask in the new instance and end up with multiple tasks that download the same data. You would need to pass the reference of a running task between instances of the same Activity.
The simplest solution is probably to create a singleton (or a Service) accessible from both activities that hosts the AsyncTask & loads the data. If it requires a Context use getApplicationContext() since that's safe to use outside the lifetime of Activites.
Activities could register themselves as listeners for "data loaded" events while they are active.
I've recently struggled with AsyncTask and had difficulty having the UI behave while the task was running in the background. While there are comments around that services aren't really appropriate for the sort of thing you're describing, I've found them much easier to work with. You might check intentService as a middle ground. Good tut's can be found here and, specifically concerning intentService, here.
I am looking to implement the Google IO Rest Structure part A - Using a Service API. So i have identified the following portions of the structure.
An interface that provides rest method.
A Processor Class that implements the above interface. There will
many processor Classes. Each Processor class will return a model
class type.
A Service Provider, that deals with a Single Processor. The data
returned from the Processor is handled by the Service Provider. This
will call the Processor Function, and obtain the data returned.
A SerivceProcessor that is a service class. There will be a
single class in the application. This will communicate with the
various SericeProvides based on the Bundle data passed to it.
Service helper that provides high level integration between the
Activity and the Service
Now i am not clear here. The Service has the data that has been requested. How to proceede further. How do i pass the data back from the Service to the ServicHelper. Put it in a Bundle with the tag BUNDLE_EXTRA ? For this my pojo would have to be either Serializable or Parceable. I know Serializable is a really bad option on the Android Platform. What other options are they. Would i be using a Broadcast Intent ?
Thanks for any help here.
You can do a couple of things.
notifying back to the service helper through intents (letting it implement a broadcast receiver). This might be a bad idea since with a single rest call you can get a lot of rows. In this case you should implement some sort of facility to put your pojos in the intents you are sending back (like a fillIntent/getFromIntent method)
inside the service provider, store the result data somewhere (sqllite, contentprovider, file) and just throw a broadcast intent that will contain only the requestId and the result of your call.
The service helper intercept the broadcast and notifies any interested activity that the request has been completed. The activity updates the ui according to that. In this case the servicehelper is used just to keep track of the ongoing request / notify the results.
In my opinion this approach is better because you keep the ui and the model separated, and you don't demand to the activity the storage of the data, and it's more "rest oriented".
Plus: some time ago I tried to implement this approach. It's not completed but you can check the service helper and the request / result intents here postman lib
A more mature and robust library is robospice, which is what I would use now if I had to deal with rest services.
Okay so up front I will say that I am new to Android. I have made a few small projects and played with a few things and done tons and tons of reading. So here is the task I am trying to accomplish:
I have a remote service that runs in the foreground of my phone that can send and receive information with other android devices over a wifi network. APK's on the phone that are built to use this service contain multiple SQLite DB's. I want these APK's to register there content providers with the service so the service always know where to put data that it recieves (I have accomplished this task). When data comes in I will identify where it belongs and place it in the right DB (no problem here). So what would be the best way to notify the correct activity that new data has been received. Do I register Broadcast Receivers for my service to call? Will Broadcast Receivers work if the APK has been killed by the OS? Once the correct activity is loaded would I use a content observer to show the new data? Why would I use IntentServices?
I'm sorry for so many questions. Like I said I am learning fast but Android's SKD is massive and there are so many cool things. I want to make sure I am thinking things through right with best practices and making this very easily maintainable and expandable. Thanks for any help or advice I can get.
If you are asking what the best way is for a current Activity to know data has changed in the ContentProvider it is reading from, than the answer is a ContentObserver.
Lets say, for examples sake, you have a set of Activities and ContentProviders. Activity A is a list view of items from Content Provider A, and that list view is populated via a CursorAdapter of some kind. Whenever you have a query on a ContentProviders CONTENT_URI, the cursor should automatically monitor the CONTENT_URI for changes via a ContentObserver.
The reason this works is because in the ContentProvider:
Your query method calls setNotificationUri on your cursor to the URI that was queried.
Whenever a change happens in an insert/update/delete method, you are calling notifyChange on the URI.
If there is additional data that can change in your service that is not tied to a ContentProvider, than you have a few choices on how to pass data. If the Activity is in the same APK as your service, than you could use some sort of static variable, or the application context, or some other custom form of communication. The methods are rather liberal here because you are running in the same VM, so you have a lot of things available to you.
In your situation, it sounds like most activities will be in separate APKs. If that is the case, you will probably want to send out broadcast Intents to let the entire system knwo about the changes. If these changes only matter when an activity is running, you can register a BroadcastReceiver for the life of the Activity that cares about the change. Alternatively, you could put a BroadcastReceiver in the applications manifest, and always receive that change.
That brings us to IntentServices. IntentServices are the "easiest" way to handle long running tasks in Android. All they do, is create a background thread that will handle intents being sent into the service. A common use case is as follows:
You receive a broadcast intent that you need to react to (and it will take a while)
Send a directed intent (intent with a set component name) to an IntentService with some info from the broadcast intent.
IntentService either spawns a new BG thread, or adds the intent to the processing queue on the existing BG thread
The onHandleIntent function is called in the IntentService so that you can now process that change using as much processing time as you want.