Why do I keep getting a null reference to my LinearLayout? - android

I have a layout called view.xml which contains a View called view_related. Basically, in my dictionary app, if there are related words to an entry, I will replace view_related with a LinearLayout that contains a header "Related entries" and a bunch of TextViews representing every related word.
I keep getting a NullPointerException everytime I'm adding a TextView to the LinearLayout in my Activity's onCreate() method, and I don't understand why though my code looks pretty straightforward.
view.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TextView android:id="#+id/view_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="12pt"
android:textColor="#fff"
android:textStyle="bold"
android:background="#990011"
android:padding="10dp"
android:text="lalala word"
/>
<ScrollView android:id="#+id/view_description"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/view_header">
<LinearLayout android:id="#+id/view_description_content"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="20dp"
android:text="#string/demo_definition"
/>
<!-- THIS WILL BE REPLACED -->
<View android:id="#+id/view_related"
android:layout_width="match_parent"
android:layout_height="wrap_content"></View>
</LinearLayout>
</ScrollView>
</RelativeLayout>
view_related.xml, the LinearLayout that will replace the View element in view.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/view_related_entries"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView android:id="#+id/view_related_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="5dp"
android:textColor="#fff"
android:textStyle="bold"
android:textSize="7pt"
android:background="#000"
android:text="Related entries"
/>
<LinearLayout android:id="#+id/view_related_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
</LinearLayout>
</LinearLayout>
And finally, the onCreate method, which for now assumes the related entries are "Hello" and "Goodbye:"
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list);
TextView tv = new TextView(this);
tv.setText("Hello");
ll.addView(tv); // NULL POINTER EXCEPTION
tv = new TextView(this);
tv.setText("Goodbye");
ll.addView(tv);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View view = findViewById(R.id.view_related);
ViewGroup parent = (ViewGroup) view.getParent();
int index = parent.indexOfChild(view);
parent.removeView(view);
View llview = li.inflate(R.id.view_related_entries, parent, false);
parent.addView(llview, index);
}

setContentView(R.layout.view);
LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list);
The function findViewById only finds views that are actually set. Your current setContentView does not set an xml that has the id you are looking for in it, so the first line I quoted will not result in anything.
You should either load the correct XML, or inflate the view you are looking for with an inflater

the line (LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list);) will search for view_related_list in view.xml, as in the line before that is the view you are using..
You need to inflate view_related.xml first and then get the view from it..

You're doing a lot of wrong things in your code. First you search for a LinearLayout that isn't in the current layout and also isn't in any inflated layout at that moment. Second, you try to inflate an id reference instead of a layout reference. Last, you should use another approach for what you're trying to do. Your code should be(from what I understood):
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.view);
LayoutInflater li = (LayoutInflater) getSystemService(LAYOUT_INFLATER_SERVICE);
View view = findViewById(R.id.view_related);
ViewGroup parent = (ViewGroup) view.getParent();
int index = parent.indexOfChild(view);
parent.removeView(view);
View llview = li.inflate(R.layout.view_related, parent, false); // is view_related the name of the extra layout file?
parent.addView(llview, index);
LinearLayout ll = (LinearLayout) findViewById(R.id.view_related_list); // or search for it in llview, llview.findViewById(R.id.view_related_list);
TextView tv = new TextView(this);
tv.setText("Hello");
ll.addView(tv); // NULL POINTER EXCEPTION
tv = new TextView(this);
tv.setText("Goodbye");
ll.addView(tv);
}
This is a situation when you should use a ViewStub to add the new layout file. Although, I don't understand why don't you add the new layout file directly in the view.xml if you're going to add the layout's content in the onCreate method.

i think you need to use setContentView(R.layout.view_related); instead of setContentView(R.layout.view);
or another simple thing you can do is take the linear layout in the same layout "view" and make it invisible when not required and visible when required

You may forgetting to declare your Activity in manifest.xml

Related

Inflate layout and edit it in code

