Kotlin - var property vs object copy [closed] - android

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 3 years ago.
Improve this question
My team has an argument today about var property and object copy. We have an adapter for a RecyclerView. The adapter takes a list of ItemModel, which has a few properties. When any item is clicked, we need to change a property's value of the clicked item.
Some people say we should make the property a var. So, we can assign the new value to it.
Some others say we should make the property val, and use ItemModel.copy and pass the new value to the copy. But to do this, we need to call List.map to create a new list as List is not mutable. This means, to change one property value of one item, we need to loop through the whole list, create a new list with all the items and the new copy of the item that is changed.
In my experiences, the former method looks right to me and the later one does too much unnecessary things and makes bad impact upon performance and resources. But, they were arguing about property mutability and etc. and claimed the later one is a more modern way of programming.
Can anyone with good understanding of android and the functional programming explain for me if the later one really is considered a better way?

It being your recyclerview´s list it should be a mutablelist if the recyclerview should mutate the lists item count effectively (create or delete). val and var on the list does not really matter (in witch case you use val) as you don´t need to reassign the list when you create, update or delete the items. Every single of those operations will not reassign the list object. It´s still the same list, just with different items in it. val and var matters when you want to change value x of item number 3 in the list. Then it (the variable x) has to be var for you to be able to change it, but the list does not.
You use val to indicated that the value will never be changed. It´s for maintainability so weird bugs don´t happen. Like you have another object referencing that list we talked about before. If the list was a var it would be possible to create a new list on the variable and now your two objects no longer point to the same list. Instead one of them still points to the old list. You may not expect that and your program will break. Hence wherever feasible you should be using val. Wherever necessary you should be using var and not complicate your life trying to preserve val unless you have a good reason like this value cannot be changed as it´s referenced all over the place. That's when you use object copy. But not as a default best practice for everything.
That´s just my opinion about it.
On a side note marking a class as a data class will generate the copy method for you. So you can copy that object without even requiring to implement copy. Witch is pretty great!

Setting the property as var is very tempting, however it can lead to errors that could not be even that easy to reproduce. When you are passing around the reference to an object and there are a couple of places where its content is used and could be changed, you might lost control of the actual application state. The code might become unpredictable.
Immutability is the core of the functional programming. It's purpose is to eliminate such vulnerabilities and help programmers write pieces of code that every time execute as expected, because it eliminates the risk of side effects occurrences.
However, as you and your team noticed, the functional approach sometimes may require additional work and resources. But is it worth it? Well, I don't know how large that list should have been to significantly influence the performance by mapping it. And even if currently your objects aren't shared anywhere, you can't be sure that in the future somebody won't change that. So having in mind that the functional approach is less error-prone, I'd say it is worth it.

The second method is contrary to the Basic Design of Kotlin.
With Kotlin you don't Need to write as much lines of Code as in Java, for example the get and set functions which are included in a class. Why do you want to make your Code longer and more complicated in a Language that was designed to shorten the lines of Code?
Another Point is, longer codes can get hard to read and maintain.
The last Point is, that a copy of a class Needs more ressources and time to create and Access than a Var, for me there is no reason why this should be considered as good Approach.

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.

Updating an UI upon changes

I am building an app that displays a bunch of information that the user can edit, and I am having trouble keeping the UI updating the data displaid so it is consistent with the new edits done at runtime.
I have implemented updateUI methods that basically look like:
void updateUI(){
((TextView) fieldDisplay).setText(fieldCurrentValue);
...
}
I know I can run this method in things like an AsyncTask or similar stuff that makes it execute continuously. But Im concerned about efficency since its not really necesary to update the UI all the time, but only when the user inputs a value wich is not that often.
What would be the best approach to this?
EDIT:
The question is how to make sure the an UI element shows the current value of a field, regardless of how or why that field is updated.
My case specifically is the with this. Im trying to make an RPG character sheet, and I have like a bazillion Skills, wich are affected by another lot of fields, such as Characteristics, Modifiers, Categories...
The application should behave so, whenever any of the many fields affects it changes, it should display the new value.
Now, since keeping track of what field affects what is part of the problem, if could update whenever any field whatsoever changes, but I dont know how to do that.

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.

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.

Android Patterns: A Spinner where every item launches a different Activity

I'm trying to build a complex form where almost all of the elements are optional. It starts with just a single field and an "add element" button. When you click add, the form shows a Spinner of the types of elements you can add to the form (location, photo, detailed note, timestamp other than "now", etc). When you select an item, it will launch an Activity, and each item has a different associated Activity.
In addition, each choice will have several bits of data, which it would be nice to store "with" the Activity somehow:
An icon and the displayed name in the Spinner
A key for storing the data in the db (as well as passing to a webservice)
A layout for how to display the result on the original form (i.e. a thumbnail for the photo, the lat/lon for the location, etc)
I was considering a set of classes that all extend an abstract FormElement class, and would have static elements for each of the above extra pieces of data. (An additional bump for this solution is how much of a pain Resources are in a static context.)
How can I make this as clean and maintainable as possible? I'd really not enjoy editing five different files to add a new type of element to this form. (Mostly because I can guarantee I'll miss one and spend hours chasing down unbugs.)
A few tips...
Unit tests will prevent "unbugs" :)
When each Activity has obtained the information it needs from the user, call Activity#setResult() with an Intent that contains your per-type data. Intent supports all the Bundle methods, so you can set different types of data as needed.
To support #2, make sure you're using Activity#startActivityForResult(Intent,int) to launch it, and listen for the result in Activity#onActivityResult(int,Intent)
I would probably maintain the list of available "element" types for use with the SpinnerAdapter (e.g., ArrayList<Class<? extends AbstractFormElement>>, and invoke static methods like .getDisplayName(), .getActivityClass(), etc, in the Adapter's getView() method, in order to determine what to display and what Activity to launch.
In this way, your list would actually contain things like { MyPhotoElement.class, MyTextElement.class, MyDateElement.class, ...}).
As each element is added to the form, add it to an ArrayList<AbstractFormElement>, which will be used to back another Adapter for a ListView. That adapter will dispatch the inflation of a custom view layout, as well as the creation of a ViewHolder, based on what type of object it is -- that will require that each distinct AbstractFormElement will have its own "view type", according to the Adapter. See BaseAdapter#getItemViewType(int) and related getViewTypeCount().
It's worth noting that these will need distinct view types only if one cannot be converted to the other... For example, if you have two "Elements" that only need to display a string of text in the list, those can both share a "text-only" view type. Likewise, two elements that only display a photo, or can easily convert one to the other (e.g., an icon with a caption, vs a photo thumbnail with no caption), can share a single "image-plus-caption" view type.
With the above in mind, you actually would end up having to modify different files to add a new type (well, I guess technically you could have them all in one file, as inner classes, but there's really no good argument for doing that), but if you've done your interface API correctly, and follow good OO practices, and implement good unit tests, you'll considerably reduce the amount of effort required to find bugs -- simply because most of the things involved in adding a new type would actually force a compiler error if you do it incorrectly. Add to that the fact that a proper unit test suite will be able to programmatically add all possible types, and ensure that everything displays properly, and you should have a pretty streamlined process for easy extensibility :)
It sounds like a lot of work, and it might seem tedious and verbose at first... But the end result is actually much more maintainable, especially if your list of element types is going to be fairly extensive.

Categories

Resources