The specified child already has a parent. You must call removeView() on the child's parent first (Android) - java

I have to switch between two layouts frequently. The error is happening in the layout posted below.
When my layout is called the first time, there doesn't occur any error and everything's fine. When I then call a different layout (a blank one) and afterwards call my layout a second time, it throws the following error:
> FATAL EXCEPTION: main
> java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
My layout-code looks like this:
tv = new TextView(getApplicationContext()); // are initialized somewhere else
et = new EditText(getApplicationContext()); // in the code
private void ConsoleWindow(){
runOnUiThread(new Runnable(){
#Override
public void run(){
// MY LAYOUT:
setContentView(R.layout.activity_console);
// LINEAR LAYOUT
LinearLayout layout=new LinearLayout(getApplicationContext());
layout.setOrientation(LinearLayout.VERTICAL);
setContentView(layout);
// TEXTVIEW
layout.addView(tv); // <========== ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT
et.setHint("Enter Command");
layout.addView(et);
}
}
}
I know this question has been asked before, but it didn't help in my case.

The error message says what You should do.
// TEXTVIEW
if(tv.getParent() != null) {
((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}
layout.addView(tv); // <========== ERROR IN THIS LINE DURING 2ND RUN
// EDITTEXT

simply pass the argument
attachtoroot = false
View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);

I came here on searching the error with my recyclerview but the solution didn't work (obviously). I have written the cause and the solution for it in case of recyclerview. Hope it helps someone.
The error is caused if in the onCreateViewHolder() the following method is followed:
layoutInflater = LayoutInflater.from(context);
return new VH(layoutInflater.inflate(R.layout.single_row, parent));
Instead it should be
return new VH(layoutInflater.inflate(R.layout.single_row, null));

I got this message while trying to commit a fragment using attach to root to true instead of false, like so:
return inflater.inflate(R.layout.fragment_profile, container, true)
After doing:
return inflater.inflate(R.layout.fragment_profile, container, false)
It worked.

You must first remove the child view from its parent.
If your project is in Kotlin, your solution will look slightly different than Java. Kotlin simplifies casting with as?, returning null if left side is null or cast fails.
(childView.parent as? ViewGroup)?.removeView(childView)
newParent.addView(childView)
Kotlin Extension Solution
If you need to do this more than once, add this extension to make your code more readable.
childView.removeSelf()
fun View?.removeSelf() {
this ?: return
val parentView = parent as? ViewGroup ?: return
parentView.removeView(this)
}
It will safely do nothing if this View is null, parent view is null, or parent view is not a ViewGroup

frameLayout.addView(bannerAdView); <----- if you get error on this line the do like below..
if (bannerAdView.getParent() != null)
((ViewGroup) bannerAdView.getParent()).removeView(bannerAdView);
frameLayout.addView(bannerAdView); <------ now added view

If other solution is not working like:
View view = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, false);
check for what are you returning from onCreateView of fragment is it single view or viewgroup? in my case I had viewpager on root of xml of fragment and I was returning viewpager, when i added viewgroup in layout i didnt updated that i have to return viewgroup now, not viewpager(view).

My error was define the view like this:
view = inflater.inflate(R.layout.qr_fragment, container);
It was missing:
view = inflater.inflate(R.layout.qr_fragment, container, false);

In my case it happens when i want add view by parent to other view
View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(lyt); // -> crash
you must add parent view like this
View root = inflater.inflate(R.layout.single, null);
LinearLayout lyt = root.findViewById(R.id.lytRoot);
lytAll.addView(root);

Simplified in KOTLIN
viewToRemove?.apply {
if (parent != null) {
(parent as ViewGroup).removeView(this)
}
}

In my case, I had id named as "root" for constraint layout, which was conflicting the existing parent root id.
Try to change the id.
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/root" //<--It should not named as root.
android:layout_width="match_parent"
android:layout_height="match_parent"
</androidx.constraintlayout.widget.ConstraintLayout>

In my case the problem was caused by the fact that I was inflating parent View with <merge> layout. In this case, addView() caused the crash.
View to_add = inflater.inflate(R.layout.child_layout_to_merge, parent_layout, true);
// parent_layout.addView(to_add); // THIS CAUSED THE CRASH
Removing addView() helped to solve the problem.

The code below solved it for me:
#Override
public void onDestroyView() {
if (getView() != null) {
ViewGroup parent = (ViewGroup) getView().getParent();
parent.removeAllViews();
}
super.onDestroyView();
}
Note: The error was from my fragment class and by overriding the onDestroy method like this, I could solve it.

My problem is related to many of the other answers, but a little bit different reason for needing to make the change... I was trying to convert an Activity to a Fragment. So I moved the inflate code from onCreate to onCreateView, but I forgot to convert from setContentView to the inflate method, and the same IllegalStateException brought me to this page.
I changed this:
binding = DataBindingUtil.setContentView(requireActivity(), R.layout.my_fragment)
to this:
binding = DataBindingUtil.inflate(inflater, R.layout.my_fragment, container, false)
That solved the problem.

You just need to pass attachToRoot parameter false.
mBinding = FragmentCategoryBinding.inflate(inflater, container, false)

If you're using ViewBinding, make sure you're referring to the right binding!
I had this issue when I was trying to inflate a custom dialog from within an activity:
AlertDialog.Builder builder = new AlertDialog.Builder(this);
final AlertBinding alertBinding = AlertBinding.inflate(LayoutInflater.from(this), null, false);
builder.setView(binding.getRoot()); // <--- I was using binding (which is my Activity's binding), instead of alertBinding.

This is how I do my custom dialog
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
android.view.View views = getLayoutInflater().inflate(layout_file, null, false);
builder.setView(views);
dialog = builder.create();
dialog.show();
I changed it into this and its works for me, I hope this helps
Dialog dialog = new Dialog(MainActivity.this);
dialog.setContentView(layout_file);
dialog.show();

check if you already added the view
if (textView.getParent() == null)
layout.addView(textView);

if(tv!= null){
((ViewGroup)tv.getParent()).removeView(tv); // <- fix
}

I was facing the same error, and look what I was doing. My bad, I was trying to add the same view NativeAdView to the multiple FrameLayouts, resolved by creating a separate view NativeAdView for each FrameLayout, Thanks

In my case I was accidentally returning a child view from within Layout.onCreateView() as shown below:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v= inflater.inflate(R.layout.activity_deliveries, container, false);
RecyclerView rv = (RecyclerView) v.findViewById(R.id.deliver_list);
return rv; // <- here's the issue
}
The solution was to return the parent view (v) instead of the child view (rv).