I have an android XML file with the following content:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/relLay"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<ImageView
android:id="#+id/ivQuit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/imgquit"
android:background="#null"
android:adjustViewBounds="true"
android:scaleType="fitXY"/>
<ImageButton
android:id="#+id/btnYes"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/btnyes"
android:background="#null"
android:adjustViewBounds="true"
android:scaleType="fitXY"/>
<ImageButton
android:id="#+id/btnNo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#drawable/btnno"
android:background="#null"
android:adjustViewBounds="true"
android:scaleType="fitXY"/>
</RelativeLayout>
Now I want to inflate it and then edit the ImageButtons via code. I do this as followed:
Inflate XML:
LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.quitgame, null);
Try editing an ImageButton:
ImageView imgView = (ImageView)findViewById(R.id.ivQuit);
ImageButton imgBtnYes = (ImageButton)findViewById(R.id.btnYes);
ImageButton imgBtnNo = (ImageButton)findViewById(R.id.btnNo);
RelativeLayout.LayoutParams relParams = (RelativeLayout.LayoutParams)imgBtnYes.getLayoutParams();
relParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
imgBtnYes.setLayoutParams(relParams);
However as long as the three code lines with the LayoutParams are existent the PopupWindow I create with the inflated view does not appear. It seems that the error is hidden in this line
RelativeLayout.LayoutParams relParams = (RelativeLayout.LayoutParams)imgBtnYes.getLayoutParams();
but I don't understand why.
Can anybody tell me why the PopupWindows does not appear because of this code line(s)?
Is it because of the PopupWindow itself or because of the LayoutInflater?
You have this
LayoutInflater inflater = (LayoutInflater) MainActivity.this.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.quitgame, null);
Use the View object to initialize the views.
ImageView imgView = (ImageView)layout.findViewById(R.id.ivQuit);
ImageButton imgBtnYes = (ImageButton)layout.findViewById(R.id.btnYes);
ImageButton imgBtnNo = (ImageButton)layout.findViewById(R.id.btnNo);
You can findViewById of the current view hierachy set to the activity. In your case you are inflating your layout. So use the inlfated view object to initialize your views.
You are inflating the layout with root set to null, so your layout variable (returned by the inflate method) holds the root of the inflated layout (in this case, your RelativeLayout). I didnt see the code where you are attaching the inflated layout to your activity's content (maybe the code you posted is not complete?).
Given this, your findViewById calls should return nulls.
Moreover, as far as I know and understand, unless the view is attached to a view that is already somewhere in the activity, the LayoutParams are not going to be correct as no dimensions are set (even in case they are invoked on a view that isn't null, obviously).

how to add another view using layout inflatter

I created mainLayout with two buttons
add: to add other layout
remove : to remove other layout.
<Button
android:id="#+id/btnAdd"
android:textStyle="bold"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Add View"
android:onClick="addView" />
<Button
android:id="#+id/btnRemove"
android:textStyle="bold"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:text="Remove View"
android:onClick="removeView" />
now i wrote following code to add the view
when I click on addView button
LayoutInflater inflater= (LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
view=inflater.inflate(R.layout.other_layout,null);
mainLayout.addView(view);
the view is added below the main layout.
But I want the view to add in middle of the screen not at the bottom of screen.
How can I do that?
Modify this line and put ur parent view.
view=inflater.inflate(R.layout.other_layout,PARENT_VIEW_OBJECT);
It should work
get the parentLayout like this
parentLayout=(YourParentLayout)view.findViewById(R.id.parentLayout);
then
parentLayout.addView(yourview);
You can check below code, its working fine for me
private View view = null ;
Button addbutton = null;
ViewGroup parent = null;
LayoutInflater inflater = null;
inflater= (LayoutInflater)this.getSystemService(LAYOUT_INFLATER_SERVICE);
addbutton = (Button)findViewById(R.id.btnAdd);
parent = (ViewGroup) findViewById(R.id.mainxml);
addbutton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
view = inflater.inflate(R.layout.other, null);
parent.addView(view);
}
});
I would put an empty LinearLayout placeholder at the top of your main layout where you want your view to be and add the view to that instead of the main layout.
You can adjust the placeholder first and modify it's location and looks.
<LinearLayout
android:id="#+id/placeholder"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<Button
..../>
<Button
..../>
I would look into using a ViewStub it holds a place until .inflate() is called. That way the layout isn't taking resources until it's needed.

Android - Adding layouts to a parent layout

