Android/Kotlin Material Button checkedId, what is it? - android

Wonder if anyone can tell me what exactly the checkedId of a Material Button is? The documentation is not very clear. For instance:
button.addOnButtonCheckedListener { group, checkedId, isChecked -> stuff e.g. Toast}
For the checkedId, I get a long integer. For instance, I have a button with XML ID android:id="#+id/paletteF", and when I click it the checkedId returns as 2131362134. I don't see an obvious correlation here, if there is one... Is it an address??

First it is useful to understand that Android has a generated class called R which contains identifiers for all of your XML declared resources. So every time you declare #+id/newId in an XML file, a new static field (an integer) is created in the R class representing that ID, namely R.id.newID.
So in answer to your question, the checkedId refers to the same ID that android:id="#+id/paletteF" does and to check them programmatically you would would something like:
checkedId == R.id.paletteF
Just as a side note, this was an oversimplification of the R class but if you're interested there's plenty of information out there, some of it on this forum.

Related

Inverse Boolean using Two Way Databinding

Using two-way Android Databinding, is it possible to have a generic inverse boolean converter? For example, I would like to do something like this:
<Switch android:checked="#={!viewModel.myBoolean}" />
When I run this in Android, the switch just rapidly fires back and forth. I tried to create a two way binding app:inverseChecked following some examples from George Mount, but I was not successful (just kept getting error stating cannot find event 'inverseCheckedAttrChanged' on View type 'android.widget.Switch').
As a comparison, using Aurelia this just works as you would expect for two way binding. In WPF, probably the first converter you make is some sort of InverseBooleanConverter to easily tackle these sorts of things. So, am assuming I am just missing something obvious here.
I actually didn't expect it to work at all. I assume, it's switching back and forth all the time, because the bindings don't apply inverse function of your binding expression.
That said, I tested the behavior with the current data binding library version and checked the generated sources. With the simple example of android:checked these show notes how the inverse should look like and apply it appropriately.
Also George Mount wrote a Blog post about it a short while ago: https://medium.com/google-developers/android-data-binding-inverse-functions-95aab4b11873
If you try to implement an app:inverseChecked, you'd also have to implement a #BindingAdapter("inverseChecked") as setter, #InverseBindingAdapter(attribute="inverseChecked") as getter and #BindingAdapter("inverseCheckedAttrChanged") for setting up the change listener.
The latter could look like the following:
#BindingAdapter("inverseCheckedAttrChanged")
public static void setupInverseCheckedAttrChanged(Switch view, InverseBindingListener listener) {
OnCheckedChangeListener newListener = null;
if (listener != null) {
newListener = (v,b) -> listener.onChange();
}
view.setOnCheckedChangeListener(newListener);
}

Android - Set my own unique integer id (not in resources) to many views created programmatically

