I have a res/layout/main.xml including these elements and others:
I ran into the same issue a while back when I added a custom View via the layout XML and then tried to attached a callback elsewhere in the application ...
I created a custom view and added it to my "layout_main.xml"
public class MUIComponent extends SurfaceView implements SurfaceHolder.Callback {
public MUIComponent (Context context, AttributeSet attrs ) {
super ( context, attrs );
}
// ..
}
And in the main Activity I wanted to attach some callbacks and get references to the UI elements from the XML.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
MUIInitializer muiInit = new MUIInitializer();
muiInit.setupCallbacks(this);
muiInit.intializeFields(this);
}
}
The initilizer wasn't doing anything fancy but any changes it tried to make to the custom view (MUIComponent) or other non-custom UI elements simply were not appearing in the application.
public class MUIInitializer {
// ...
public void setupCallbacks ( Activity mainAct ) {
// This does NOT work properly
// - The object instance returned is technically an instance of my "MUICompnent" view
// but it is a *different* instance than the instance created and shown in the UI screen
// - Callbacks never get triggered, changes don't appear on UI, etc.
MUIComponent badInst = (MUIComponent) mainAct.findViewById(R.id.MUIComponent_TESTSURF);
// ...
// This works properly
LayoutInflater inflater = (LayoutInflater) mainAct.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View inflatedLayout = inflater.inflate ( R.layout.activity_main, null );
MUIComponent goodInst = (MUIComponent) inflatedLayout.findViewById(R.id.MUIComponent_TESTSURF);
// Add callbacks
// ...
}
}
The difference between the "badInst" and "goodInst" is:
I had the same problem. My mistake was that: I wrote
LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout=inflater.inflate(R.layout.dlg_show_info, null);
alertDlgShowInfo.setView(layout);
TableRow trowDesc=(TableRow)findViewById(R.id.trowDesc);
and as I used an inflater to "load" the view from an XML file, the last line was wrong. To solve it, I had to write:
TableRow trowDesc=(TableRow)layout.findViewById(R.id.trowDesc);
I wrote my solution, in case someone have the same problem.
In my case findViewById was returning null because my custom view looked something like this in the main XML:
<com.gerfmarquez.seekbar.VerticalSeekBar
android:id="@+id/verticalSeekBar"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
/>
and I found out that when I added the xmlns stuff it worked like this:
<com.gerfmarquez.seekbar.VerticalSeekBar
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/verticalSeekBar"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
/>
The findViewById() method sometimes returns null when the root of layout has no android:id attribute. Eclipse wizard for generating layout xml file does not automatically generate android:id attribute for the root element.
This happened to me with a custom component for Wear, but is a generic piece of advice. If you're using a Stub (such as I was using WatchViewStub), you can't just put the call to findViewById() anywhere. Everything inside the stub must be inflated first, which doesn't just happen after setContentView(). Thus, you should write something like this in order to wait for that to happen:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wear);
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub);
stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
@Override
public void onLayoutInflated(WatchViewStub stub) {
myCustomViewInst = (MyCustomView) findViewById(R.id.my_custom_view);
...
i had the same problem because i forgot to update the view id in all my layout folders.