I have 2 layout xml files: "highlights.xml" and "highlights_cell.xml".
Here is a simplified version of each. I've removed the width/height/etc and just kept the important attributes...
highlights.xml
<LinearLayout>
<uk.co.jasonfry.android.tools.ui.SwipeView android:id="#+id/swipe_view" />
<uk.co.jasonfry.android.tools.ui.PageControl android:id="#+id/page_control" />
</LinearLayout>
highlights_cell.xml
<LinearLayout android:orientation="vertical">
<LinearLayout android:id="#+id/linear_layout1" android:orientation="horizontal">
<ImageView android:id="#+id/logo" />
<LinearLayout android:id="#+id/linear_layout2" android:orientation="vertical">
<TextView android:id="#+id/title" />
<TextView android:id="#+id/subtitle" />
</LinearLayout>
</LinearLayout>
<ScrollView android:id="#+id/scroll_view">
<TextView android:id="#+id/description" />
</ScrollView>
</LinearLayout>
The idea is that I want to add several "highlights_cell" to "highlights" through a loop.
I've thrown together some test code as follows but, as it's not working, I suspect that I'm not adding the cell layouts correctly, or perhaps I shouldn't be using "inflater"...
/** Declare shared variables */
SwipeView mSwipeView;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState){
//Initialise layout and variables
super.onCreate(savedInstanceState);
setContentView(R.layout.highlights);
//Setup controls
mSwipeView = (SwipeView) findViewById(R.id.swipe_view);
LayoutInflater inflater = (LayoutInflater)getSystemService(LAYOUT_INFLATER_SERVICE);
//Loop through collection and add views
for(int i=0; i<7;i++)
{
//Create the itemView to use layout xml for each cell
View itemView = inflater.inflate(R.layout.highlights_cell, null);
//Set values within cell
TextView title = (TextView) itemView.findViewById(R.id.title);
title.setText("HELLO WORLD_" + i);
//add the itemView to main view
mSwipeView.addView(itemView);
}
}
Is this the correct way to add layouts dynamically to a parent layout?
Thanks!
It looks good except for a few things.
Because you are adding views to your custom ViewGroup, you will have to be sure that it correctly lays out and displays its children.
Also, when you add a View to a ViewGroup, you specify the LayoutParams that views can have in that ViewGroup.
Some more info about creating a custom ViewGroup
http://about-android.blogspot.com/2010/05/create-dynamic-view-group.html
custom ViewGroup example?

Android - Dynamically Add Views into View

I have a layout for a view -
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="0px"
android:orientation="vertical">
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/items_header"
style="#style/Home.ListHeader" />
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/items_none"
android:visibility="gone"
style="#style/TextBlock"
android:paddingLeft="6px" />
<ListView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:id="#+id/items_list" />
</LinearLayout>
What I want to do, is in my main activity with a layout like this
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="0px"
android:id="#+id/item_wrapper">
</LinearLayout>
I want to loop through my data model and inject multiple views consisting of the first layout into the main layout. I know I can do this by building the controls completely within the code, but I was wondering if there was a way to dynamically build the views so that I can continue using a layout instead of putting everything in code.
Use the LayoutInflater to create a view based on your layout template, and then inject it into the view where you need it.
LayoutInflater vi = (LayoutInflater) getApplicationContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View v = vi.inflate(R.layout.your_layout, null);
// fill in any details dynamically here
TextView textView = (TextView) v.findViewById(R.id.a_text_view);
textView.setText("your text");
// insert into main view
ViewGroup insertPoint = (ViewGroup) findViewById(R.id.insert_point);
insertPoint.addView(v, 0, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
You may have to adjust the index where you want to insert the view.
Additionally, set the LayoutParams according to how you would like it to fit in the parent view. e.g. with FILL_PARENT, or MATCH_PARENT, etc.
See the LayoutInflater class.
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ViewGroup parent = (ViewGroup)findViewById(R.id.where_you_want_to_insert);
inflater.inflate(R.layout.the_child_view, parent);
It looks like what you really want a ListView with a custom adapter to inflate the specified layout. Using an ArrayAdapter and the method notifyDataSetChanged() you have full control of the Views generation and rendering.
Take a look at these tutorials
http://www.softwarepassion.com/android-series-custom-listview-items-and-adapters/
http://developerlife.com/tutorials/?p=327
http://www.androidguys.com/2008/07/14/fancy-listviews-part-one/
To make #Mark Fisher's answer more clear, the inserted view being inflated should be a xml file under layout folder but without a layout (ViewGroup) like LinearLayout etc. inside. My example:
res/layout/my_view.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/i_am_id"
android:text="my name"
android:textSize="17sp"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"/>
Then, the insertion point should be a layout like LinearLayout:
res/layout/activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/aaa"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/insert_point"
android:layout_width="match_parent"
android:layout_height="match_parent">
</LinearLayout>
</RelativeLayout>
Then the code should be
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_shopping_cart);
LayoutInflater inflater = getLayoutInflater();
View view = inflater.inflate(R.layout.my_view, null);
ViewGroup main = (ViewGroup) findViewById(R.id.insert_point);
main.addView(view, 0);
}
The reason I post this very similar answer is that when I tried to implement Mark's solution, I got stuck on what xml file should I use for insert_point and the child view. I used layout in the child view firstly and it was totally not working, which took me several hours to figure out. So hope my exploration can save others' time.
// Parent layout
LinearLayout parentLayout = (LinearLayout)findViewById(R.id.layout);
// Layout inflater
LayoutInflater layoutInflater = getLayoutInflater();
View view;
for (int i = 1; i < 101; i++){
// Add the text layout to the parent layout
view = layoutInflater.inflate(R.layout.text_layout, parentLayout, false);
// In order to get the view we have to use the new view with text_layout in it
TextView textView = (TextView)view.findViewById(R.id.text);
textView.setText("Row " + i);
// Add the text view to the parent layout
parentLayout.addView(textView);
}

