2

When I call findViewById() to get a button (in the form of an ImageView), it returns null. I have looked over these suggestions and I can tell that

  • findViewById() is called after setContentView().
  • There is only one layout: activity_main.xml.
  • I am not using ExpandableListView.
  • Both findViewById() and topbar.findViewById() return null.

What else might I have overlooked?

activity_main.xml

<LinearLayout>
 <GridView
   android:id="@+id/topbar_grid">
 </GridView>
</LinearLayout>

Mainactivity.java

public class MainActivity extends Activity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initializeTopBar();
        initializeMenu();
    }

    private void initializeTopBar() {
        GridView topbar = (GridView) findViewById(R.id.topbar_grid);
        TopBarAdapter topBarAdapter = new TopBarAdapter(this);
        topbar.setAdapter(topBarAdapter);

        ImageView playButton = (ImageView) findViewById(topBarAdapter.playButtonId);
        // Debugging shows playButton is null here
        // Removing the below statement results in the app 
        // being displayed just fine
        playButton.setOnClickListener(new Button.OnClickListener(){
            public void onClick(View v){
                onPlayButtonClick();
            }
        }); 
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }
}

TopBarAdapter.java

public class TopBarAdapter extends BaseAdapter {
    private Context context;
    private View[] views = new View[2];

    public int playButtonId = 2000;
    public int trackLabelId = 2001;

    public TopBarAdapter(Context c){
        context = c;
        createTrackLabel();
        createPlayButton();
    }

    private void createPlayButton(){
        ImageView playButton = new ImageView(context);
        playButton.setImageResource(R.drawable.play_icon);
        playButton.setScaleType(ScaleType.CENTER_CROP);
        playButton.setLayoutParams(new GridView.LayoutParams(50, 50));
        playButton.setId(playButtonId);
        views[1] = playButton;
    }




    @Override
    public int getCount() {
        return views.length;
    }

    @Override
    public Object getItem(int position) {
        return views[position];
    }

    @Override
    public long getItemId(int position) {
        return 0;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        return views[position];
    }
}
Community
  • 1
  • 1
Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • but you never add the playButton to the view hierarchy of the Activity, or am I missing something? – Blackbelt Mar 09 '14 at 20:05
  • @blackbelt: the `playButton` is part of the `TopBarAdapter` which is added to the `GridView`. Removing the event listener displays the app just fine (including the play button). – Jeroen Vannevel Mar 09 '14 at 20:07
  • but then are you returning the playButton somehow in the getView method? – Blackbelt Mar 09 '14 at 20:12
  • @blackbelt: I have added the rest of the `TopBarAdapter` class. As far as I can tell: yes, it should be returned. – Jeroen Vannevel Mar 09 '14 at 20:15
  • I see. you should set the onClickListener when you created the object, inside createPlayButton or, better, use `tobbar.setOnItemClickListener` – Blackbelt Mar 09 '14 at 20:28
  • @blackbelt: that does make a lot more sense than what I'm doing right now. I'll try it out and get back to you. I'm still curious as to why I can't retrieve the generated element by its ID though, do you have any idea why that is? – Jeroen Vannevel Mar 09 '14 at 20:30
  • @blackbelt: setting the event listener in the `TopBarAdapter` works perfectly, if you post it as an answer I will accept it. Still very curious why I can't retrieve the element by its ID though. – Jeroen Vannevel Mar 09 '14 at 20:33
  • well that's a long discussion, but the adapter works with 1 element like 1000. If your getView returns all the elements with same id, which one the system would return? Also we are not considering view's recycle and other mechanism involved to optimize resources – Blackbelt Mar 09 '14 at 20:33

2 Answers2

2

you should set the OnItemClickListener on your topbar:

topbar.setOnItemClickListener(new OnItemClickListener() {

    @Override
    public void onItemClick(AdapterView<?> parent, View view, 
            int position, long id) {

    }
});
Blackbelt
  • 156,034
  • 29
  • 297
  • 305
  • 1
    I have simply put the `playButton.setOnClickListener()` inside `TopBarAdapter#createPlayButton()`, but I'm assuming your example will work as well. – Jeroen Vannevel Mar 09 '14 at 20:40
0

Is the playButton added somewhere to your layout? Where it comes from? The best way to use findViewById method is to rely on Android-generater ids, so instead

     Button playButton = (Button) findViewById(topBarAdapter.playButtonId);

You should rather rely on

Button playButton = (Button) findViewById(R.id.playButtonId);

given that <Button/> with id playButtonId is actually a part of your current view's layout specified by R.layout.activity_main . When looking for topBarAdapter children's id's you should rather call

Button playButton = (Button) topBarAdapter.findViewById(R.id.playButtonId);
Dale Cooper
  • 310
  • 2
  • 9
  • The `playButton` (It's an `ImageView`, not a `Button`. Mistake in my original post) is part of the `TopBarAdapter` which is the adapter set to my `GridView`. It renders just fine if I don't call the NPE with the event listener: the play button shows up. Keep in mind that my button is not entered into the XML so it does not have its ID generated in `R.id`: it is generated in `TopBarAdapter`. – Jeroen Vannevel Mar 09 '14 at 20:14