I want to give ids to multiple views created programmatically and each id to be a specific integer based on my own logic. Consider the following example:
I have M colors defined in a sequential way, e.g. using enum, or using an array to put M color values. (Which implementation/structure to use is part of the puzzle and suggestions need to be provided for this as well, in order to achieve the final goal described below.)
Create N instances of a custom Class and store them in a sequential way too (e.g. an array of N elements). This custom Class will just have a member mColor where a color for the specific instance will be stored.
Create (programmatically always) N RadioGroups with M RadioButtons for each RadioGroup.
The goal is when user clicks the j-th RadioButton of the i-th RadioGroup, then the i-th instance will use as background color the j-th color.
So, I would like to do something like this when OnCheckedChanged event occurs for a RadioGroup:
public void onCheckedChanged(RadioGroup group, int checkedId) {
int i = group.getId();
/*j variable is not actually needed here, but is used for concistency
with the description above.*/
int j = checkedId;
/*assume for simplicity that an array of N elements is used to store
the N CustomCLass instances and an array of M elements is used for
colors*/
customClassArray[i].setmColor(colorsArray[j]);
}
From the above, I think it is necessary that specific ids for the programmatically created RadioGroups and RadioButtons need to be set. If there is a way for this to be done, then code will be clear, optimized and no switch statements will be needed for N RadioGroups and M RadioButtons (for which, in any case, I have no clue about how it could be implemented too).
Which is the best way to achieve this, firstly with efficiency in mind and secondly, with clear code in mind?
Thank you in advance for any suggestions.
Edit: For clarification, I have read about setting my own ids by using View.setId(), but there are many resources on the web which are against this hardcoded approach (and I also vote against this if there is another way) and many of them suggest using xml resource to put your ids. However, as I said earlier, I think this is not what I want in order to achieve my goal.
Example links suggesting this approach: https://code.google.com/p/android/issues/detail?id=75081 or also How to set Id of dynamic created layout?.
Also, this approach is the suggested one in the android developer documentation: http://developer.android.com/guide/topics/resources/more-resources.html#Id
Lastly, I have also read this: What is the main purpose of setTag() getTag() methods of View? which explains the purpose of Tags and the use of setTag()/getTag() methods. This may be the best approach I've found so far for what I need. However, it surely introduces more complicated, unsupportable code. In any case, the right way, I think, has to be connected with ids, whose purpose is to uniquely identify views, rather than tags.
As you are creating RadioGroups and RadioButtons from java, I suggest to create a map and use radiobutton reference as key and instance-color combination as value. assign a single checkChangedListener to all your radioButtons and process the event as follows
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
colorInstanceCombo = map.get(buttonView);
//use colorInstanceCombo to do your work
}
assigning ids dynamically can cause problems as id is an integer and your assigned ids may cause conflict with system assigned ids to other components.

how can i set RadioGroup unchecked by default in android?

