I want to load data from database while scrolling, so I am using loader callback. But in init loader it is asking for database URI. If I use a ContentProvider, then it is working fine. But I would like to initialize the loader without a ContentProvider.
You need to use a different Loader. I recommend copying the source of CursorLoader and changing it to use an instance of your database (more specifically, your subclass of SQLiteOpenHelper) instead of the Uri and other arguments it uses to talk to ContentResolver.
Related
I'm newbie writing unit tests for my Android app. Currently I'm testing ContentProviders (like here) and I recently finished one and all fine doing CRUD operations tests for a "satellite" SQLite table ("satellite"=no foreign keys). Now I have to test another ContentProvider that perform operations in other table that have a foreign key to "satellite" table AND filesystem (images) files.
My issues are (questions reference to the ContentProvider being tested):
How to test ContentProvider if I need data from "satellite" table and (images) files? I need to create (in setUp() method) whole scenario (satellite data and images files) before running tests? And how? Think about this scenario: select * from table join satellite where satellite.id = ? (query return a path to image column too). I mean, tables and file system have to have some data to ensure query return rows and test if file exists, right?
ContentProvider is designed as an endpoint to trade data for SQlite table and images files in this way: insert() method receive temporal image file path and user data associated to the image. This ContentProvider move temporal image file to it's own logic inside custom path; and insert user data and previous path to SQlite table. Next query() method return image path and user data as a row. While inserting, I have to call an utility static method that return custom path, for instance this method: Uri origPath( Context context, long idC, long idP, String fileName ) called using FileUtility.origPath(...) inside ContentProvider#insert() (Context param came from testing ContentProvider). When testing, I have a
java.lang.UnsupportedOperationException
at android.test.mock.MockContext.getExternalFilesDir(MockContext.java:186)
I know that external/system calls by default throw an exception like that, but how to test my ContentProvider if it do a call to a static method from utility class to work? (like this) I need to refactor my code to adapt it to test work? or I have to change my test code for something else?
Can I call a ContentProvider from other ContentProvider? or is a bad design?
Is more useful to create a FileProvider and deal with all user camera images with that provider?, By design it have to be called inside ContentProvider anyway (like 3.)
Feel free to explain how my design can change for sake of code lord, or if there is a pattern for that, or I missing something.
how to set the data source for a custom loader if not using content provider?
I need to populate a listview from a sqlite but do not want to create the content provider for the database, instead want to use loader to fetch data from the database. So how do I set sqlitedatabase as the data source of a custom loader?
Two options:
Use a ContentProvider and set android:exported="false" for the <provider> entry in your AndroidManifest.xml.
Copy the source code for CursorLoader and modify it to query an SQLiteDatabase instead of a ContentResolver. Then you only need to pass it a reference to your database.
Note that in order for the loader to requery, you need to properly implement data change notifications when you modify data in the database. Typically this is done using contentResolver.notifyChange() on a URI. For option 1, it should be the URI you gave to the CursorLoader; for option 2, you can manually set up a ContentObserver in your loader and do the same sort of notification, or you could implement some other signal to the loader to issue a requery.
In my app I want to show a list of apps that I have placed in an resource file.
I parse the XML(resource) file and then save the value in a SQLiteDatabase. I have implemented my Database inside a ContentProvider. What I want to know is do I need a Custom CursorLoader (should I extend CursorLoader?)? or will CursorLoader itself will be sufficient. I have seen an example, but in this no ContentProvider has been used.
Can someone explain when should I implement a Custom CursorLoader as against using the original one?
(A little unrelated) Also what would be the best practice, to implement a database with or without a ContentProvider?
Thanks in Advance!
There are many ways to implement it -
If using a ContentProvider there is no need to extend the CursorLoader.
If not using a ContentProvider and using a SQLiteDatabase instead, we can extend the CursorLoader with our Custom-Loader and override the loadInBackground() method of CursorLoader and instead of querying the ContentProvider we can query the SQLiteDatabase.
While using a SQLiteDatabase we can extend AsyncTaskLoader, however, this is more tedious method than one specified in 2.
I have created a SQLite DB (which I am trying to use as contentProvider) and need your help to guide me on this:
1) Register a content observer (I don't know how to create URI for my Database)
2) on DB changes like update/delete row, I want to notify the contentObserver which has registered to URI of DB .
How can this be done?
You need to extend the ContentProvider class to implement your content provider.
The Android documentation walks you through the necessary steps including how to signal ContentObservers:
http://developer.android.com/guide/topics/providers/content-providers.html
I've been reading http://developer.android.com/resources/articles/live-folders.html
and http://developer.android.com/reference/android/provider/LiveFolders.html
and https://android.googlesource.com/platform/packages/apps/Contacts/+/donut-release/src/com/android/contacts/ContactsLiveFolders.java
But I want to extend my app (Which is a listview) to a live folder. It would be a nice fit. How do i use my listadapter as a cursor? Is this possible? And past that, how do i set the similar getView that my Listadapter provides? is a Baseadapter, which my listadapter inherits, able to become a cursor, which a livefolder needs?
Yes, this is possible. But you need a ContentProvider. While a ContentProvider is usually backed by some sql database, it is not an requirement. You can get the data in the ContentProvider's query() method from any source, as long as you return it as cursor. If you dont have a database cursor, you can wrap your data in a MatrixCursor instead and return the MatrixCursor.
I have such an implementation of the query() method and it works by returning a MatrixCursor.
It is a common misunderstanding that ContentProvider need to be backed up by datebase queries.
It is better to understand the ContentProvider as a contract which specifies 4 different (CRUD) methods which take certain types of arguments and return certain types.
Additionally, you can have different queries inside these 4 methods and switch them depending on the Uri.
Used like that ContentProviders can use any datasource and perforn any operation on that datasource, as long as you adhere to the contract specifiied by the ContentProvider class. That makes them extremely powerful.