6

I am building an app named Ping in Android Studio. So far my activities are LoginActivity ProfileActivity and Timeline. My issue is that a button in the layout corresponding to the Timeline activity has an onClick method that isn't working. When the button is clicked, the emulator gives the "Unfortunatley, Ping has stopped." I'm defining the buttons and onClick methods the same way I have for other buttons whose functions are working, just this one does not seem to work. I'm receiving an error saying the method can't be found, but I've written the method in the corresponding activity. Here is the logcat:

04-30 10:40:08.727    2075-2075/com.ping_social.www.ping E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Process: com.ping_social.www.ping, PID: 2075
    java.lang.IllegalStateException: Could not find a method onProfilePress(View) in the activity class android.view.ContextThemeWrapper for onClick handler on view class android.widget.Button with id 'profileButton'
            at android.view.View$1.onClick(View.java:4007)
            at android.view.View.performClick(View.java:4780)
            at android.view.View$PerformClick.run(View.java:19866)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.NoSuchMethodException: onProfilePress [class android.view.View]
            at java.lang.Class.getMethod(Class.java:664)
            at java.lang.Class.getMethod(Class.java:643)
            at android.view.View$1.onClick(View.java:4000)
            at android.view.View.performClick(View.java:4780)
            at android.view.View$PerformClick.run(View.java:19866)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5257)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)

Here is my Timeline activity class:

package com.ping_social.www.ping;

import android.content.Intent;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;

public class TimeLine extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_time_line);

        /*print log that shows we've got here*/
        Log.i("LoginActivity", "Layout has been set");
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_time_line, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    /*called when user presses the Log in button*/
    public void onProfilePress(View view){
        /*Log the button press*/
        Log.i("TimeLine", "Has reached the onProfilePress method");

        Intent intent = new Intent(this, ProfileActivity.class);
        startActivity(intent);
    }
}

And here is my Timeline layout xml code:

<RelativeLayout 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:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:theme="@style/GeneralTheme"
    tools:context="com.ping_social.www.ping.TimeLine">

    <TextView android:text="@string/no_pings" android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30sp"
        android:layout_centerVertical="true"
        android:layout_centerHorizontal="true"
        android:textIsSelectable="false"
        android:textColor="@color/PING_TOP_BAR_RED"
        android:id="@+id/textView4" />

    <LinearLayout
        android:orientation="horizontal"
        android:layout_width="fill_parent"
        android:layout_height="60dp"
        android:layout_alignParentBottom="true"
        android:layout_centerHorizontal="true">

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/timeline_button"
            android:id="@+id/timelineButton"
            android:textColor="@color/PING_TOP_BAR_RED"
            android:layout_weight="1"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/new_ping_button"
            android:id="@+id/newPingButton"
            android:layout_weight="1"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/activity_button"
            android:id="@+id/activityButton"
            android:layout_weight="1"/>

        <Button
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/profile_button"
            android:id="@+id/profileButton"
            android:layout_weight="1"
            android:onClick="onProfilePress"/>
    </LinearLayout>

</RelativeLayout>

I'm pretty positive there are not spelling issues, and there are also no other buttons that share the same ID or methods that share the same name. Been stuck on this for a few days, any help is very much appreciated!

ThePartyTurtle
  • 2,276
  • 2
  • 18
  • 32
  • 1
    Why you don't register it from java code `Button.setOnClickListener(new View.onClickListener` ? – Jibran Khan Apr 30 '15 at 17:53
  • 1
    Do you mind testing it without this line please: `android:theme="@style/GeneralTheme"`? – AndroidEx Apr 30 '15 at 18:12
  • 1
    This is the same problem as at the link by @divyenduz however it is hidden there behind an additional, unrelated problem. The issue looks to be that various children of Activity don't correctly set the View's ownership information, so it goes looking for the custom method in the generic parent class android.view.ContextThemeWrapper rather than in the custom Activity subclass where it actually exists. – Chris Stratton Apr 30 '15 at 18:14
  • 1
    Reopened as there was neither an applicable solution or even correct analysis at the proposed duplicate. Most of what was there concerned instead a more obvious problem unique to that question, which forced programmatic setting rather than using the android:onClick mechanism in xml. This question deserves an explanation of how to make the xml method work, or a researched statement of why it cannot work despite the *appearance* that it should. – Chris Stratton Apr 30 '15 at 18:24
  • At a hand-waving level, the problem is that the complicated indirection involved in ActionBarActivity means that the View's attempt to find your custom method via reflection ends up looking in the wrong place. Exactly where in the support library source it goes wrong I am yet to find, but it seems like this is not going to work for an ActionBarActivity or AppCompatActivity. – Chris Stratton Apr 30 '15 at 19:05
  • Android777: Just ran the code without the theme field. That did it! Does anyone know why? It seems Chris has an idea, but I guess it's messy. Regardless thanks for the help!!! This is my first post to stack overflow and I really appreciate it. – ThePartyTurtle May 01 '15 at 03:12

1 Answers1

3

Ok, so I made my own test. I've put together a basic relative layout with a single button, put android:theme="@style/AppTheme" in it, and a button - app crashed with the same error. Then I removed android:theme attribute - onclick event fired as it should.

All the same happened when I used AppCompatActivity instead of now-deprecated ActionBarActivity.

It's hard for me to say why it doesn't work with android:theme. It's one of Lollipop's features, but I tried to launch in on API 5.0 emulator. The article states that currently this attribute is only supported for android.support.v7.widget.Toolbar.

AndroidEx
  • 15,524
  • 9
  • 54
  • 50