3

I am creating a custom theme for button and using android:onClick event of Button from xml itself to handle the click of Button.

Due to some reason its crashing with below exception

java.lang.IllegalStateException: Could not find a method MyOnClick(View) in the activity class android.view.ContextThemeWrapper for onClick handler on view class android.widget.Button with id 'button1'

And its working fine if I just remove the theme attribute from the Button, below is my theme for Button

    <style name="ButtonTheme" parent="@android:style/Widget.Button">
        <item name="android:textColor">#FF0000</item>
        <item name="android:shadowColor">#FF000000</item>
    </style>

And my Button defined in xml as below,

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/textView1"
        android:layout_margin="20dp"
        android:onClick="MyOnClick"
        android:theme="@style/ButtonTheme"
        android:text="Button" />

Here is my java code as well,

public void MyOnClick(View view) {
        switch (view.getId()) {
        case R.id.button1:
            getWindow().setStatusBarColor(getResources()
                                   .getColor(R.color.statusBarColor));
            getWindow().setNavigationBarColor(getResources()
                                   .getColor(R.color.statusBarColor));
            break;

        default:
            break;
        }

    }

So, what could be the reason for crashing? I am able to handle the click event if I remove android:theme="@style/ButtonTheme" attribute from Button Widget from xml.

Lalit Poptani
  • 67,150
  • 23
  • 161
  • 242
  • post your java code... – Rishad Appat Jul 27 '15 at 12:39
  • try using old way remove android:onClick attribute and use Button button=(Button)findViewById(R.id.button1);button.setOnClickListener(new View.OnClickListener(){ @Override public void onClick(View v) { } }); and don't forget to define button – Sanjeev Jul 27 '15 at 12:46
  • @L-X but why? I want to add click event in xml itself, then what? – Lalit Poptani Jul 27 '15 at 12:58
  • Buddy i guess the error is you are defining same onClick method to every button(Guessing you have more than 1 button) , but that is creating error try defining different function name to different button and define all those function in java ,Try it – Sanjeev Jul 27 '15 at 13:02
  • @L-X I have only one button for now and if I have more than one then too I can define it by using `view.getId()` inside a switch case. – Lalit Poptani Jul 27 '15 at 13:07
  • yes I was wrong can you try two things first check that this function is define in correct class where this layout has inflated and second try running your program by removing android:id attribute from button(as you have only 1 button now ) and remove switch from function – Sanjeev Jul 27 '15 at 13:21

3 Answers3

3

I've never seen anybody applying the android:theme attribute to an individual View, but after a bit of googling I found out that this is indeed possible, but only since Android 5.0.

A hint of this can be seen at the end here.

And some more detail here.

As the second link explains, a ContextThemeWrapper is used to modify the theme associated with the base Context. However, since your Activity will need to hold on to its own theme, I can only imagine that a new ContextThemeWrapper is created and assigned as the new Context of your View. Since this new Context is not your Activity any more, your callback functions don't exist here and you get the error you describe.

You can use the debugger to prove this yourself (I used Android Studio, but you can probably use the IDE of your choice, the details might be different).

  1. Run the app in debug mode with theme attribute set.
  2. When you get the exception, the stacktrace will contain a reference to the View class where it invokes onClick.
  3. Use this to add a breakpoint before the exception occurs.
  4. Now run the app again in debug mode, click the button
  5. When you hit the breakpoint evaluate the expression getContext(). You will see that this returns an object of type ContextThemeWrapper and it will have a member mBase which points back to your actual Activity, so getContext() itself does not return your Activity and does not have the callback functions you defined on your Activity.
  6. Now remove the theme attribute, leave the breakpoint and run the app again.
  7. When you hit the breakpoint, evaluate the expression getContext() again and you will see that this time it returns your Activity directly, which is why your callbacks work, if you don't set the theme attribute.

In short, it seems like you can't use the android:onClick attribute if you want to make use of this new feature, and you will have to manually assign an OnClickListener as described here

ci_
  • 8,594
  • 10
  • 39
  • 63
  • We can use `android:onClick` with Fragments as well, I have used it! – Lalit Poptani Jul 28 '15 at 10:00
  • I didn't say you can't use it, I said it's less useful. I believe so because you're creating fragments to modularise you're UI and then you're binding it strongly to a particular activity with onClick. Anyway, this was not the original question and is kinda besides the point. – ci_ Jul 28 '15 at 10:04
  • I have removed the contentious statement at the end because it didn't add to the answer. I have also added debugging instructions that show exactly what's going on, so you can validate this for yourself. – ci_ Jul 28 '15 at 10:22
  • Just wanted to point out that AppCompat v22.1 and above should allow individual widget theming from API 11 and above http://android-developers.blogspot.co.nz/2015/04/android-support-library-221.html – TheIT May 09 '16 at 02:09
0

Sometimes when we add style to Button It affects default android clickable behavior.

Try adding property clickable="true" in <Button... />

Or

You can also add <item name="android:clickable" >true</item> to style of button.

Azim Ansari
  • 1,378
  • 11
  • 20
0

After spending so much time on this, the thing that worked for me was to apply the theme in code setTheme(R.style.AppToolbar); in the onCreate() instead of ripping out all the android:OnClick from all the layouts.