I found another fix:
if (mView.getParent() == null) {
myDialog = new Dialog(MainActivity.this);
myDialog.setContentView(mView);
createAlgorithmDialog();
} else {
createAlgorithmDialog();
}
Here i just have an if statement check if the view had a parent and if it didn't Create the new dialog, set the contentView and show the dialog in my "createAlgorithmDialog()" method.
This also sets the positive and negative buttons (ok and cancel buttons) up with onClickListeners.

In my case, I had an adapter which worked with a recyclerView, the items that were being passed to the adapter were items with their own views.
What was required was just a LinearLayout to act as a container for every item passed, so what I was doing was to grab the item in the specified position inside onBindViewHolder then add it to the LinearLayout, which was then displayed.
Checking the basics in docs,
When an item scrolls off the screen, RecyclerView doesn't destroy its
view
Therefore, with my items, when I scroll towards a direction, then change towards the opposite direction - fast, the racently displayed items have not been destroyed, meaning, the items are still associated with the LinearLayout container, then on my end, I'm trying to attach to another container, which ends up with a child having a parent already.
My solution was to check if the specified item has a parent, if it has, I assign it to a variable, then call parentVar.removeView(item), then assign the new parent.
Here's the sample code(Problematic Adapter):
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int) {
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
holder.linearLayoutContainer.addView(questionWidget)/*addView throws error once in a while*/
}
inner class QuestionWidgetViewHolder(mView: View) :
RecyclerView.ViewHolder(mView) {
val linearLayoutContainer: LinearLayout =
mView.findViewById(R.id.custom_question_widget_container)
}
Content of the R.id.custom_question_widget_container:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom_question_widget_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:orientation="vertical"
android:padding="10dp" />
So, the questionWidget seems to have been retaining the parent for almost 4 steps outside visibility, and when I scroll to the opposite direction fast, I would encounter it still with its parent, then I'm attempting to add it to another container.
Here's the fix - option 1:
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int) {
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
val initialWidgetParent : ViewParent? = questionWidget.parent
//attempt to detach from previous parent if it actually has one
(initialWidgetParent as? ViewGroup)?.removeView(questionWidget)
holder.linearLayoutContainer.addView(questionWidget)
}
Another better solution - option 2:
override fun onBindViewHolder(holder: QuestionWidgetViewHolder, position: Int) {
holder.linearLayoutContainer.removeAllViewsInLayout()
val questionWidget: QuestionWidget =
dataSource[position]
questionWidget.setValueChangedListener(this)
val initialWidgetParent : ViewParent? = questionWidget.parent
//if it's in a parent container already, just ignore adding it to a view, it's already visible
if(initialWidgetParent == null) {
holder.linearLayoutContainer.addView(questionWidget)
}
}
Actually, it's much of asking the child if it has a parent before adding it to a parent.

