I have a main activity with a nav drawer that brings up different pages as fragments. In one of the fragments there is a button, that when clicked will start a sensor service and store sensor info to a database in the background even when the screen is turn off (wake lock).
However, when the button is clicked the onStartCommand
method doesn't seem to be called (its not logging anything to logcat)
I'm not sure why the service isn't starting. I've seen a number of tutorials/questions on this, but they all use activities, but in my case I am trying to start the sensor service class from a fragment within a MainActivity. A lot of my confusion stems from mixing fragments and activities, and how to correctly start services from a fragment
Here is the fragment with the button:
public class StartFragment extends Fragment implements View.OnClickListener {
Button startButton;
Boolean started = false;
CoordinatorLayout coordinatorLayout;
MainActivity mainActivity;
public StartFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_start, container, false);
coordinatorLayout = (CoordinatorLayout) getActivity().findViewById(R.id.coordinator_layout);
//Set the nav drawer item highlight
mainActivity = (MainActivity)getActivity();
mainActivity.navigationView.setCheckedItem(R.id.nav_start);
//Set actionbar title
mainActivity.setTitle("Start");
//Set onclick listener for save button
startButton = (Button) view.findViewById(R.id.startButton);
startButton.setOnClickListener(this);
// Inflate the layout for this fragment
return view;
}
@Override
public void onClick(View v) {
if (!started){
mainActivity.startService(new Intent(mainActivity, SensorService.class));
startButton.setText(getResources().getString(R.string.start_button_label_stop));
Snackbar.make(coordinatorLayout, "Recording...", Snackbar.LENGTH_SHORT).show();
} else {
mainActivity.stopService(new Intent(mainActivity, SensorService.class));
startButton.setText(getResources().getString(R.string.start_button_label_start));
Snackbar.make(coordinatorLayout, "Recording stopped.", Snackbar.LENGTH_SHORT).show();
}
started = !started;
}
}
And here is the SensorService
class that should run on button click:
public class SensorService extends Service implements SensorEventListener {
public static final String TAG = SensorService.class.getName();
public static final int SCREEN_OFF_RECEIVER_DELAY = 500;
private SensorManager sensorManager = null;
private WakeLock wakeLock = null;
private Sensor sensor;
Sensor accelerometer;
Sensor gyroscope;
Sensor gravity;
Sensor magnetic;
private void registerListener() {
sensorManager.registerListener(this, accelerometer, SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(this, gyroscope, SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(this, gravity, SensorManager.SENSOR_DELAY_FASTEST);
sensorManager.registerListener(this, magnetic, SensorManager.SENSOR_DELAY_FASTEST);
}
private void unregisterListener() {
sensorManager.unregisterListener(this);
}
public BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive("+intent+")");
if (!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
return;
}
Runnable runnable = new Runnable() {
public void run() {
Log.i(TAG, "Runnable executing.");
unregisterListener();
registerListener();
}
};
new Handler().postDelayed(runnable, SCREEN_OFF_RECEIVER_DELAY);
}
};
public void onAccuracyChanged(Sensor sensor, int accuracy) {
//Safe not to implement
}
public void onSensorChanged(SensorEvent event) {
//TODO add async task to insert to DB
}
@Override
public void onCreate() {
super.onCreate();
sensorManager = (SensorManager) getSystemService(SENSOR_SERVICE);
accelerometer = sensorManager.getDefaultSensor(MainActivity.TYPE_ACCELEROMETER);
gyroscope = sensorManager.getDefaultSensor(MainActivity.TYPE_GYROSCOPE);
gravity = sensorManager.getDefaultSensor(MainActivity.TYPE_GRAVITY);
magnetic = sensorManager.getDefaultSensor(MainActivity.TYPE_MAGNETIC);
PowerManager manager =
(PowerManager) getSystemService(Context.POWER_SERVICE);
wakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
registerReceiver(receiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
}
@Override
public void onDestroy() {
unregisterReceiver(receiver);
unregisterListener();
wakeLock.release();
stopForeground(true);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand");
startForeground(Process.myPid(), new Notification());
registerListener();
wakeLock.acquire();
return START_STICKY;
}
}
Try adding this in your XML Manifest inside the application tag, outside anything else:
<service android:name=".SensorService" />
Let me know if this helped.