Why bother avoiding `Cursor.getCount()` when `moveToNext()` calls it anyway? - android

Conventional wisdom says to avoid calls to Cursor.getCount() because it's an expensive operation.
After digging through AbstractCursor source code, it seems all standard operations including moveToNext, moveToFirst, and moveToPosition all call getCount internally!
So what's the point of avoiding calling it yourself at all?
EDIT: added hyperlink to Android docs
EDIT: Perhaps I stand corrected?
I was under the impression that a Cursor can provide a moving window over large data sets, whose full length can only be known once the window has perused the entire set at least once. Hence calling getCount would cause a full load/iteration, and moveToNext advances the window only as necessary.

Related

Android SQLite wrapper keeps query open in CursorAdapter, is this good?

EDIT the assumption of this question is wrong, Android doesn't keep the query open, but it can cause other problems. See discussion bellow...
The Android Cursor implementation keeps a scrolling window of the underlining SQLite cursor, so it can implement "move forwards".
But I found a old SQLite documentation saying this is a bad practice, and you should not leave query open for UI inputs:
https://www.sqlite.org/cvstrac/wiki?p=ScrollingCursor
Also for example Telegram use it's own wrapper of SQLite, and don't have the scrolling cursor. https://github.com/DrKLO/Telegram/blob/master/TMessagesProj/src/main/java/org/telegram/SQLite/SQLiteCursor.java . They only have "next"
Also there is the "best practice" to call "getCount" in CursorLoader, if you look at the implementation, it actually tries to loop through all the data in the underlining query.
So is Android's wrapper implementation bad? Is SQLite doc outdated and it is ok to keep query open?
The Android Cursor implementation keeps a scrolling window of the
underlining SQLite cursor, so it can implement "move forwards".
Both scrollable and non-scrollable cursors implement move forward, i think you meant move backward here.
The documentation you specified, doesn't tell that using scrollable cursor with UI is a bad practice. It says
Get in, grab your data, then get out. Later on, when the user decides
to scroll up or down (which will usually be eons of time later from
the point of view of your CPU), run another query to refresh the
screen with new data.
As far as I know, android cursors work exactly this way. Android's SQLiteCursor (that is actually used with SQLiteDatabase class) is a subclass of the AbstractWindowedCursor. AbstractWindowedCursor uses CursorWindow within it, that is, as per documentation:
A buffer containing multiple cursor rows.
Each time the limit of this buffer is reached, AbstractWindowedCursor makes new CursorWindow and fills it with data.
P.S. In fact, these windows keep fairly big amount of data. It,s not limited by the screen size and far more than 5 or 50 rows (to be precise, it can be limited by 5 or even 1 row, if your rows contain, say, a thousand columns), and we as developers rarely face such behaviour.

getReference() vs. getChild()

I was wondering what the difference between database.getReference("foo/bar/123") and database.getReference("foo").child("bar").child("123") is?
I'm assuming that the later one will load the complete "foo" object whereas database.getReference("foo/bar/123") just loads the "123" object?
Is my assumption correct or what is the correct / most efficient way to only load data of "123"?
The two are equivalent. You can inspect this manually this by printing the toString() format for both References.
References are cheap - there's nothing inefficient about either solution. Neither one has yet loaded any data. A Reference is just a pointer to a location in the database.
It should not make a difference, a reference is not actually accessed when instantiated. This is the most relevant document I can find,
https://firebase.google.com/docs/reference/node/firebase.database.Reference
The docs don't say it explicitly, but requests are only performed when using the .set() or .on() methods

Asynchronous download of Bitmaps in an Adapter, with emphasis on Bitmap.recycle()