I tried all the things that you guys suggested, with no luck.
But, I managed to fix it by moving all my binding initializations from onCreate to onCreateView.
onCreate(){
binding = ScreenTicketsBinding.inflate(layoutInflater)
}
MOVE TO
onCreateView(...){
binding = ScreenTicketsBinding.inflate(layoutInflater)
}

You can use this methode to check if a view has children or not .
public static boolean hasChildren(ViewGroup viewGroup) {
return viewGroup.getChildCount() > 0;
}

My case was different the child view already had a parent view i am adding the child view inside parent view to different parent. example code below
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="#dimen/lineGap"
>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/black1"
android:layout_gravity="center"
android:gravity="center"
/>
</LinearLayout>
And i was inflating this view and adding to another LinearLayout, then i removed the LinaarLayout from the above layout and its started working
below code fixed the issue:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="#color/black1" />

It happened with me when I was using Databinding for Activity and Fragments.
For fragment - in onCreateView we can inflate the layout in traditional way using inflater.
and in onViewCreated method, binding object can be updated as
binding = DataBindingUtil.getBinding<FragmentReceiverBinding>(view) as FragmentReceiverBinding
It solved my issue

In my case, I was doing this (wrong):
...
TextView content = new TextView(context);
for (Quote quote : favQuotes) {
content.setText(quote.content);
...
instead of (good):
...
for (Quote quote : favQuotes) {
TextView content = new TextView(context);
content.setText(quote.content);
...

If you are working with MaterialAlertDialog, this worked for me:
(yourChildView.parent as? ViewGroup)?.removeView(yourChildView)

If in your XML you have layout with id "root" It`s problem, just change id name

Related

How to create a dynamic UI with Kotlin in Android Studio

create widget at runtime as texts and buttons, with kotlin language
For example, when clicking a button, a new text is created
The answer for XML-based UI:
To add a view programmatically on Android, you can use the addView method of a ViewGroup. Here are the basic steps:
Get a reference to the parent ViewGroup where you want to add the new view. You can do this by calling findViewById on the parent Activity or Fragment.
Create a new instance of the View you want to add to the parent ViewGroup. You can do this by calling the constructor of the View class that matches the type of View you want to create.
Set any necessary properties on the new View, such as its layout parameters or content.
Add the new View to the parent ViewGroup by calling the addView method on the parent ViewGroup and passing in the new View.
Here's an example of how to add a TextView to a LinearLayout programmatically:
val linearLayout = findViewById(R.id.linear_layout) // get a reference to the parent LinearLayout
val textView = TextView(this) // create a new TextView in Activity
// or TextView(requireContext) in Fragment
textView.text = "Hello, world!" // set the text of the TextView
linearLayout.addView(textView) // add the TextView to the LinearLayout
lets assume you have a ViewGroup such as LinearLayout and lets name it group
and you have a button.
Based on this assumption. I would do the following
mButton.setOnClickListener{
group.addView(TextView(context)
.also{
it.text = "your text"
})
}
of course you will have to work on positioning it too

Why do we need to Inflate a layout and attachToRoot in Android?

I was given this code:
override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater!!.inflate(R.layout.fragment_wednesday, container, false)
}
and I don't understand why we need to Inflate a layout and write attachToRoot value.
btw, why do we need a viewGroup?
A layout definition is just some XML data but to really show a layout it must be converted to a tree of objects. The inflater does that.
A container (ViewGroup) is necessary to control where (in a larger tree of view objects) the inflated subtree should be placed.
consider this code
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup fragment_container, Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.example_fragment, fragment_container, false);
}
The second parameter fragment_container is a container(framelayout) with id fragment_container that activity uses to add view of fragment in its layout.
No if we read source code of inflate method of LayoutInflater class, we get this( i removed unnecessary shit here to make you understand code better)
// The view that would be returned from this method.
View result = root;
// Temp is the root view that was found in the xml.
final View temp = createViewFromTag(root, name, attrs, false);
Firstly, it creates a temp view from the supplied root.
In case attachToRoot is false, it does this :
// Decide whether to return the root that was passed in or the
// top view found in xml.
if (root == null || !attachToRoot) {
result = temp;
}
In case attachToRoot is false, it simply returns the root of the fragment's xml, i.e. the container parameter is just used to get layoutParams for fragment's root view (since it doesn't have a root, so it needs params from somewhere).
In case attachToRoot is true, it does this :
// We are supposed to attach all the views we found (int temp)
// to root. Do that now.
if (root != null && attachToRoot) {
root.addView(temp, params);
}
It adds the temp view created above to the root view (i.e. container).
The main difference between the "third" parameter attachToRoot being true or false is this.
true : add the child view to parent RIGHT NOW
false: add the child view to parent NOT NOW. Add it later. `
When is that later?
That later is when you use for eg parent.addView(childView)
A common misconception is, if attachToRoot parameter is false then the child view will not be added to parent. WRONG
In both cases child view will be added to parentView. It is just the matter of time.
inflater.inflate(child,parent,false);
parent.addView(child);
is equivalent to
inflater.inflate(child,parent,true);
NOTE !! NOTE !! NOTE !!
You should never pass attachToRoot as true when you are not responsible for adding the child view to parent.
Eg When adding Fragment
public View onCreateView(LayoutInflater inflater,ViewGroup parent,Bundle bundle)
{
super.onCreateView(inflater,parent,bundle);
View v = inflater.inflate(R.layout.image_fragment,parent,false);
return v;
}
now , if you pass third parameter as true you will get IllegalStateException because of the following piece of code.
getSupportFragmentManager()
.beginTransaction()
.add(parent, childFragment)
.commit();
Since you have already added the child fragment in onCreateView() by mistake. Calling add will tell you that child view is already added to parent , hence IllegalStateException. This Exception comes from the following piece of code which can be found while inspecting inflate method in LayoutInflater class
if (child.getParent() != null) {
throw new IllegalStateException("The specified child already has a parent. " +
"You must call removeView() on the child's parent first.");
}
Here you are not responsible for adding childView, FragmentManager is responsible. So always pass false in this case

App crashes when setting background colour

Every time I run my app it crashes giving me a nullpointerexception, I want to programatically change my background depending on the scenario, here is my code:
Main Activity:
public class Activity extends AppCompatActivity {
ConstraintLayout layout;
String messageSafe = "Item is Safe for Consumption";
String messageUnSafe = "Item is NOT Safe for Consumption";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_information);
layout = new ConstraintLayout(this);
if (matched.length == 0) {
layout.setBackgroundResource(R.drawable.background_safe);
setContentView(layout);
changeColor("#00FF00");
messageView.setText(messageSafe);
}
else{
layout.setBackgroundResource(R.drawable.background_unsafe);
setContentView(layout);
changeColor("#FF0000");
messageView.setText(messageUnSafe);
}
ListView listContains = (ListView) findViewById(R.id.lvItemsFound);
ArrayAdapter<String> contains = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, foundItems);
listContains.setAdapter(contains);
ListView listRestricted = (ListView) findViewById(R.id.lvItemsRestricted);
ArrayAdapter<String> found = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, matched);
listRestricted.setAdapter(found);
}
You are losing reference to your old view because you changed the layout to a new ConstraintLayout object. This means you now don't have your ListView objects and other items in your XML because that View is gone. It's not the ContentView anymore. If you want to work on the existing layout, you need to give the root view an ID.
<constraintlayout android:id="#+id/container" ... />
Then you can reference that ID with findViewById(R.id.container) and use the object you get from it to change your background like you are doing.
Try this:
1. Give your root view an ID
2. Set a ConstraintLayout object with ConstraintLayout layout = findViewById(R.id.container) (Note: You can call it anything, not just container, I am just going off my example from above, since I gave it the ID 'container')
3. call setBackgroundResource() like you are doing.
4. No need to call setContentView() again, this was set in the beginning, and you do not want to reset it to a new view you just constructed like you were initially doing.
5. You shouldn't crash when trying to call setAdapter() to your ListView now because you don't have a reference to an object that isn't in your content view.
layout = (ConstraintLayout)findViewById(R.id.container);
if (matched.length == 0) {
layout.setBackgroundResource(R.drawable.background_safe);
changeColor("#00FF00"); //assuming this is some local function?
messageView.setText(messageSafe);
}
else{
layout.setBackgroundResource(R.drawable.background_unsafe);
changeColor("#FF0000");
messageView.setText(messageUnSafe);
}
You are trying to set the background by replacing the view of your activity (this is what setContentView() does). This causes a null pointer exception later because the old layout (defined in the XML) has been replaced, so your list view no longer exists.
Instead, you should get a reference to the existing root view (the ConstraintLayout, although if you're just setting background you can just reference it as a View, no need to be so specific), and set the background on it, like so:
findViewById(R.id.container).setBackgroundResource(R.drawable.unsafe);
You'll also need to give the containing layout an id in the existing layout XML:
<android.support.constraint.ConstraintLayout
android:id="#+id/container"
... etc.

Radio Buttons inside expandable list remain when expanding other child elements

I want to make an expandable list of radio groups in my android app. each element of the list should contain (when opened) several individual radio groups. So far I am testing with only one radiogroup per child and already I am encountering a problem I can't seem to solve by myself.
When I expand a parent of my expandable list, it seems to work properly. The radiobuttons of a radiogroup (which is the only child element of a parent right now) are displayed the way they should. However, when I expand another parent of my expandable list, the radio buttons are added to the already existing buttons of the other child group. Which means: Once I've expanded several child groups, each one of the expanded children contains tons of radio buttons, flooding the whole screen.
Simply put, when I expand parent 1 I get the choices
yes
no
maybe
When I expand the second parent, I get the radio choices
yes
no
maybe
yes
no
perhaps
probably
... which are also added to the radio button group thats inside parent 1. So now I have 2 large expanded list elements. When I expand another group, the choices get added to all the child views as well, and so on, and so on...
So, following simple logic it seems that all the radio buttons are not put into a new group (thats newly created every time I expand a child list), but instead they are added to the same, already existing group.
I have been able to pretty much isolate the problem to the getChildView function inside my ExpandableListAdapter class. This is the code which causes the output described above:
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,
ViewGroup parent) {
ExpandListChild child = (ExpandListChild) getChild(groupPosition, childPosition);
if (view == null) {
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = infalInflater.inflate(R.layout.child_layout, null);
}
ArrayList<HashMap<String,String>> inputDetailsList = child.getInputfields();
//RadioGroup rg = new RadioGroup(view.getContext());
RadioGroup rg = (RadioGroup) view.findViewById(R.id.radiogroup);
int has_radiogroup = 0;
for (int i = 0; i <inputDetailsList.size(); i++){
if (inputDetailsList.get(i).get("type").equals("radio")){
has_radiogroup = 1;
RadioButton rb = new RadioButton(rg.getContext());
rb.setText(inputDetailsList.get(i).get("textcontent"));
rg.addView(rb);
}
}
return view;
}
Here is the xml file that is used as child layout:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="55dip"
android:background="#color/ExpandChildBackground"
android:orientation="vertical" >
<TextView
android:id="#+id/tvChild"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#color/Black"
android:textSize="17dip" />
<RadioGroup
android:id="#+id/radiogroup"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
>
</RadioGroup>
</LinearLayout>
The line where I suspect my error could be this one:
RadioGroup rg = (RadioGroup) view.findViewById(R.id.radiogroup);
It looks for the radio group I created inside the inflated child layout (R.layout.child_layout). But it does not use a new one for each expanded child view and instead uses an existing one to apply the buttons to. In other words, it seems like the radio group never gets the sign that its "finished" and/or the child view never gets the sign that a new radioGroup has to be used instead of the old one.
What I have tried is creating a new RadioGroup for each child view using the following line (you can see it is the commented line in the code above), instead of using the radiogroup I defined in my layout.
Making a fresh radiogroup would look like this:
RadioGroup rg = new RadioGroup(view.getContext());
However, this does not work, it does not display any radio groups, let alone buttons at all. I have also tried removing the radiogroup element from the layout xml-file (because its not used anyway). Still no luck. Using simple unorganized textviews for each element seems to work properly, so this points to a problem with my radio group implementation as well.
Honestly, I am out of ideas right now. I might be getting the wrong context, but I have no clue what context to use. If anyone is able to point me the right direction, I would be extremely grateful. Thanks in advance.
If anyone is interested, I have been able to fix the problem myself. I have simply removed the if-condition [ if (view == null) ], so the new code looks like this:
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View view,
ViewGroup parent) {
ExpandListChild child = (ExpandListChild) getChild(groupPosition, childPosition);
LayoutInflater infalInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = infalInflater.inflate(R.layout.child_layout, null);
ArrayList<HashMap<String,String>> inputDetailsList = child.getInputfields();
RadioGroup rg = (RadioGroup) view.findViewById(R.id.radiogroup);
int has_radiogroup = 0;
for (int i = 0; i <inputDetailsList.size(); i++){
if (inputDetailsList.get(i).get("type").equals("radio")){
System.out.println("type: "+inputDetailsList.get(i).get("type"));
has_radiogroup = 1;
RadioButton rb = new RadioButton(rg.getContext());
rb.setText(inputDetailsList.get(i).get("textcontent"));
System.out.println("textcontent: "+inputDetailsList.get(i).get("textcontent"));
rb.setId(Integer.parseInt(inputDetailsList.get(i).get("value")));
if (has_radiogroup == 1){
rg.addView(rb);
}
}
}
return view;
}
Now it makes sense. The LayoutInflater is called everytime a new child view is generated, i.e. a group is expanded. Before this, it just used the existing view (view was not null) that was filled with radiobuttons, and added the new radiobuttons to that existing view, resulting in my list flooding the screen.
Thanks however to anyone trying to get their heads into the problem.
This is worked for me.
For RadioButtons and CheckBoxs
android:focusable="false"

