I am using a database that I need to access in all activities. So I created a class MyDBAdapter with all the methods open, create, getData etc...
To access the DB I see two different ways:
a. In each activity do I now write: MyDBAdapter db = new MyDBAdapter();
which means a new DBAdapter would be created in each activity. Each would open the same DB and have to close it. This also means that the same DB might be opened by several activities - is that OK? Or do I manually ensure that the DB is closed everytime I switch activities?
or
b. create only one instance of the DBAdapter in the first activity and pass it everytime to the next activity using putExtra("Task", x);
Then the DB gets only opened and closed once in the very first activity.
Which one is a better approach?
Thanks very much.
I prefer content provider to share data among activities.
Even though its mainly aimed to share among applications, It can be used inside our single app.
If we use content provider, there is no worries of closing and locking of db.
Content providers implement a common interface for querying the provider and returning results — as well as for adding, altering, and deleting data.
It's an interface that clients use indirectly, most generally through ContentResolver objects. You get a ContentResolver by calling getContentResolver()
Check this Simple Content Provider for db operations
Generally you have to close the database, right after you finish working with it (manually call db.close()). This mean that if you use your database in multiple activities, you have to close it every time after you have done using it. That said, it's up to you if you will make calls MyDBAdapter db = new MyDBAdapter(); in every activity or you will make a static reference to it. After all, if you have some local variable MyDBAdapter db in some code block, it will be garbage collected at some point.
Also generally speaking, you don't want your database operations in your Activities, because this way they will be executed on the UI Thread, blocking it, until they finish their db operation. You might want to use AsyncTask for your db operations which will create a separate Thread for db operations (and handle it for you). Here's a great tutorial on using AsyncTasks.
Related
I have an activity that uses AsyncTask to download and save some data to the database. To open a database we need to pass Context param to the SQLiteOpenHelper's onCreate method, which means that database somehow needs context.
And I'm just curious, what would happen when device turns and activity goes through destroy and create cycle? Is it ok to open database in activity's constructor rather than in activity's onCreate() method?
The problem is that I use DB from another thread and I want to know what exactly would happen when activity is being destroyed and recreated
One solution would be to use the ApplicationContext instead of the ActivityContext. You only need a static method that requests the ApplicationContext from the Application constructor.
If you use some kind of singleton to access the context, you won't have any problems with concurrency.
See example here: http://androidcookbook.com/Recipe.seam?recipeId=1218
Another approach would be to use the LoaderManager which keeps track of your opened database connections.
See here: http://developer.android.com/reference/android/app/LoaderManager.html
(There is a complete example too)
The LoaderManager is available in the compatibility package for down to Android 1.5
Michael
Incase you want to do some db operations in background. you should use "Sevices".
Services can do long running operations on background.
here is the link : http://developer.android.com/guide/topics/fundamentals/services.html
Seems the Google-recommended way (using the android support library) for a fragment or activity to interact with a sqlite database is via a loader that extends AsyncTaskLoader and works similar to the way CursorLoader does for ContentProviders.
A single activity or fragment may interact with a database in a variety of ways, updating, deleting, and querying data in one or more tables. But since a loader has only one place in which to carry out database manipulation (i.e. in loadInBackground()), is the developer expected to write a separate loader for each type of interaction, especially since it seems the only way to parametrize the behavior in loadInBackground() is by passing arguments to the loader's constructor via the args argument to LoaderManager.initLoader()?
Thanks much.
When not using a ContentProvider, i.e. when using sqlite directly, use AsyncTaskLoader if the set of database operations to be performed returns a Cursor. The set may include any kind of operation - update, query, delete, insert. These operations should be executed in AsyncTaskLoader.loadInBackground().
If the set of database operations does not result in a Cursor being returned, use an AsyncTask. In this case, the operations should be executed in AsyncTask.doInBackground().
There are two key benefits to using a CursorLoader in your app over Activity.managedQuery():
The query is handled on a background thread for you (courtesy of being build on AsyncTaskLoader) so large data queries do not block the UI. This is something the docs recommended you do for yourself when using a plain Cursor, but now it's done under the hood.
CursorLoader is auto-updating. In addition to performing the initial query, the CursorLoader registers a ContentObserver with the dataset you requested and calls forceLoad() on itself when the data set changes. This results in you getting async callbacks anytime the data changes in order to update the view.
Each Loader instance is also handled through the singular LoaderManager, so you still don't have to manage the cursor directly, and now the connection can persist even beyond a single Activity. LoaderManager.initLoader() and LoaderManager.restartLoader() allow you to reconnect with an existing Loader already set up for your query and, in some cases, instantly get the latest data if it is available.
Your Activity or Fragment will likely now implement the LoaderManager.Callback interface. Calling initLoader() will result in the onCreateLoader() method where you will construct the query and a new CursorLoader instance, if necessary. The onLoadFinished() method will be fired each time new data is available, and will include the latest Cursor for you to attach to the view or otherwise iterate through.
In addition, there is a pretty good example of all this fitting together on the LoaderManager class documentation page: http://developer.android.com/reference/android/app/LoaderManager.html
Hope that Helps!
Based on the previous answers, I'm not sure if this is what you're asking exactly. But YES, you have to make a loader with its unique id for each data set i.e. each type of query you perform.
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.
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.
Scenario:
public class MyApplication extends Application{...}
Three Activities, Overview, List and Map,
displaying the same data only providing different UI/UX.
Data fed into Contentprovider db and frequently updated externally by a SyncAdapter,
part of another application.
Read data from Contentprovider in to cursor.
Do cursor.setNotificationUri(),
to make the cursor listen for db/Uri changes.
Alt1. Hold the cursor in MyApplication.
Overview, List and Map then asks MyApplication for data.
On a db change MyApplication holds a reference to each Activity
and notifies them to ask for the data again from MyApplication.
Alt2. Hold one cursor in each Activity.
On a db change each Activity requeries the cursor for the data again.
Where should we hold the Cursor(s) ?
I'm facing a similar problem but not with DB and cursor but simple web request\response.
The problem u'll start facing soon enough is what ahppens when your activity dies in the midst of a request response.
I would suggest the following:
make a base activity u'll inherit
from that will contain a cursor for
the query.
make sure you have a method to fill
the currsor with data in onResume
start listening to broadcast
receiver.
when you finish a db update in the
separate thread, notify all
receivers.
when you perform on create check the
data in the DB to see if you missed
a call from the broadcast because your activity
has died.
so basically u will have a cursor in each activity, but no need to manage it by code unless you need to do something that is not standard with it. don't forget to dispose the cursor once the activity dies.