I am doing an app to conduct simple quiz.I have given the answers are multiple choice using RadioGroup. So on loading each question how can I set RadioGroup unchecked by default ?
Just set the checked Property in your XML for every RadioButton to false:
android:checked="false"
That should solve the issue.
Have you looked on the android developer guide?
http://developer.android.com/reference/android/widget/RadioGroup.html
Intially, all of the radio buttons are unchecked.
Although you can do this in code with the clearCheck() method
Clears the selection. When the selection is cleared, no radio button in this group is selected and getCheckedRadioButtonId() returns null.
Perhaps your problem might be a different from my understanding. Perhaps explain more about how you are loading questions and so forth.
Try
RadioGroup.check(0)
0 is an id which will nevere be generated by adt
upd: from source of RadioGroup
public class RadioGroup extends LinearLayout {
// holds the checked id; the selection is empty by default
private int mCheckedId = -1;
...

MenuItem#getTag()

On subclasses of View there is a getTag() method, which returns the android:tag attribute's value from .xml.
I would like the same for a MenuItem... is it okay to just cast it to a View?
Because item elements also allow a tag attribute in .xml...
Update: My goal with this is setting a tag in .xml, i.e. "notranslate", and querying it at runtime (we localize by hand at runtime, don't ask...)
It is always alright to cast, however, casting any Interface cannot be checked at compile time, only runtime. This is normally the reason many do not recommend casting an Interface that you have no control over. Having the proper error checking code is the best way to insure that such a cast does not break your code.
For the casting, it doesn't really matter whether the MenuItem is an Interface or a View, but the object it references must be one of View's subclasses, if not a View itself. If you are going to cast it, try the cast and catch a ClassCastException just in case as this is the error that will be thrown in runtime.
Another option is that since the MenuItem is simply an interface, you can easily just create a View subclass that utilizes MenuItem allowing you to do the cast. If you are doing a custom ContextMenu as many launchers do, then chances are your answer is nearly complete.
Hope this helps,
FuzzicalLogic
MenuItem is an interface. Any class can implement this interface and so it will not always be safe to cast the MenuItem to a View. You can use the "instanceOf" operator to test to see if the object that implements the MenuItem interface is indeed a View or not.
I understand that you want to define a flag in the XML definition of the menu and then at run time interrogate that flag to make a programmatic decision.
The Menu Resource Documentation records what attributes can be set in the XML. You can consider using (abusing) one of those settings such as the "android:alphabeticShortcut" to encode the flag and use the MenuItem::getAlphabeticShortcut() method to get the value. This does not require casting - it just uses the existing fields in the MenuItem XML construct/class for your own purposes.
Perhaps a less hacky way to do this is to keep a simple table in a separate assets file that lists the menu item identifiers and the special behavior associated with that identifier such as to translate or not to translate.
Alternatively create a simple class that has a table with this configuration information hard coded using the logical "#[+][package:]id/resource_name" resource identifier as the keys to the table. While this doesn't keep it all in one place (in the XML) it does it in a manner that is not encoding information in unused attributes, or relying on the ids not changing. The "table" could be implemented as a static method with an embedded switch statement allowing code such as "if (TranslationTable.shouldTranslate(menuItem.getItemId())) { do translation }"
I had a similar problem in that I wanted to associate some arbitrary data with each menu item so that I could handle menu items in a generic way without having to use hardcoded checks for individual item ids in code.
What I did was for a particular menu item (e.g. #+id/foo) There was an a TypedArray that was defined using the same name as the menu item ID. You could do this with other types of resources as well.
So to do the association, you get the resouce entry name (foo in my example) and then use that to look up the id of the other resource of a different type (#array/foo in my example).
In my handler for menu I had code like this:
Resources resources = getResources();
String name = resources.getResourceEntryName(item.getItemId());
int id = resources.getIdentifier(name, "array", "com.example");
if(id != 0)
{
TypedArray data = resources.obtainTypedArray(id);
// Use the typed array to get associated data
}
EDIT:
Actually it is even easier than that. There is nothing special about the ids on menu items other than you don't want multiple menu items with the same id. The id does not have to be of the form #+id/foo. It can actually also refer to other resources. So in my example above, instead of having the menu have an id of #+id/foo and using the resource manager to use that to find #array/foo, I changed to actually have the menu item have the id of #array/foo.
Now in my onOptionsItemSelected I have this:
Resources resources = getResources();
if("array".equals(resources.getResourceTypeName(item.getItemId())))
{
TypedArray data = resources.obtainTypedArray(item.getItemId());
// Use the typed array
}

Android and storing/loading preferences for resources - how to achieve consistency?

I'm writing an application and need some help with consistently storing and loading preferences related to certain resources. Let me give an example.
Suppose I have 10 spinners. They all have the same functionality but different meaning. Because they have the same functionality, I can bind them to the same onItemSelectedListener, which will then deal with the selected value.
Well, what if I also want to store the preferences for each spinner? For example, when a spinner value is selected, I'd store a key "spinner SOMETHING" = SOME_DATA.
The problem is - what should this SOMETHING be? The listener has the following signature:
public void onItemSelected(AdapterView parent, View v, int position, long id)
The position and id are not helpful here as they're set relative to each spinner.
However, the parent, which in this case is the spinner itself, should have all the information I need. I tried using parent.getId() to get a resource ID of each spinner and store the preference using a key "spinner ID" but apparently these resource IDs change when you add more resources into your app, so my settings would get reset because the keys change.
What should I do here? I can't seem to find a simple parent.getName() function of some sort that would return me a consistent name of each spinner.
Thank you.
The getId is the only thing I know of that has a unique reference to the View, but as you say, a view might not have the same Id in the next build of your app.
The best human-readable identifier available out of the box would be getPrompt, which would simply show you whatever you have set as the spinners prompt. It should be an OK identifier, but it is of course also prone to breakage if you manually change your prompt texts.
The most break-proof way, then, is to specify an identifier in the general container - tag - that every View contains.
String myIdentifier = (String) parent.getTag();
If you're already using the tag for something else, the 1.6+ APIs include the ability to specify several tags, and access them via index. If you need to support older API versions, you could always set the tag to a wrapper object that contains both the identifier, and your original tag.

Categories

Resources