Could someone tell me how to make a good mechanism for async. download of images for use in a ListView/GridView?
There are many suggestions, but each only considers a small subset of the typical requirements.
Below I've listed some reasonable factors (requirements or things to take into account) that I, and my collegues, are unable to satisfy at once.
I am not asking for code (though it would be welcome), just an approach that manages the Bitmaps as described.
No duplication of downloaders or Bitmaps
Canceling downloads/assigning of images that would no longer be needed, or are likely to be automatically removed (SoftReference, etc)
Note: an adapter can have multiple Views for the same ID (calls to getView(0) are very frequent)
Note: there is no guarantee that a view will not be lost instead of recycled (consider List/GridView resizing or filtering by text)
A separation of views and data/logic (as much as possible)
Not starting a separate Thread for each download (visible slowdown of UI). Use a queue/stack (BlockingQueue?) and thread pool, or somesuch.... but need to end that if the Activity is stopped.
Purging Bitmaps sufficiently distant from the current position in the list/grid, preferably only when memory is needed
Calling recycle() on every Bitmap that is to be discarded.
Note: External memory may not be available (at all or all the time), and, if used, should be cleared (of only the images downloaded here) asap (consider Activity destruction/recreation by Android)
Note: Data can be changed: entries removed (multi-selection & delete) and added (in a background Thread). Already downloaded Bitmaps should be kept, as long as the entries they're linked to still exist.
setTextFilterEnabled(true) (if based on ArrayAdapter's mechanism, will affect array indexes)
Usable in ExpandableList (affects the order the thumbnails are shown in)
(optional) when a Bitmap is downloaded, refresh ONLY the relevant ImageView (the list items may be very complex)
Please do not post answers for individual points. My problem is that that the more we focus on some aspects, the fuzzier others become, Heisenberg-like.
Each adds a dimension of difficulty, especially Bitmap.recycle, which needs to be called during operation and on Activity destruction (note that onDestroy, even onStop might not be called).
This also precludes relying on SoftReferences.
It is necessary, or I get OutOfMemoryError even after any number of gc, sleep (20s, even), yield and huge array allocations in a try-catch (to force a controlled OutOfMemory) after nulling a Bitmap.
I am resampling the Bitmaps already.
Check this example. As Its is used by Google and I am also using the same logic to avoid OutOfMemory Error.
http://developer.android.com/resources/samples/XmlAdapters/index.html
Basically this ImageDownlaoder is your answer ( As It cover most of your requirements) some you can also implement in that.
http://developer.android.com/resources/samples/XmlAdapters/src/com/example/android/xmladapters/ImageDownloader.html
In the end, I chose to disregard the recycling bug entirely. it just adds a layer of impossible difficulty on top of a manageable process.
Without that burden (just making adapters, etc stop showing images), I made a manager using Map<String, SoftReference<Bitmap>> to store the downloaded Bitmaps under URLs.
Also, 2-4 AsyncTasks (making use of both doInBackground and onProgressUpdate; stopped by adding special jobs that throw InterruptedException) taking jobs from a LinkedBlockingDeque<WeakReference<DownloadingJob>> supported by a WeakHashMap<Object, Set<DownloadingJob>>.The deque (LinkedBlockingDeque code copied for use on earlier API) is a queue where jobs can leave if they're no longer needed. The map has job creators as keys, so, if an Adapter demands downloads and then is removed, it is removed from the map, and, as a consequence, all its jobs disappear from the queue.
A job will, if the image is already present, return synchronously. it can also contain a Bundle of data that can identify which position in an AdapterView it concerns.
Caching is also done on an SD card, if available, under URLEncoded names. (cleaned partially, starting with oldest, on app start, and/or using deleteOnExit()
requests include "If-Modified-Since" if we have a cached version, to check for updates.
The same thing can also be used for XML parsing, and most other data acquisition.
If I ever clean that class up, I'll post the code.

android cursor movetofirst performance issue

i am trying to optimize my application. I noticed that cursor.movetofirst() method somehow slowing the performance of my code.
Cursor cursor = myDbHelper.getDayInfo(new SimpleDateFormat("yyyy-MM-dd").format(myCalendar.getTime());
above line executes in 10 ms in 2.1 emulator, and
if(cursor != null && cursor.moveToFirst())
this line took about 1.6 seconds. I made little search about this. Somepeople say make it in another thread or in asynctask, but this will make the code more complicated.
I 'm just trying to figure out what is actually happening to this cursor.
Can anyone simplify or give a hint about database performance increase related to my question?
It's been a while since this was marked answered but you never really got a great answer here. Even on a very large table a single row query should usually take much less than 1.6 seconds. The reason it's slow is that you don't have an index for the column(s) that you are querying on so it has to scan the entire table to find those values. If you create an index you can cut the time down to a fraction of a second.
It is natural, that moveToFirst() method gets much more time that other code. The data enquariyng actually takes place, which invokes database communication, data reading and so on. You actually can't do anything with it. The advice was right - move all the long operations to AsyncTask.
If the dataset held by the cursor is large, moving the cursor around takes time. You have to perform such data-intensive operations on a separate thread. Using an AsyncTask might make your code a tiny bit complex but it's worth it. This against the user thread being blocked at the cost of a broken UI experience.

Android -- Object Creation/Memory Allocation vs. Performance

This is probably an easy one. I have about 20 TextViews/ImageViews in my current project that I access like this:
((TextView)multiLayout.findViewById(R.id.GameBoard_Multi_Answer1_Text)).setText("");
//or
((ImageView)multiLayout.findViewById(R.id.GameBoard_Multi_Answer1_Right)).setVisibility(View.INVISIBLE);
My question is this, am I better off, from a performance standpoint, just assigning these object variables? Further, am I losing some performance to the constant "search" process that goes on as a part of the findViewById(...) method? (i.e. Does findsViewById(...) use some sort of hashtable/hashmap for look-ups or does it implement an iterative search over the view hierarchy?)
At present, my program never uses more than 2.5MB of RAM, so will assigning 20 or so more object variables drastically affect this? I don't think so, but I figured I'd ask.
Thanks.
Yes, this would be correct to cache references to the views. That's what the ListView's Tag/Holder is about which is there for performance reasons.

Categories

Resources