Search code examples
androidandroid-custom-viewlayout-inflatercustom-viewfindviewbyid

Custom compound view and .findViewById()


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?


Solution

  • 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