Clickable ListView

I'm looking now a few days for a solution for clickable items in a listView.
First I came across this:
developer.android.com/resources/articles/touch-mode.html
and found that it's doesn't have the "normal" onListItemClick() behavouir.
Then I came across of this code:
http://www.androidsnippets.org/snippets/125/
// LINE 296-321
#Override
protected ViewHolder createHolder(View v) {
// createHolder will be called only as long, as the ListView is not filled
// entirely. That is, where we gain our performance:
// We use the relatively costly findViewById() methods and
// bind the view's reference to the holder objects.
TextView text = (TextView) v.findViewById(R.id.listitem_text);
ImageView icon = (ImageView) v.findViewById(R.id.listitem_icon);
ViewHolder mvh = new MyViewHolder(text, icon);
// Additionally, we make some icons clickable
// Mind, that item becomes clickable, when adding a click listener (see API)
// so, it is not necessary to use the android:clickable attribute in XML
icon.setOnClickListener(new ClickableListAdapter.OnClickListener(mvh) {
public void onClick(View v, ViewHolder viewHolder) {
// we toggle the enabled state and also switch the icon
MyViewHolder mvh = (MyViewHolder) viewHolder;
MyData mo = (MyData) mvh.data;
mo.enable = !mo.enable; // toggle
ImageView icon = (ImageView) v;
icon.setImageBitmap(
mo.enable ? ClickableListItemActivity.this.mIconEnabled
: ClickableListItemActivity.this.mIconDisabled);
}
});
While debugging I noticed the parameter View v is a TextView and not a "normal" View and then of course:
TextView text = (TextView) v.findViewById(R.id.listitem_text);
returnes null and I get a NullPointerException...
Any ideas why? And how I can solve this?
Thanks in advance! :)
How do you create your instance of ClickableListAdapter ?
When you create your list adapter, you have to pass a resource id viewId, this should be a layout which will be inflated later.
public ClickableListAdapter(Context context, int viewid, List objects) {
// Cache the LayoutInflate to avoid asking for a new one each time.
mInflater = LayoutInflater.from(context);
mDataObjects = objects;
mViewId = viewid;
Below, the code inflate the xml layout passed to the constructor and call createHolder.
view = mInflater.inflate(mViewId, null);
// call the user's implementation
holder = createHolder(view);
So make sure that when instantiating your ClickableListAdapter, you pass a layout instead of an id
Edit
You have to create a xml layout with the following which is taken from the link you have provided:
<?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="horizontal"
android:gravity="center_vertical"
>
<TextView android:text="Text" android:id="#+id/listitem_text"
android:layout_weight="1"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
></TextView>
<ImageView android:id="#+id/listitem_icon"
android:src="#drawable/globe2_32x32"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxWidth="32px"
android:maxHeight="32px"
>
</ImageView>
</LinearLayout>
If you call it mylistrow.xml in the layout directory, so you construct your adapter as :
adapter = new MyClickableChannelListAdapter(this, R.layout.mylistrow, channelList);
setListAdapter(adapter);
List items should be clickable right out of the box. You can check how lists are coded by looking at ApiDemos project code. It should be present on your local machine since it is a part of the SDK. I have it at <root_sdk_folder>\platforms\android-2.0.1\samples\ApiDemos.

Categories