I want registered callback method using sqlite trigger
for example,
public void printLog(){
Log.i("TAG","1 row added");
}
this method calling after insert any row in sqlite.
Is it possible?
How to do that?
SQLite provides Data Change Notification Callbacks. I don't think that Android exposes them directly but it does have for example CursorAdapter which provides some change notifications.
You can use also use the getContentResolver().registerContentObserver but unfortunately it doesn't tell you what kind of change was made, it could be a delete, insert or update.
If you control the ContentProvider that interfaces with the DB then you could fire an Intent or use getContentResolver().notifyChange to send a special Uri notification that identifies both the table and action. An example Uri you could notify with might be: content://my-authority/change/table-name/insert
But even then you don't know exactly which rows were effected by the change.
Seems like triggers that write to a change log table will guarantee you hear about all changes regardless of where they came from, and you can know the exact id and action that occurred. Unfortunately it means slower inserts/updates/deletes and it means you probably need a Service of some kind to process and delete changes.
I'd love to hear if these is some better solution out there!
You can set content observer this link will help Receives call backs for changes to content http://developer.android.com/reference/android/database/ContentObserver.html
Related
When i got some cursor i want to be aware for changes, so i have used the registerContentObserver() on my cursor and when change occur i just notify that change happened.
i looked into the notifyChange method on android developer and i didnt see any way to pass some metadata .
when i said metadata i meant any other object which tell me what change happen like delete/update/insert
You can't specifically add any metadata per se, but you can bend the system to pass this information anyway.
When registering your content observer, set the notifyForDescendants parameter to true. Then in your ContentProvider, generate a different uri to add information.
For example if the uri you normally use is content://com.example.app.provider/item/42, you can use one of the following uris to add information :
content://com.example.app.provider/item/42/inserted
content://com.example.app.provider/item/42/updated
content://com.example.app.provider/item/42/deleted
I'm starting to approach this wonderful world of Realm. I'm very happy of the results I'm getting and now I have one question to submit.
In my android app I've got a Fragment that displays data retrieved from Realm. The query condition is that the time this data refers to is in between the beginning and the end of today.
RealmResults<Appointment> results = realm
.where(MyObject.class)
.between("begin", rangeBegin, rangeEnd)
.between("end", rangeBegin, rangeEnd)
.findAllSorted("begin", Sort.ASCENDING);
This query is executed in the onStart() method helping me to exploit the live-update feature, which indeed works very well.
I've also added listeners for changes in order to optimize UI updates.
Now the question is: how does this live-update behave if the time conditions change? (Imagine I keep the app opened for more than one day without touching it or simply I keep the app opened for minutes around midnight)
From what I've seen it seems to do the same query done the very first time onStart() was executed.
Is there a way to have also live-updating query or should I re-run that query somewhere else outside onStart()?
Thank you in advance
Now the question is: how does this live-update behave if the time conditions change? (Imagine I keep the app opened for more than one day without touching it or simply I keep the app opened for minutes around midnight)
The query is pretty constant after you've set it up, so you'd need to execute a new query with different parameters for rangeStart and rangeEnd, and replace your other results.
This query is executed in the onStart() method helping me to exploit the live-update feature, which indeed works very well. I've also added listeners for changes in order to optimize UI updates.
Personally I'd advise to put the query in onCreateView() instead, and the Realm lifecycle management to onCreateView() and onDestroyView().
Also, you can avoid manually assigning RealmChangeListeners for displaying lists if you use RealmRecyclerViewAdapter (adapters 1.3.0 works with realm 1.2.0).
If you use RealmRecyclerViewAdapter, then just call adapter.updateData(newResults); and it'll update the view as needed.
I'm looking for a way to suspend notifications on a given ContentProvider's Uri. The use case is:
An Activity is bound to a CursorAdapter through a CursorLoader.
A Service may do a lot of batch, single-row updates on a ContentProvider.
The CursorLoader will reload its content on every row update, as the ContentProvider notifies listeners by ContentResolver#notifyChange.
Since I cannot edit the ContentProvider, and I have no control over the batch queries execution, is there a way to suspend notifications on a Uri (in the executing Service) until all of the ContentProvider-managed queries have been executed? I need this in order to avoid the flickering caused by the continuous requerying of the CursorLoader.
You cannot disable this mechanism in your Service. But you should try to batch them by using ContentProviderOperations.
I've written an introductory post about ContentProviderOperations and two additional posts covering the methods withYieldAllowed() and withBackReference() respectively.
Especially the latter one should be of interest for what you've described here.
With ContentProviderOperations you can batch multiple updates and inserts. If you then call applyBatch() on your ContentResolver object the ContentProvider executes them all at once.
Now I've never used Nicolas Klein's generator but since he is a very, very proficient Android developer and works at Google, I bet that the generated code makes use of transactions and calls notifyChange() only once for the complete batch at the end.
Exactly what you need.
Can you substitute your own ContentResolver?
You may try extends ContentResolver with your own class then and you will may override method notifyChange and realize your logic there.
In your Content provider class, inside query() method before returning the cursor, just comment the code which looks something like this
cursor.setNotificationUri(getContext().getContentResolver(), uri);
I have a ListView bound to a SimpleCursorAdapter, and I want it to refresh when I modify the database (by inserting, updating or deleting rows). cursor.notifyDataSetChanged() has no effect (it's called on the UI thread) and ListView.removeViewAt(int) throws an UnsupportedOperationException.
What am I supposed to do on Android to get such a basic behavior?
Note that the database is correctly affected and the modification is shown when I restart the activity. But restarting the activity is not an option here, and changing the ListView adapter is the last resource here, since it's a hack and can't guarantee a smooth transition
DISCLAIMER
Quite basic question, asked millions of times and answered zero.
Please, do not answer if you have never done this in your code, don't ask for mine, and don't bother with try this or try that. Only answer if you know how it's done
From API >= 11 the way to do this is using a CursorLoader, this is also included in the Android Compatibility Library, so you can also use this if you are targeting a previous Android version. CursorLoader will make the query in a background thread and return you the cursor. You will need to implement a ContentProvider. You can read the documentation to get an idea of how to use it. Basically you init a loader and then you restart it when you know data has changed. In the callback you just swap the cursor of your adapter.
Or you can just use requery() on the Cursor. The adapter will get automatically notified of the changes. This method is deprecated now and, of course, it's not the recommended way.
somehow I don't understand the working concept of the query parameter CALLER_IS_SYNCADAPTER. Its default value is false, if set, the DIRTY flag is not automatically set. So what does it actually mean? Out from my understanding, each change on a contact results in setting the dirty flag to 1. After a sync adapter finished the job, using insert/update/delete with the CALLER_IS_SYNCADAPTER the inserted/updated and deleted records should have a dirty flag of 0, is that right?
However if I invoke queries with that optional parameter, the entries remain with the flag 1.
Is there something else I have to do, or is my understanding how it should work wrong? Or is there something to tell the system the sync has been finished successfully to set the flags?
Does anybody have a sample or some advices for further reading?
CALLER_IS_SYNCADAPTER doesn't necessarily affect what's stored in the database row, it depends on the command performed. It shouldn't have an effect on queries. Do not use it from a user application on the device.
Now... Why does it exist?
It is provided to help with notifyChange() / ContentObservers / ContentResolver / Syncadapter integration. There are two use cases for changing a row in the database.
Local user edits from an application.
Changes come from the network (via SyncAdapter)
Either change requires the UI to update, if it's onscreen. Therefore ContentResolver.notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) gets called. This updates ContentObservers and tells them to go fetch the newest data from the ContentProvider DB. That last parameter in the call is your clue.
ContentResolver itself is a ContentObserver. When it sees the database change, it considers starting up your SyncAdapter to push the change up to the network. This is great in case 1. In case 2, it's redundant. The change came from the network, there's no reason at all to start up a sync to send the change back.
Calendar.CALLER_IS_SYNCADAPTER is a cue used within the update() performed by the SyncAdapter. When it's true, ContentProvider sets syncToNetwork as false, ensuring a redundant second sync is not performed
A second example is as veljko mentioned. The cleanest way to delete a thing from the server is to set the delete flag, and then perform a sync. When the CALLER_IS_SYNCADAPTER flag is false (user app) a call to delete() sets the flag. When the flag is true (sync is happening), a call to delete() pushes the deletion up to the server and removes the row from the local DB. There's only one delete() call, this flag allows the ContentProvider to know which task it's supposed to do.
You can add to your existing Uri:
myUri=calendarUri.buildUpon().appendQueryParameter(Calendar.CALLER_IS_SYNCADAPTER, "true").build();
Here is from Javadoc:
/**
* An optional insert, update or delete URI parameter that allows the caller
* to specify that it is a sync adapter. The default value is false. If true
* the dirty flag is not automatically set and the "syncToNetwork" parameter
* is set to false when calling
* {#link ContentResolver#notifyChange(android.net.Uri, android.database.ContentObserver, boolean)}.
*/
.
The invocation of resolver.delete(...), does not immediately delete a raw contacts row. Instead, it sets the DELETED flag on the raw contact and removes the raw contact from its aggregate contact. The sync adapter then deletes the raw contact from the server and finalizes phone-side deletion by calling resolver.delete(...) again and passing the CALLER_IS_SYNCADAPTER query parameter.