When you should use SparseArray setValueAt()? - android

Why is setValueAt(...) in the public interface of the SparseArray class? I was using it instead of put(...) obviously not getting the result I had in mind.

I came here trying to figure out the same thing. As Prekak Sola mentioned in the comments, setValueAt maps a value on a specific index, while put maps a value on a specific key.
Obviously, that can become confusing, but I think it is a very useful feature, because if you look at the official SparseArray documentation, it is mentioned that the SparseArray is generally slower than a HashMap, because lookups require a binary search and adds and removes require inserting and deleting entries in the array.
So, I guess that in certain cases, it would perform much faster if you iterate over the items in this container using keyAt(int), size(), and obviously all index-related functions, such as setValueAt, instead of using the keys.

Related

Is setting fields line after line from a Firestore document read an anti-pattern?

I have a document on Firestore, from which I read its fields in a fragment. Since it has many fields, I set variables in the Activity that hosts this fragment so that I can pass the data between other fragments. In order to achieve that, I realize that I have to write similar lines of codes over and over again, which got me to thinking if there is a better way.
Two possible solutions that come to my mind:
Structure all these fields in JSON format -> something that wouldn't be suitable in Firestore's document system imo
Put all these fields into a serializable data class which I keep in the activity then pass it around the bundles of fragments -> Seemed to complicated and I would still have to write it.get(foo) as bar for each of the field's of this class' constructor.
Given all these, what is the best approach? Thanks in advance.
You have a several options on how to approach this. There is none that's necessarily better than another. Ultimately, you will pick the one that best suits your needs and preferences.
You can do what you're doing now.
You can go a step further an actually check the types of the values instead of just blindly casting them (which would cause a crash at runtime if they didn't match).
You can provide a Class object to get(String, Class<T>) that can automatically map the fields to properties in a new object of type T, as long as the types also match.
You can call a variety of type-specific versions of get, such as getString()
Ultimately you will have to decide if you are going to trust what you get in the snapshot and allow errors to happen, or trust nothing and check everything. It's up to you.

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

update listview cells/items whose index may change

I have elements in a listview that change the way they look based on a network response
by the time the network responds the listview item (or item in the arraylist) could be at a different index
What I can do:
Make an alternate api call back to the server which returns all the items in the list (in their most updated form), and then call notifyDataSetChanged() on the adapter
but this seems like a waste of processes, and so does some alternative of searching an arraylist for the equivalent object, updating it and then calling notifyDataSetChanged()
Is there a way instead to have something like a BroadcastReceiver within the adapter that can keep track of the adapter item which started the network call or service? any maybe only respond to the receiver if the view is not currently recycled
It's hard to give an exact answer as your best approach since what you described is a really high level overview. I'll have to give an equal high level answer. Hopefully it help.
There's not many ways around searching an ArrayList in the adapter for a given item. One good idea:
You could create a custom adapter which is backed by an ArrayList but also maintains a Set of the data as well. The benefit is finding an item is O(1) however any adds or removes require you to modify two collections instead of one...which will cause a slight slow down. I've personally had to use this solution once for a highly complex adapter/listview. It could get updated quite often (to the point throttling notifyDataSetChanged() was once discussed) Surprisingly the slow down in maintaining a List and Set was hardly noticeable and overall worked well.
You could use a similar approach if your data has some sort of unique id associated with it. In which case you could build a Map of the data and use the maps values() method to obtain the List to use for the adapter. While using the keys to quickly find and update the required data. This may or may not be more difficult then the Set idea. Further if you can get your data into a SparseArray (having a unique int for each item), then you could use a SparseArrayAdapter which can get you O(log n) search times. Of course you loose the ability to sort your data in any meaningful way.
I'm not sure how viable the BroadcastReceiver idea is. I would see it more like each item's object instance would control the network request/response for itself, but that would seem tricky and odd. There's always the option of using a CursorAdapter. Just store all your data to DB. Have the network calls update the DB which can then be reflected within the CursorAdapter.

Sort LongSparseArray values

I have a LongSparseArray variable, in which the objects stored implement the interface Comparable.
Is there a easy way to sort them, without do it "manually"?
I tried Collections.sort(myLongSparseArray), but it does not implements the List interface.
Another way could be convert it to a List, but still I have not found any method to do that.
SparseArray, or LongSparseArray, should be considered as an efficient hash table when the keys are integers or longs. As such, it is not the best class to use if ordering is important to you.
Usually, when using hash-table type data structures, then uniqueness of values & efficiency of get / set are important.
If this is the case, perhaps you should look into using LinkedHashSet? It provides a way of holding unique items (based on their hashCode & equals functions), but also preserves the order of items, and has high efficiency of get / set.
If sorting is important, then you could extract the value list from the LinkedHashSet, then place it in a List, and use Collections.Sort() on it.

Android Spinner - System view VS User view

I have been creating Spinner controls (Combo boxes/Drop downs) in one of my apps, and was surprised to find out how difficult it was to achieve all of the following features:
User facing Strings are externalized, taking advantage of strings.xml internationalisation (I18N) feature of Android.
Spinner selections operate using a System view, which facilitates not having to work with or map Strings to meaningful values (yuck).
User view to System view mapping should be easy, automated and minimal (i.e not hand rolled for every component).
Others have attempted solutions to this, but universally as far as I could see they suffer from one or many of the following problems:
UI code is creeping into their enum class which doesn’t belong there (messy), nearly all existing solutions suffered from this.
Hardcoded User facing Strings in their enum classes. Because these are not externalized you cannot do I18N using the stock Android features.
Authors typically make the Fragment or Activity an OnItemSelectedListener which perpetuates a common problem of inheritance for convenience, where composition is more appropriate.
I have developed my own solution which does this: http://www.androidanalyse.com/android-spinner-externalize-user-strings-mapped-to-system-enum/
My question is, have I missed something? This seems like something that should not have been this hard (which makes me feel like I'm possibly reinventing the wheel).
Below is some example code showing my solution in-use (which is available Apache 2 license from the link above).
String none = getString(R.string.none);
String light = getString(R.string.light);
String medium = getString(R.string.medium);
String strong = getString(R.string.strong);
SpinnerUtil.createNewSpinner(view, R.id.wind, Arrays.asList(none, light, medium, strong), WindLevel.values(),
new SpinnerItemSelectedListener<WindLevel>() {
public void onItemSelected(Spinner item, WindLevel value) {
// Take whatever action you wish to here.
}});
I would just use ArrayAdapter<WindLevel>. Yes, you created a custom typed listener, but the regular event listener gets the position and can call getItem() on the ArrayAdapter<WindLevel> to get a WindLevel properly typed.
IMHO, the vast majority of Spinner widgets will be populated with material read in from a database, the Internet, or some other dynamic data source, rather than populated by some sort of enum with display values coming from static strings that can be internationalized ahead of time.
This is not to say that your code is useless: if you find it useful, then it was worth writing. And I am sure that there are apps out there that contain your targeted pattern (i.e., a Spinner backed by an enum or equivalent where the display values are known in advance and can be internationalized) who might find your solution useful as well. Every developer who writes enough code cooks up these sorts of helper classes and the like that help map an OS or framework model into something that better fits the developer's own mental model. So long as you are not perceiving any performance issues, it's all good.
Also, note that OnItemSelectedListener is an interface; implementing that interface on an existing class is not inheritance.
I believe the reason nobody answered you is :
What problem are you trying to solve ? Spinners existed prior to your well designed attempt.
Why reinvent them in exactly the same way they exist in Android ?
http://developer.android.com/guide/topics/ui/controls/spinner.html
It is a beautiful wheel indeed you designed, but still, it is just a wheel :)
UPDATE :
I think I begin to understand what you did. This is interesting. I'm not sure why you did not go to the pattern implemented by the ListPreference with its entries and entryvalues.
In fact, I'm not sure I understand why the Android team did not go that route either.
In any case, it is worth proposing your idea to the Android framework. It is after all open source.

Categories

Resources