I'm trying to achieve isolation and modularization, so I store data in different apps that talk to each other.
I have a custom ContentProvider for public "foos" called FooContentProvider.
A second ContentProvider in a second app should hold some "bar" for some of the foos based on the matching "foo_id".
A third app should now be able to display a ListView with all the foos and if available, also the bars.
Now I'm stuck on how to organize my code. Can I get my FooBarContentProvider to list foos with associated bars or should I join these only in the FooBar ListView App? How can I still leverage the databases involved without duplicating data or having to store the joined table in memory?
Option #1: Two ContentProvider joined into a MatrixCursor using CursorJoiner
I found CursorJoiner that I could use to fill a MatrixCursor which I could probably use for my FooBarContentProvider or optionally just in the FooBar ListView App to back the ListView but I would expect a considerable lag at startup and memory issues if the foos and bars get into the many hundreds or thousands (which power users will achieve) and of course it would not work nicely if the data changes and new foos arrive.
Option #2: Use only the FooContentProvider and provide the BarContentProvider from a precompiled HashMap<String, Bar>
If the FooBar ListView was backed by the FooContentProvider, it could fill the "bar" data from a Map. This way I could reduce having to parse both ContentProvider prior to showing the first data to only one of them. Bars are smaller and strictly less than the foos in my case and changes to the foos are driven from a service, while the bars are mainly user input, so this would probably also be the better option for notifyChange() to work.
Option #3: Let a proxy ContentProvider collect the data into a merged database
A proxy ContentProvider could listen to the other two and provide the database I need but it would waste a lot of storage as especially the FooContentProvider will easily go into the hundreds of MB.
Option #4 ????
Is there a good option #4? How can I have a ListView that is backed by two ContentProvider in a way that all works smoothly especially at startup and changes in the data get propagated to the ListView quickly?
Related
Here's something interesting- How do I display information both from my content provider, and some real-time data from the web (which I don't want to save to my content provider?).
1.CursorLoader and CursorAdapter won't do IMO since I don't want to save the information to my content provider.
2.AsyncTask and updating the view in onPostExecute won't work, since right now I am displaying information from my content provider through cursorAdapter etc. and since the screen itself is an AdapterView subclass, when the loading is finished, the view might belong to some other element (recycled)
3.Service won't do for the same reason as #2 (and besides that, in this case, the background thread is coupled with the UI, so that doesn't seem like a natural solution).
**********Optional specific details starting from here if the picture isn't clear******
Say that I have some app which allows users to follow stocks.
I have a content provider, that at the path content://whatever.my.package.name/follows
has some information about which stock the user is following, whether or not it was sent to my server already (so it does have already some 'real time' data displaying through it), the parameters the user is interested in following, etc.
When displaying this information, I want to include some real time information from the web. I already have the necessary method implemented, but I can't think of a natural solution (see above). In particular, the real time data certainly cannot be saved on the same path (/follows) since this isn't a natural part of what I have in mind when I am thinking about the object "follow",but I do want to present the real time information about the stock, and it does relate to the follow presented on the screen (for example, a follow includes a start price, so we want to present the change from that start price to the real time price of the same stock etc).
I'm can't think of a good design I could use, so help will be appreciated :)
If the only thing that stops you from using the content provider is that you don't want to store the informations in it, then don't store it. Remember that a provider is just some abstraction above some data source. Nobody is going to stop you from using a in memory sqlite database for storing the live data.
Then you have two data sources and can build relations on them for displaying purposes like with sqlites attach_database or in code. Of course the live data is gone as soon as the provider is shut down so you must be able to handle that case.
EDIT
Hmm, ok. So touching the provider is a no go. You said the views are adapter views. How about using Volley or something similar to fetch the data in the adapter itself and cache it there. Whenever a view is requested (i.e in 'onBindView' when using RecyclerView) check the adapter cache for the data. If it does not exist or is outdated start fetching the data. When the request returns notify the adapter that the dataset changed. It then would start requesting views again making the next cache probe a hit. If you are fetching the data for each item in the cursor try to pass the index/position of the item to the request so that you can notify the adapter that a specific item has changed.
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.
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.
My application allows users to chat with friends (like skype or whatsapp), so I have an Activity for displaying a "conversation" (a list).
The user can change from one conversation to another.
So, the problem is changing from one list to another, or "updating" the whole list of messages.
What is the best way to do that? (performance and memory)
- Remove all elements from the list and add the new messages?
- Use multiple ListViews and Adapters?
...
Thanks!
I'd say it all depends on how you're storing the messages, and a lot of other parameters revolving around that.
However, I would probably cache the messages locally so that when the user selects a new conversation, they first get the to see the old messages while loading the new ones. One ListView, one ListAdapter of some sort and a List that I clear out when switching between conversations.
That might not be the most optimal approach, but that's how I'd do it in the given scenario.
I want to have an activity that shows the logs for the application. When it checks the internet for updates, how many updates it makes, etc etc.
So I'm thinking that there should be a new log entry every minute or so. What's the best way to display a long log like this? ListView? I plan to truncate the logs after...1000 entries? but still I don't want my app wasting tons of memory storing 1000 logs.
Depending on the complexity of your logs (one cell per entry might actually be a bit overkill)
you could try and store logs in a sqlite database, then use a simplecursoradapter and bind it to a listview. You wouldn't have memory problems as from the database perspective it's just text, and the cursor + adapter combination would make sure you only load and keep in memory what you're currently displaying on screen.