The app has data in a SQLite database. The UI is primarily a RecyclerView. The question is how to best to transfer data from the database into the UI, whilst keeping off the main thread?
I originally planned to use a CursorLoader, ContentProvider, and RecyclerView. But reading around it looks like RecyclerView has no out-of-the-box support for Cursor-supplied data. Dang.
That then leaves me with a few other options...
AsyncTask to load the data, put it into model objects, and pass into the RecyclerView Adapter. Aside from being ugly, it isn't config-change friendly.
A custom Loader that loads the data from SQL and pushes it into model objects.
Use a Cursor loader, and when it returns the Cursor iterate through it to push the data into model objects. I suspect this would occur on the main thread and may damage performance.
Use Otto to send a request message to request data, and then return a model objects collection by return message. There may be ~500 objects so I think I may rather abusing Otto doing this.
If I am using a collection of model objects instead of a Cursor I see less benefit to a ContentProvider, and I also lose the ability for the UI to auto-refresh on data changes (which may be useful).
None of these options appeal much, is there a better way? The app is under time pressure so whatever it is needs to be fairly quick to implement. Unfortunately the UI needs to scroll horizontally and only targets Lollipop, so RecyclerView does seem a better bet than ListView.
use this simple adapter https://gist.github.com/Shywim/127f207e7248fe48400b, alternatively you could use android.support.v17.leanback.widget.ItemBridgeAdapter with android.support.v17.leanback.widget.CursorObjectAdapter but why to make own life harder?
Related
A bit of history: I used to code on main frames with COBOL back in the 90s when top down programming was all that was needed. I then lived through 2-tier, 3-tier and n-tier programming, so I understand abstracting the UI layer from the data layer, but the use of a content provider seems very restrictive and frankly counter intuitive.
I like the concept of abstracting the UI code from the data layer code, but the way the ContentProvider (CP) works seems to break this model. For instance, let's look at an example of an insert/update. Using N-tier, the UI code would call the data abstraction layer with a specific ItemID which would then hand back a POCO for the UI to use. The UI only needed to know about the getters and setters for data binding to work. When it came time to update/insert, the UI code would simply hand the POCO back to the data layer which would then determine if the item needed to be updated or inserted. The UI code didn't need to be concerned with HOW the data got to the DB, only that it either succeeded or failed.
With a CP, the UI code needs to know which URI to use to query based on getting a list of items or a specific item (which I am ok with). But both URIs return a cursor that I have to pass to my POCO which then populates the values so they can be changed by my data binding because cursors can't be updated. Then the UI code must determine whether the POCO needs to be updated or inserted and make a call to the appropriate function again using a specific URI. It then has to build a list of all the fields and all the values that need to be updated as well as providing a selection list to update the DB with.
It seems wrong for the UI layer to have to know about any of these items. Shouldn't all of that be encapsulated within the CP? It really seems to break the abstraction model entirely. What am I missing here with this new fangled technology?
BTW, I've already written an app using a CP so I understand HOW it works, I just don't understand the advantages of WHY it works the way it does. Other than keeping track of changes to data sourced by the CP and automagically updating them in the UI it seems like a lot of unnecessary overhead and programming and the implementation FEELS wrong.
Is performance in android degrading when interacting with a database storage often?
Is it better to load objects from DB and pass them around or access database frequently to get the objects?
I was thinking if the accessing the DB had more overhead due to instantiating objects from the result set each time.
I was thinking if the accessing the DB had more overhead due to instantiating objects from the result set each time.
Yes, it does, which is why if you are worried about performance, you should not use ORM tools to instantiate objects.
Is performance in android degrading when interacting with a database storage often?
Probably... you are reading from disk, which is slower than in-memory storage (which, hint, SQLite can do)
Is it better to load objects from DB and pass them around or access database frequently to get the objects?
Depends in what context you need actual class objects. If you store data in a database, then you should only query for that data when you need it, load it into an object, then do whatever calculation logic and save it. At least, that is my opinion on the matter. You shouldn't need to be serializing any objects between Activities primarily because you could lose state if you update an object in one Activity, pass it to another, then don't / forget to save it back to the database.
As google writes:
Note: Because they can be long-running, be sure that you call getWritableDatabase() or getReadableDatabase() in a background thread, such as with AsyncTask or IntentService.
which makes interacting with database out of main thread. So it can be not immadiate, so user will see some delay in app or fast appearing progress bar, or something. Especially when there will be big queries with 'union' and 'join'. But in most cases it is fast enough.
About your thinkig to access object due memory cache. It makes sense. Exact the same working with images provided by google here. So in your case db is disc cache other is same. You will need to provide some memory cache for your objects, but beware. If you working with huge number of them or each will be so heavy, you will need to provide not just simple wrapper to Map, that stores your objects, but something like LruCache.
So gathering all, you will recieve data from db, then store it in memory until app will need more memory.
I have a MainActivity that fetches a large-ish amount of data from a web server using Retrofit. This data is shown in a recycler view.
Now, I want to have another activity which works on the exact same data set. What's the most efficient way to do this? Earlier I have done this using a static Controller that keeps track of the data, but I keep hearing a lot of critique about static containers like that. Passing the data in the intents is not optimal, since the data is rather complicated and there's so much of it.
Optimally, I'd like to be able to modify the data set in either of the activities so that the changes are reflected to the other activity as well.
I think you should consider 2 options (depending on the amount of data you would like to share, and the type of devices your app is suppose to run on)
You can extended the application class to include global data between your activities. You can read more about it here: http://www.helloandroid.com/tutorials/maintaining-global-application-state
You can use persistence storage (i.e. sqlite/file).
There are trade-offs for each approach. And which one will suit you best depends on your specific setup.
I am still confused. I have read several tutorials of loaders and asynctask in Android but I can't understand some differences in some cases. For example:
Your app can't continue without the information which is provided by Asynctask or Loader
If you need information from MySQL database, what will be better?
And...What if you need information from SQLite database?
Maybe, you might need data from a url.
Your app can continue without the information which is provided by Asynctask or Loader
If you need information from MySQL database, what will be better?
And...What if you need information from SQLite database?
Maybe, you might need data from a url.
If you consider we must mention more differences or other case, you can write it.
Well, both of them are used to perform asynchronous operations, it doesn't really matter if your app can or can't continue without the information. Even if your app can continue wihtout the data, you still need to process it asynchronously to avoid an ANR message.
One reason to choose a Loader or an AsyncTask would be if you need to get data updates. The advantage of the Loaders is that they keep track of the data you are accessing and deliver new results when the data changes.
Other difference is that with Loaders you don't have to worry about configuration changes (orientation change e.g.). The LoaderManager takes care of that for you. With AsyncTask you need to take care of that yourself.
And there is even an AsyncTaskLoader, that does what AsyncTask does but with the benefits of Loaders.
The advantage of AsyncTask is that is very simple to use. If you don't need to load or monitor data, but just process something in the background. AsyncTask is still a good choice.
Cursors are simply used to reconnect to the last cursor onec it has been interrupted for a reason. They are usually designed to use in fragments or activitys.
Documentation for Loaders:
They are available to every Activity and Fragment.
They provide asynchronous loading of data.
They monitor the source of their data and deliver new results when the content changes.
They automatically reconnect to the last loader's cursor when being recreated after a configuration change. Thus, they don't need to re-query their data.
Asynctask are more likely a wrapper which contains a whole subset of methods to access the mainUI and background thread.
If I do need it, I'll have to modify about 15 classes (models and model-manager classes), so I really want to know if I need a ContentProvider.
Here's where I am:
Similar to Twitter, I'm getting rows of data from a server, and saving it locally in case the user has no Internet connection. But the ideal way is to always get it from the Server.
I am probably not going to use SimpleCursorAdapter because the rows of data I get from the server includes URLs, which means I have to create a custom adapter to display images.
I need to load data into the ListViews asynchronously because I'm having a ViewPager with 3 Fragments that shows the same data (different filters tho), so, since a ViewPager loads 3 Fragments into memory, it means 3 queries are executing (and that's most likely the cause of non-smooth swiping).
So far, the way I synchronize data between the App and the Server is:
Fragment.onStart() executes an AsyncTask which returns rows of data formatted as JSON data
Said AsycTask.onPostExecute() updates the List<E> and calls Adapter.notifyDataSetChanged()
The issue here is that each time I change tabs, the onStart() is called, ergo the AsyncTask executes causing the UI not being smooth.
Should I change the way I synchronize data with the Server, or should I use ContentProvider?
EDIT: as a head up, the reason I'm asking is that startManagingCursor() method is depracated. It says to use the Loader framework, but it seems it's only available through ContentProvider
You don't need to develop your own provider if you don't intend to
share your data with other applications. However, you do need your own
provider to provide custom search suggestions in your own application.
You also need your own provider if you want to copy and paste complex
data or files from your application to other applications.
from http://developer.android.com/guide/topics/providers/content-providers.html
I wrote a custom CursorLoader based on the SimpleCursorLoader source code that comes within the support library. You can search this site for more information about writing a custom one.