0

I am really worried about the .findViewById() method and its use in a custom compound view creation. I am not sure about the exact place that it is guaranteed that it will never return null.

Let's say I have this custom compound view and that it is added to some .xml like this:

<com.app.path.TwoButtonsView
            android:id="@+id/ok_cancel_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>

two_buttons_view.xml:

<?xml version="1.0" encoding="utf-8"?>
<merge>

    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
                  xmlns:tools="http://schemas.android.com/tools"
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:orientation="horizontal">

        <TextView
            android:id="@+id/first_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:clickable="true"
            android:gravity="center"
            android:textAllCaps="true"/>

        <TextView
            android:id="@+id/second_button"
            android:layout_width="0dp"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:clickable="true"
            android:gravity="center"
            android:textAllCaps="true"/>
    </LinearLayout>
</merge>

TwoButtonsView.java

public class TwoButtonsView extends LinearLayout {

    // views
    private TextView mFirstButtonView;
    private TextView mSecondButtonView;

    public TwoButtonsView(Context context) {
        super(context);
        init(context, null);
    }

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

    public TwoButtonsView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context, attrs);
    }

    @TargetApi(Build.VERSION_CODES.LOLLIPOP)
    public TwoButtonsView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context, attrs);
    }

    private void init(Context context, AttributeSet attrs) {
        LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.two_buttons_view, this);

        // retrieve views
        mFirstButtonView = (TextView) findViewById(R.id.first_button); // is there a chance it will return null?
        mSecondButtonView = (TextView) findViewById(R.id.second_button); // is there a chance it will return null?
    }
}

My question is: is there any chance that .findViewById(RESOURCE_ID) will return null right after calling inflater.inflate(R.layout.two_buttons_view, this);, or should I call my init() method on onFinishInflate() callback?

Augusto Carmo
  • 4,386
  • 2
  • 28
  • 61

1 Answers1

2

My question is: is there any chance that .findViewById(RESOURCE_ID) will return null right after calling inflater.inflate(R.layout.two_buttons_view, this)

No, there is not, as long as the views you are looking for are in the layout and you explicitly added to the view's hierarchy. In the end, findViewById loops on View[], filled up by addView.

A small note about

LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflater.inflate(R.layout.two_buttons_view, this);

ViewGroup has the static method inflate, so you don't need to retrieve the inflater calling getSystemService

Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • Thank you very much for your answer, @Blackbelt! Could you explain me what is the purpose of `onFinishInflate()` then, please? – Augusto Carmo Nov 11 '16 at 11:08
  • 1
    it is a callback that gets call when all the children declared in the layout have been added. In your case, you are adding manually – Blackbelt Nov 11 '16 at 11:15
  • Thanks again for the answer :D. One final question: you said that I added them manually, but what is the other way to add them "not manually"? I could not think of any =/ – Augusto Carmo Nov 11 '16 at 11:19
  • 1
    when you declare those in the xml. Android inflates them and add it for you – Blackbelt Nov 11 '16 at 11:22
  • Oh, but this custom view were added through xml (in another layout), and so its children (in its xml). – Augusto Carmo Nov 11 '16 at 11:25
  • not thy are not. You are retrieving the inflater, and inflating the layout manually and asking it to add it. – Blackbelt Nov 11 '16 at 11:27