1

I am trying to launch a foreground service and notification when the user clicks on a button. This button is called "startBtn". It is meant to show the number of steps that the user takes.

I have 3 files, StepsFragment.java, fragment_steps.xml and StepsService.java.

I encountered this error in Logcat when the user clicks on the button:

java.lang.IllegalStateException: Could not find method startService(View) in a parent or ancestor Context for android:onClick attribute defined on view class android.support.v7.widget.AppCompatButton with id 'startBtn'

I have tried these following solutions asked on StackOverflow:

How to solve error: Could not find method onClick(View) in a parent or ancestor Context for android:onClick

Could not find method in a parent or ancestor Context for android:onClick attribute

This is my code in StepsFragment.java:

package sg.edu.singaporetech.teamproject;

import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;

public class StepsFragment extends Fragment implements SensorEventListener, View.OnClickListener {

    Button updateBtn;
    ProgressBar progressBar;
    TextView tv_steps;
    TextView levelDisplay;
    SensorManager sensorManager;
    Sensor sensor;
    boolean running = false;
    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {


        View view = inflater.inflate(R.layout.fragment_steps, container, false);

        super.onCreate ( savedInstanceState );
        updateBtn = view.findViewById(R.id.updateBtn);
        progressBar = view.findViewById(R.id.progress_bar);
        tv_steps = (TextView) view.findViewById(R.id.tv_steps);
        levelDisplay = (TextView) view.findViewById(R.id.levelDisplay);
        sensorManager = (SensorManager) getActivity().getSystemService ( Context.SENSOR_SERVICE);

        updateBtn.setOnClickListener(this);

        return view;

    }

    public void startService(View view) {
        String input = tv_steps.getText().toString();
        Intent serviceIntent = new Intent(getActivity(),StepsService.class);
        serviceIntent.putExtra("inputExtra",input);

        getActivity().startService(serviceIntent);
    }

}

This is the button code in fragment_steps.xml:

    <android.support.v7.widget.AppCompatButton
        android:id="@+id/startBtn"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="30dp"
        android:background="@drawable/btn_orange"
        android:text="@string/start_steps"
        android:textColor="@color/white"
        android:textSize="15dp"
        android:onClick="startService"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/updateBtn" />

And lastly, this is the code in StepsService.java

package sg.edu.singaporetech.teamproject;

import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.support.v4.app.NotificationCompat;

import static sg.edu.singaporetech.teamproject.StepsNotification.CHANNEL_ID;

public class StepsService extends Service {

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String input = intent.getStringExtra("inputExtra");

        Intent notificationIntent = new Intent(this,StepsFragment.class);
        PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0);

        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
                .setContentTitle("Steps Tracker")
                .setContentText("Steps tracked")
                .setSmallIcon(R.drawable.exersize)
                .setContentIntent(pendingIntent)
                .build();
        startForeground(1,notification);

        return START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        return null;
    }
}
Zoe
  • 27,060
  • 21
  • 118
  • 148
Jim Ng
  • 91
  • 1
  • 4
  • 15
  • someone reported this issue two years ago, it seems like this is a bug? https://stackoverflow.com/questions/44028831/appcompatbutton-androidonclick-could-not-find-a-method-exception – John Joe Mar 29 '19 at 03:26
  • What is the android version you using ? – John Joe Mar 29 '19 at 03:30
  • Hi @JohnJoe, the device that I am debugging on is Android 9, API 28. My compileSdkVersion is 28. Android Studio Version is 3.3.2 – Jim Ng Mar 29 '19 at 03:32
  • The two link you posted in your post are actually extends to AppCompatActivity. You can't declare the method inside the fragment, instead you should declare in activity, then call the fragment method from the activity. – John Joe Mar 29 '19 at 03:38

1 Answers1

3

android:onClick="startService" will not called in fragment. You should use OnClickListener instead to handle this type of events.

Another approach is declare the startService function in activity, then call the fragment method from the activity.

Kindly refer Android app crashing (fragment and xml onclick) to know more.

John Joe
  • 12,412
  • 16
  • 70
  • 135