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.