What is android.R.id.message? - android

I found two SO threads that tell how to center title and message in an AlertDialog object and faked my way through writing a method that I hope to be able to call to center any AlertDialog. It worked fine on a phone and a tablet to display even multi-line messages, both with and without '\n's.
public void showCenteredInfoDialog(TextView _title, TextView _message) {
_title.setGravity(Gravity.CENTER);
LayoutInflater inflater = (LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setPositiveButton("OK", null);
builder.setCustomTitle(_title);
builder.setMessage(_message.getText());
AlertDialog dialog = builder.show();
TextView messageView = (TextView)
dialog.findViewById(android.R.id.message);
messageView.setGravity(Gravity.CENTER);
}
I did a considerable amount of customizing--i.e., I have SOME clue about what I found and did--but one line has left me wondering:
TextView messageView = (TextView) dialog.findViewById(android.R.id.message);
What is android.R.id.message?
Here is all the documentation I could find about it:
android.R.id
public static final int message = 16908299
Where can I find more documentation for the Android.R.id objects (and more)? This seems to be a possible gold mine.

In Android, views contained in layouts generally (though not always) have an id. The purpose of this id is to be able to identify particular views, for example:
Button button = (Button)layout.findViewById(R.id.button1);
button.setOnClickListener(...);
When you create a layout XML file, you're generally creating new ids for your views, the syntax is:
<Button
android:id="#+id/button1"
...
This will create an integer value in your project's R file (R.id.button1).
android.R.id, on the other hand, contains the ids of views that are either defined in the Android framework, or must be somehow referenced by it.
In your example, the AlertDialog.Builder creates a TextView with a fixed id, android.R.id.message. That way, you can take the view hierarchy returned by show(), and find the TextView inside it.
You can take a look at the full list of predefined ids in the documentation, however this list is not very informative in itself. The ids are generally mentioned in the documentation for each particular feature that uses them.
As an example of the other use case (marking your own view with a predefined android id), when using a ListFragment, if you provide a custom layout then you must include a ListView with id R.id.list. This is because the ListFragment class inspects the inflated layout to look for this widget. See the documentation:
ListFragment has a default layout that consists of a single list
view. However, if you desire, you can customize the fragment layout by
returning your own view hierarchy from onCreateView(LayoutInflater,
ViewGroup, Bundle). To do this, your view hierarchy must contain a
ListView object with the id "#android:id/list" (or list if it's in
code)
Optionally, your view hierarchy can contain another view object of any
type to display when the list view is empty. This "empty list"
notifier must have an id "android:empty".

android.R.id.message refers to the Resource with an id named message.
For example, the TextView here:
<AbsoluteLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<Button
android:id="#+id/backbutton"
android:text="Back"
android:layout_x="10px"
android:layout_y="5px"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/message"
android:layout_x="10px"
android:layout_y="110px"
android:text="First Name"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</AbsoluteLayout>
Excuse me when I tell you that if you didn't know that, you really should read the Android Training Guide: http://developer.android.com/training/index.html

#matiash 's answer gives some good insight.
In the simplest terms, suppose you were providing a custom layout for a dialog, you would just access a view using R.id.viewId - an id which you defined in the custom xml layout.
android.R.id.message will let you access views that are predefined by android. Such as in your case, you're using an AlertDialog with a predefined layout. So, using the particular id you'll be able to access the TextView where you can set a message in the AlertDialog.

Related

android studio: unique identifier for each element

I have an android application where not all elements have unique ID's. For example, two TextViews are each called "itemButton" and are on the same screen. I want to give every element a unique identifier by setting a tag on each element.
My current solution is to iterate through every element in the application and set the tag for each element. This is a very expensive solution because I have many elements. Is there another property you know of that would help identify an element other than setting a unique tag for each element?
View IDs have no special requirement that they be unique. However, you will run into difficulties if you use non-unique IDs on a single screen.
The two most common issues you will face if you use non-unique IDs are (1) failure of the system to automatically save instance state for the view and (2) findViewById() returning the "wrong" view.
Activity.findViewById() will search the view hierarchy for the first view it finds with the matching ID. If you have two views in your hierarchy with the same ID, that means you won't be able to find the second one using this method. However, you can use View.findViewById() instead.
View.findViewById() will search the view hierarchy starting from the view you're invoking the method on, which means that you can differentiate between two views with the same ID as long as they have different parents.
In your case, I suspect you can do something like the following:
View parentOne = findViewById(R.id.parentOne);
View childOne = parentOne.findViewById(R.id.someIdBeingReused);
View parentTwo = findViewById(R.id.parentTwo);
View childTwo = parentTwo.findViewById(R.id.someIdBeingReused);
I don't think you got it right, you should assign unique ids to your elements by using in each of them: android:id="#+id/YOUR_ID", then you can find them with findViewById(R.id.YOUR_ID), so, if you have two text views, lets say, username and password, you set the ids on each:
<TextView android:id="#+id/username" .../>
<TextView android:id="#+id/password" .../>
and then you get them in your activity or fragment with:
TextView txtUsername = findViewById(R.id.username);
TextView txtPassword = findViewById(R.id.password);

Querying root and indirect sibling views in Android ListView

I have a ListView to show a list of articles. Each ListView element is a LinearLayout. On each article, there is a TextView button to edit the title (another TextView). However, the button and the title are not under a direct parent (and actually not at the same level).
A sample structure is shown below:
<LinearLayout>
<LinearLayout
android:id="#+id/title_zone">
<TextView
android:id="#+id/title">
<ImageView
android:id="#+id/icon_popularity">
</LinearLayout><!--end of title_zone-->
<LinearLayout
android:id="#+id/content_zone">
...
</LinearLayout><!--end of content_zone-->
<LinearLayout
android:id="#+id/button_zone">
<LinearLayout
android:id="#+id/author_buttons">
<TextView
android:id="#+id/edit_title_button"
android:onClick="editTitle">
...
</LinearLayout><!--end of author_buttons-->
</LinearLayout><!--end of button_zone-->
</LinearLayout>
I write a SimpleAdapter to apply data to views, so the root LinearLayout will have a tag of the article ID. When editTitle() is called, it needs to find its parent's parent's parent to the root. And after new title is entered, a message will send to server containing new title and the article ID. Also, the title text will be changed visually, which means I need to find the title TextView based on the root.
The problem is that this querying root process is tightly coupled to the UI structure. If I changed the structure in XML, I need to pay attention to change the querying code in Java. (The querying title view is relatively easy, if the root is obtained.)
Is there a more maintainable way to implement my purpose?
OK. A solution that works for my situation is as follows:
In the customized simple adapter for this ListView, set the article ID as the edit_title_button's tag. And set the article ID composed string as the root LinearLayout's tag, e.g., "a_123" if the article ID is 123.
So, when editTitle(View v) is called, we can get the story ID by v.getTag(). Of course, we can also get the ListView by its ID (e.g., ListView list=findViewById(R.id.my_list_view);). Then, we can simply get the root LinearLayout by list.findViewWithTag("a_123").
Since the root LinearLayout is obtained without knowing the UI structure, following codes are easy to maintain.

Is it possible to generate a list of `EditText` pairs that automatically retain their state?

I am running into a very frustrating series of problems. I would like a definitive solution; thus, I will award bounty for this question.
Requirements
Generate a list of pairs of EditText views that automatically retain their values on orientation change (screen rotation).
The number of EditText pairs is determined at runtime.
Failing method: Use a ListView
Use a ListView that has an ArrayAdapter. The array adapter uses a layout to generate each pair of TextView views. The XML for a ListView item might appear as:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<EditText
android:id="#+id/edit_first"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<EditText
android:id="#+id/edit_second"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
The ArrayAdapter would simply inflate the layout for each view.
#Override
public View getView(int position, View convertView, ViewGroup parent)
{
LayoutInflater inflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.listview_pair, parent, false);
The values entered into the EditText are not retained on orientation change. Since the EditText views are instantiated through the ArrayAdapter, the Android runtime has no way of automatically pre-populating the EditText views with their last state before rotation. This means we must save/restore user-input manually -- failing requirement #1.
Failing method: Use a TableLayout and TableRows
Instead of using a ListView, we can inflate one TableRow layout for each EditText pair and attach it to the TableLayout. Since we only know the number of pairs at runtime (per requirement #2) we must instantiate the layout programmatically. Something like:
for (int i = 0; i < numPairs; ++i)
{
TableRow row = (TableRow) View.inflate(this, R.layout.tablerow_pair, null);
table.addView(row);
}
This also fails to retain state on orientation change. Each pair of EditText views has the same Ids as all other EditText pairs in the ListView. This happens because we instantiate the same layout for each item in the list; thus, they all have the same Ids. On rotation, Android will give every pair of EditText values the same values since they share the same Id.
Recapitulation
So, is there a way to create a list of EditText pairs that retain their state automatically upon orientation change? It seems like there must be a way, yet researching this question is difficult because it's a fairly specialized use case. I would be glad to reward some bounty for somebody who can give me a nice explanation of this situation.
You can use setId() with your EditText widgets, whether you create those widgets via their constructors or via layout inflation (per your second strategy). Use generateViewId() to get distinct view IDs.

User Interface Design in Android

I want to design the layouts programatically that means without the xml file as per project requirement.
But the terms used programatically is completely different from xml file.Is their any useful tutorial to learn programatically that means without xml file. guide me!
you can create any view you want
a linear layout
LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.FILL_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
A Text View
final TextView tv = new TextView(this);
tv.setBackgroundColor(0xFFFF00FF);
tv.setTextColor(0xFF000000);
tv.setTypeface(null, Typeface.BOLD);
tv.setText("Where is Fred?");
tv.setGravity(Gravity.CENTER_HORIZONTAL);
and anything else.
Source
I advise you to spend some time learning about the View class and its popular subclasses such as LinearLayout, RelativeLayout, and so on. (Also, spend a bit of time looking at Drawables.)
When you're creating a layout using XML, you're using XML to define a hierarchy of View objects which, at runtime, are "inflated" into a real hierarchy of View objects that the XML layout file describes. For example, your first XML layout file might be a simple LinearLayout that contains a TextView (note I'm simplifying it for brevity):
<LinearLayout ... >
<TextView ... />
</LinearLayout>
In your Activity you would use this layout using setContentView().
All that XML file is doing is providing a specification, if you like, about the View structure that the system needs to build (or inflate) for you. The end result is that there will be a real LinearLayout object (which is a subclass of View) that has a reference a child TextView (again a subclass of View) together with suitable layout parameters.
To do the above programmatically (i.e. by creating instances of objects and using their methods, rather than inflating from XML) you might do something like (again simplified):
LinearLayout container = new LinearLayout(this);
TextView tv = new TextView(this);
tv.setText("hello");
container.addChild(tv); // Simple example - usually you'd specify layout parameters
setContentView(container);
The basic point I'm making is that, in really simple terms, a layout XML file can be thought of as a kind of 'script' that you can use to tell the system how to create a hierarchy of Views. You can create exactly the same result by programmatically creating instances of View objects and calling appropriate methods on them. Whichever route you take, the end result is the same: a bunch of View objects in memory that represent a View hierarchy.
What you will find is that XML layout attribute names aren't necessarily the same as the corresponding method names, but you can use the relevant API documentation to see what corresponding XML attribute strings are for given methods. For instance, the API documentation for LinearLayout details all of the methods as well as the XML attributes.

Creating table rows programmatically while defining layout in XML

I am trying to add rows to a TableLayout that I define in an XML file. The XML file contains a header row for the table.
I can add new rows quite well using info from various tutorials but the code required for setting up the layout for the new rows is a horrendous mess and it seems like a pain in the ass to maintain whenever the layout for the header row changes.
Is it possible to create new rows to a TableLayout while still defining the row layout in XML? For example define a template row in XML, obtain a handle to it in code and then clone the template whenever I need it.
Or is the right way to do this somehow completely different?
Your proposed approach will work fine and it more or less matches the common pattern used when populating ListView items.
Define a layout that contains a single row. Obtain a LayoutInflater by using LayoutInflater.from(myActivity). Use this inflater to create new rows using your layout like a template. Generally you will want to use the 3-argument form of LayoutInflater#inflate passing false for the third attachToRoot parameter.
Let's say you wanted to use a template layout with a label and a button in each item. It might look something like this: (Though yours would define your table rows instead.)
res/layout/item.xml:
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:id="#+id/my_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<Button android:id="#+id/my_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Then at the point where you inflate:
// Inflate the layout and find the component views to configure
final View item = inflater.inflate(R.layout.item, parentView, false);
final TextView label = (TextView) item.findViewById(R.id.my_label);
final Button button = (Button) item.findViewById(R.id.my_button);
// Configure component views
label.setText(labelText);
button.setText(buttonText);
button.setOnClickListener(buttonClickListener);
// Add to parent
parentView.addView(item);

Categories

Resources