When is the best time during an activity to bind my controls (such as textview) to values in my SQLite database? I thought I remember reading that you should do this in onStart() but most of the examples I have seen set the values in onCreate().
Here is an example of the code:
//I think this always goes in onCreate
MyDb db = new MyDB();
db.open();
Textview tvTextView;
tvTextView = findViewById(R.id.tv1);
//I'm not sure whether to put this in onCreate(), onStart(), or onResume()
tvTextView.setText(db.getMyText());
Normally MyDb and TextView would be variables for the whole class.
It depends on the behavior you desire. If you only want the text to be set a single time, onCreate() will suffice. If you want the text to be updated each time your activity is brought back to the foreground you can use onStart(), onRestart() or even onResume(). Obviously if you want the text to be updated even more often (e.g. every time the database changes) you'll need to do something more elaborate.
I suggest using laoders in the fragment support library. This example shows how to use loaders (using the ones in the HC API) to load a cursor from the contacts DB and update a list adapter when you get the first result and as it updates:
http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/app/FragmentListCursorLoader.html
Using this to fill in your own data is basically the same, but instead of setting it in an adapter when you get the cursor back you can just pull the data you want out and set it in your fields.
Article on how to get the support library version of these:
http://android-developers.blogspot.com/2011/03/fragments-for-all.html
I strongly recommend this as the preferred, modern way to load data from cursors and other sources. It takes care of a lot of things for you to make sure you are doing things the best way: it does the query asynchronously so your UI doesn't block waiting for it, it monitors the data for changes and gives you a clean way to update from a new cursor when there is a change, it takes care of integrating with the activity lifecycle, it propagates previous data across activity instances when an activity is destroyed and new instance created due to a config change, etc.
Related
I have an Activity that implements LoaderManager.LoaderCallbacks<Cursor>. The CursorLoader feeds into a RecyclerView (think ListView). So inside onLoadFinished I swap the data inside my adapter.
Imagine the data has to do with stock performance for a day. Now I have a Spinner that allows the user to choose a day. And when the user changes day I want the data to change. So I am thinking that the Loader needs to be able to listen to the parameter. How do I do that? Per the documentation of getSupportLoaderManager().initLoader I am not sure if calling it inside my spinner’s onItemSelected will do that trick. Thanks for any help.
And when the user changes day I want the data to change. So I am
thinking that the Loader needs to be able to listen to the parameter
to me, it sounds like you want to requery your database again when those data change. you can use restartLoader. You have to possibility to provide a different id, which can be used as identifiers for the specific loader. From the documentaion:
Starts a new or restarts an existing Loader in this manager, registers
the callbacks to it, and (if the activity/fragment is currently
started) starts loading it.
In my app, I inject some singleton manager objects using dagger.
Suppose one of these managers, say myManager, keeps data in a list, say myList.
Also I have a BroadcastReceiver class, say myBroadcastReceiver which calls one of myManager methods, say myMethod, when it receives some particular intents.
If I open my app and wait until myList is initialized, then press home, and after that myBroadcastReceiver receives the intent and calls myMethod, myList is null (though myManager itself is not null).
I can't figure if it's a matter of android's natural behavior or if I've actually made a mistake that it happens.
I think your singleton class is getting unloaded due to low memory you need to save that list in onSaveInstanceState(Bundle outState) and retrieve the same in onCreate method
You could either implement a "save state" solution using onSaveIntanceState functionality provided by android in your activity or service or whatever component you're using
Or you can save your data locally in a file or even better a sqlite database, which could be very simple and straight forward to implement.
And by keeping your list "in memory" synch'd with the local storage, you'll never lose any data.
Simply using lazy loading, each time your list is null, fetch the data back from local storage.
Updating ListViews with a CursorLoader was a simple way of displaying datas from a DB into UI. Model modifications where propagated to the UI with no extra work, and maybe not so efficiently.
RecyclerView.adapter, gives access to more granularity, allowing for instance to specify the adapter that a particular item was removed.
But, what is the best place to call those preferred methods (notifyItem*), replacing notifyDataSetChanged?
Obviously, the adapter must not observe the contentProvider, otherwise it won't know the nature of the model modification (just as before).
Different patterns could be used, like adding a bus to publish modifications from the provider, creating a singleton model which would hold a reference to the adapter, maybe using presenters (introduced in L), or creating an activity-bound service.
Here is a common use case: a sync process inserts an entry in DB (or a gcm notification is received, which also inserts an entry in DB), then i want UI (if launched) to be updated via a call to notifyItemInserted. Where to place this call?
Thanks.
I have a List of items that I want in a ListView, and I can make it work with setting a custom adapter every time the List grows, but the program flow is kind of weird and I have problems with persistence. (If I switch tabs, the UI gets rebuilt with an empty ListView.)
Now, in my day job I'm a C# developer, so when I look at this problem I see a WPF ListView bound to an ObservableCollection. Does Android/Java have something like that, a "fire and forget" connection between a UI element and a data structure?
You don't need to replace the adapter every time you change the data. The adapter "adapts" between data and view. There is no need to change the adapter as long as the way it adapts does not change.
Activity / Fragment lifecycle is not necessarily the lifecycle of your data collection. You can for example make a singleton data collection somewhere and use an adapter to display that collection all the time. Call .notifyDataSetChanged() on the adapter if you changed the data.
A persistent data collection in Android is probably best backed by a database. Take a look at LoaderManager & ContentProvider to provide and load data then displayed via CursorAdapter.
There is no automatic way of keeping a bunch of data available outside of your Activity / Fragment / .. lifecycle and it can get quite complicated but that's basically what you have to do if you want to keep data for longer than a given lifecycle. Singletons, Activity#onSaveInstanceState(), Activity#getLastNonConfigurationInstance(), Fragment#setRetainInstance(), ... are useful utilities to keep data in memory, databases are good for persistent data.
You have to do a little bit work yourself but it's possible. Use a ContentProvider as your DataSource. How the data is stored is up to you. I would prefer a SQLite-DB. A content provider has the possibility to add ContentObservers. (See this related question.)
You can write a CourserAdapter to fetch the Data from your content provider. And your ContentObserver should call notifyDataSetChanged() on your adapter. This closes the circle and your UI refreshes itself.
In Addition to zapls answer:
You can also write an adapter which contains a BroadcastReceiver. When your DataSource changes you can send a LocalBroadcast. The broadcast handler just calls notifyDataSetChanged() of your adapter. I think this would work around most of the lifecycle problems because only active elements will get the broadcast.
The google documentation has an example for such a solution.
I have a ListView with a custom ArrayAdapter, that shows orders from an ArrayList. These orders are supposed to be synced with my server. There I have an API, which I am requesting for new orders, and if there are any, I get an XML of the order back. What is the best approach to dynamically update the listView? I do not want to use SQLite to store the orders, because only last ten are supposed to be displayed. With a ContentProvider I am not able to store my custom Order object. And if I wrap the ArrayList into a singleton class and use it in the service as well as in the Activity class for the ArrayAdapter, the ListView is not dynamically updated (probably, because the arrayAdapter makes a copy of the arraylist?). Thank you very much.
Filip
use Intent or Bundle
i'm no sure what you mean regarding the ArrayAdapter not being updated, but i can give you a solution we used in my company.
I have a DataMaanger which is a bridge between the Activities and the Networking or SQLite.
The dataMaanger keeps it's data in memory so it's not in DB or on disk. the disadvantage of it is if your app gets killed for lack of memory and reconstructs itself, the dataManager will be empty, which leaves you with two options, either on every Activitie's death or you main task's activities death you serialize your DataManager's data, or if you are not dependant on any previous data, just make arequest again and update the data manager.
I use broadcasts to notify my activities.
To get an access to the DataManager i don't use a sigletone. i use the Application object, you can extend it and in the Manifest.xml give it's name in the tag, then it will be used instead of the regualr Application object.
You can access it later by using getApplication() method in Activity class.