Home » Android » java – Custom View children are null after inflating the view in Android

java – Custom View children are null after inflating the view in Android

Posted by: admin June 15, 2020 Leave a comment

Questions:

I am working on an Android app. I have a custom view and layout as follows:

<com.hello.view.card.inner.SimpleCardView xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/card_simple_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical" >

        <TextView
            android:id="@+id/simple_label"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>

</com.hello.view.card.inner.SimpleCardView>

And this is the Java class:

public class SimpleCardView extends LinearLayout {
    protected SimpleCard card = null;
    protected TextView textView;

    public SimpleCardView(Context context) {
        super(context);     
        init(context);
    }

    public SimpleCardView(Context context, AttributeSet attrs) {
        super(context, attrs);      
        init(context);
    }

    public SimpleCardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    protected void init(Context context) {
        textView = (TextView)findViewById(R.id.simple_label);
    }

    public void setCard(SimpleCard card) {
        this.card = card;
        textView.setText(card.getMessage());        
    }
}

And this is how I am inflating the view (I tried both following calls):

SimpleCardView view = (SimpleCardView)inflater.inflate(R.layout.card_simple, null);
//SimpleCardView view = (SimpleCardView)inflater.inflate(R.layout.card_simple, parent);
view.setCard(card);

The problem I am having is when view.setCard(card) is called, I see that textView is null, even though I am expecting it to be set in the init(..) method. Can anyone tell me what it not being set correctly? Thanks in advance.

How to&Answers:

Thank you for your answers. It turns out init(context) should not be called in the constructor. The right place to call it is in onFinishInflate(). The following change helped fix it:

public class SimpleCardView extends LinearLayout {
    protected SimpleCard card = null;
    protected TextView textView;

    public SimpleCardView(Context context) {
        super(context);     
    }

    public SimpleCardView(Context context, AttributeSet attrs) {
        super(context, attrs);      
    }

    public SimpleCardView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        init(getContext());
    }

    protected void init(Context context) {
        textView = (TextView)findViewById(R.id.simple_label);
    }

    public void setCard(SimpleCard card) {
        this.card = card;
        textView.setText(card.getMessage());        
    }
}

Answer:

Instead of using root element

com.hello.view.card.inner.SimpleCardView

try using

<merge xmlns:android="http://schemas.android.com/apk/res/android">
    <TextView
        android:id="@+id/simple_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"/>
</merge>

then, in your init method

LayoutInflater.from(context).inflate(R.layout.card_simple, this);
setOrientation(LinearLayout.VERTICAL);
textView = (TextView)findViewById(R.id.simple_label);

When you use the view in other layouts, that’s where you will want to put

<com.hello.view.card.inner.SimpleCardView />

and any properties that it needs, its id, its width/height, etc.