Let's get straight to code.
Activity Code, onCreate method
setContentView(R.layout.main);
View main_view = findViewById(R.id.main_view);
View view_flipper = main_view.findViewById(R.id.vf);
View first_tab = view_flipper.findViewById(R.id.prev_pane);
The main.xml layout code:
<ViewFlipper android:id="#+id/vf"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<include android:id="#+id/prev_pane" layout="#layout/vf_inner" />
<include android:id="#+id/cur_pane" layout="#layout/vf_inner" />
<include android:id="#+id/next_pane" layout="#layout/vf_inner" />
</ViewFlipper>
The problem!
Main view is correctly found, so is ViewFlipper, yet prev_pane or cur_pane or next_pane are not found, a null pointer is returned. Any ideas why?
This activity is called through a tab by using an Intent. All references are resolved correctly except id's on includes
When I inspect variables, I find the contents of vf_inner layout in mChildren
That's because <include /> tags are not an actual view in your UI hierachy.
They are more of a copy&paste instruction for the android tools.
If you want to find the panes at runtime, add the IDs to the root elements of the included layouts. This way they can be found via findViewById().
One thing you can do is wrap the <include> statements inside a parent layout (which is still a child of your main parent layout). Give those views different ids so you can findViewById each of them separately.
Related
In the onCreateView() method of a fragment, I am trying to initialize a CustomView with behavior similar to a fab button.
Upon clicking on this custom view an animation is supposed to run which utilizes an empty RelativeLayout which is present in the parent ViewGroup in the Fragment.
I am passing this ViewGroup to the CustomView in a constructor.
When I try to create a reference to the empty RelativeLayout by calling ViewGroup.findViewById(R.id.target), the reference create holds null ultimately causing a NullPointerException upon animation
However, if I use ViewGroup.getChildAt(1) to create the reference, the animation works just fine.
By using watchers, I found that the id of the ViewGroup.getChildAt(1) is different from the R.id.target which has been assigned to it via xml.
What sorcery is this?
I have browsed already for a few days to be able to find a question which describes this situation.
Extra Information:
We recently switched from support libraries to androidX.
fragment.xml
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/top_container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout>
<!-- Other views -->
</LinearLayout>
<!-- This is the layout i am trying to instantiate -->
<RelativeLayout
android:id="#+id/target"/>
</RelativeLayout>
In my Android app I have a layout for an activity that presents a choice.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/wrapper"
android:orientation="vertical">
<include layout="#layout/choices" />
<include layout="#layout/choice_one" />
<include layout="#layout/choice_two" />
</LinearLayout>
In layout/choices the user sees two buttons. One button shows layout/choice_one and the other shows layout/choice_two. (The parent in layout/choice_one and layout/choice_two is initially set to android:visibility=gone.)
So when a user chooses either choice_one or choice_two, essentially I'm setting the visibility to VISIBLE. That works great.
The issue is that inside of both choice_one and choice_two I have shared elements with the same ID. For example I have a TextView with ID header. (I did this because I figured only one of those layouts would be visible and they use the same things.)
The issue is that I use Butterknife, and it seems like if I Bind header, when I set the visibility on choice_one or choice_two, I have a 50/50 chance of correctly calling header.setText("Blah") on the appropriate header element.
I'm sure I can get around this by giving unique IDs to all elements in the layouts or ditching Butterknife and using findViewById instead. But is there another way I can target a shared ID inside of a layout without ditching Butterknife or my shared layouts?
I figured this out. (Writing it out helped, so I'll keep it here in case someone else stumbles upon it.) Instead of using include in xml and inflating layouts there, I just subclassed ViewGroup for my two layouts and added them to wrapper:
ChoiceOne choiceOne = new ChoiceOne();
wrapper.addView(choiceOne);
So I have included a layout in my xml file but I want to get that included layout in my code and then add to it.
You get Views using findViewByID()
But I don't think that can be used in this case. This is the part of my XML that I am referring
<include
android:layout_width="350dp"
android:layout_height="wrap_content"
layout="#layout/progress_bar"
android:layout_marginTop="20dp"
android:layout_below="#+id/instructions_label"
android:layout_centerHorizontal="true" />
You get views using 'findViewByID'
But i don't think that can be used in this case
Sure you can. Give your included layout an id
<include layout=#layout/someLayout
android:id="#+id/myId"
.../>
then retrieve it with that id
View myLayout = (View) findViewById(R.id.myId);
then you can use that reference to get sub views from someLayout.xml
Button btn = (Button) myLayout.findViewById(R.id.btn1)
assuming someLayout.xml has a Button with id of btn1
You can still add id to your included layout and get it with it's id. Or You can give ID to the parent element in that layout (inside it) and you can still call it with that id as well.
<include android:id=”#+id/news_title”
android:layout_width=”match_parent”
android:layout_height=”match_parent”
layout=”#layout/title”/>
I have a layout as below:
Let's name it my_layout.xml:-
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:background="#19396a"
/>
<TextView
android:id="#+id/textView2"
android:layout_weight="1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textSize="20sp"
android:textColor="#ffffff"
android:background="#19396a"
/>
</LinearLayout>
<ListView
android:id="#+id/uilistView"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
</LinearLayout>
In my activity I have a method in which I initialize all the UI elements i.e I do mapping of activity UI variables to layout.
Assume, the method is as below:-
//used to initialize UI elements
//called in oncreate() method
public void initializeUIelements() {
......
activity_listView = (ListView) findViewById(R.id.uilistView);
}
Here, activity_listView is a class level variable of type ListView
In my project, I have res\layout as well as res\layout-land and my_layout.xml exists in both the folders.
But sometimes during activity restart/when it's created I get a NullpointerException while initializing activity_listView that comes from R.java.
I know:
We get NullpointerException similar to what I am asking when an
element does not exist in any of the layout folder(i.e it exists in layout-land but does not exist in layout folder).
But here,the element exists in both folders and even though I get this inconsistent error
i.e. I am not able to produce it always but sometimes it starts coming.
So,please help me in analyzing as what may be the reasons when we get this error apart from the one mentioned by me above.
Thanks in advance.
If you could provide a more specific example, it might be easier to debug the exact problem. A few reasons why your View might be null:
The layout you've set as the content view does not include a view with this id:
If you reference a View that exists in the R file (a file that holds references to all elements within the res folder), say uilistview, in an Activity where you are not setting it's layout container as the content view (in this case this would be my_layout.xml), you will not get an error in Eclipse or whatever IDE you are using. Android will look for a View with this id within the layout, and if it can't find it, it will return a null value.
You call findViewById too early
You must use the method setContentView(R.layout.some_layout) before you try to access any of the elements with findViewById(). Logically, it makes sense - you need to tell Android where it should look where it's find an element
Looking for an element inside an inflated View
This is similar to the first, but it's common. If you've inflated a view and then want to manipulate a View inside the inflated View, you must instruct Android to look in the right place. For example:
RLayoutInflater layoutInflater = (LayoutInflater)this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View smallerView = layoutInflater.inflate(R.layout.mylayout);
If you want to reference something within mylayout.xml, you would need to use this:
TextView text = (TextView) smallerView.findViewById(R.id.text_view);
rather than:
TextView text = (TextView) findViewById(R.id.text_view);
The first indicates to look into the inflated view by placing the findViewById method on the inflated view, while the second one applies it to the current View of the Activity, which will cause a null value to be return.
Clean your project
This is the most frustrating answer, because this is not your fault. Sometimes the R.java class messes up and causes wrong references to id's while it is being compiled/built. Try cleaning your project and correcting the wrong references by looking for Project -> Clean in the main bar of Eclipse (or the IDE you're using).
below is a snippet copied from And Dev.
<com.android.launcher.Workspace
android:id="#+id/workspace"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
launcher:defaultScreen="1">
<include android:id="#+id/cell1" layout="#layout/workspace_screen" />
<include android:id="#+id/cell2" layout="#layout/workspace_screen" />
<include android:id="#+id/cell3" layout="#layout/workspace_screen" />
</com.android.launcher.Workspace>
Here they demonstrate how to overwrite the ID of the root View or ViewGroup of the included layout.
My question is, is it also possible to overwrite the children's ID through XML?
If not, how am I supposed to link cell2 or cell3's children Views if their IDs were already preset? HierarchyViewer tells me that all included children Views' attributes do not change, including the ID attribute, thus generating multiple Views with the SAME ID.
There is nothing wrong in matching id's. How else would you implement list view items for example?
You can access children views you need by using nested findViewById().
findViewById(cell3).findViewById(child_View_id)