How to add a button control to an android xml view at runtime?

I have an android xml layout, main.xml. I would like to add controls to this layout at runtime (I would like to add a series of additional linear layouts that contain buttons controls). Can I do that and if yes, how?
Thanks
I see the error u r doing here
LinearLayout mainLayout = (LinearLayout) findViewById(R.layout.main);
You r taking the layout as Linearlayout object, you should take the LinearLayout id
Try this
LinearLayout lnr = (LinearLayout) findViewById(R.id.LinearLayout01);
Button b1 = new Button(this);
b1.setText("Btn");
lnr.addView(b1);
You can add controls programmatically if you want in your code, or even another XML with a View and an Inflater.
Here you can read the basics: http://developer.android.com/guide/topics/ui/declaring-layout.html
Ok, I have got it to work.
The steps are the following:
First inflate the xml layout, ie,
View view = View.inflate(this, R.layout.main, null);
Then instantiate the container object from the xml layout into a ViewGroup class, ie,
ViewGroup container = (ViewGroup) view.findViewById(R.id.myContainer);
Then create a linearLayout object, create and add onto that any controls needed, add the linearLayout to the container object and use setContentView on the view object, ie,
container.addView(buttonsLayout);
this.setContentView(view);
You can do this quite easy by setting an id on the layout on which you want to add views to. Say your main.xml look like this:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:id="#+id/label"
android:layout_width="fill_parent"/>
<LinearLayout android:id="#+id/container"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
</LinearLayout>
</LinearLayout>
Lets assume that you want to add your additional views to the LinearLayout with id id/container. In your onCreate method you could retrieve that object for later use:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContainer = (ViewGroup)view.findViewById(R.id.container);
}
Now you are all set to add other views to your container ViewGroup:
LinearLayout theButtons = getButtons()
mContainer.addView(theButtons);
In the getButtons method you need to create your LinearLayout containing the buttons you need. Either you do this programmatically or by inflating a view defined in an XML file. See LayoutInflater.inflate.
just try this:
LinearLayout mainLinearLayout = (LinearLayout) findViewById(R.layout.llmain);
now create button dynamically like this
Button btn1 = new Button(this);
btn1.setText=("Button 1");
mainLinearLayout .addView(btn1);
now if you want to add onether linearlayout then add it below button then
LinearLayout llinner = new LinearLayout(this);
Button btn2 = new Button(this);
btn2.setText=("Button 2");
mainLinearLayout .addView(btn2);
llinner.addView(btn2 );
mainLinearLayout .addView(llinner);
Try this :
LinearLayout ll =(LinearLayout)findViewById(R.id.linlay);
Button b = new Button(this);
b.setText("Hello");
l.addView(b);
This might help you
Here is what I did to display a set of runtime buttons on table layout.
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View view = View.inflate(this, R.layout.activity_main, null);
TableRow myrow = (TableRow) view.findViewById(R.id.myrow);
Button btn1 = new Button(this);
btn1.setText("Button 1");
myrow .addView(btn1);
Button btn2 = new Button(this);
btn2.setText("Button 2");
myrow .addView(btn2);
this.setContentView(view);
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ScrollView
android:id="#+id/myview"
android:layout_width="404dp"
android:layout_height="691dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<TableLayout
android:id="#+id/mylayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TableRow android:id="#+id/myrow"></TableRow>
</TableLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>
AVD Pixel4API30
Output screenshot

Categories

Resources