MJonesDev MJonesDev - 4 months ago 27
Android Question

Start and stop timer service on click

I have a service that runs in the background and every 15 minutes, it will show a notification or dialog. But how can I get it to start and stop OnClick of a FAB?
The button shows a Snack Bar OnClick, currently. I want to add If/Else code to start and stop the service. How can I do this?

Here is the service:

public class SafeService extends Service {
private Handler mHandler = new Handler();
private Timer mTimer = null;
public static final int NOTIFICATION_ID = 1;
public static final long NOTIFY_INTERVAL = 900 * 1000; // 15 Minutes
/*^TODO - TEST NOTIFY_INTERVAL FOR ACCURACY^*/

/*^Those are for the timer and handler so the code
can recognise it^ The last one gives how long the timer runs */
@Override
public IBinder onBind(Intent intent) {
return null;
}

@Override
public void onCreate() {
// Cancels the timer if it already existed.
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}

class TimeDisplayTimerTask extends TimerTask {

@Override
public void run() {
// run on another thread
mHandler.post(new Runnable() {

@Override
public void run() {
// Lollipop or Above
if (Build.VERSION.SDK_INT >= 21) {
NotificationCompat.Builder builder = new NotificationCompat.Builder(SafeService.this);
new NotificationCompat.Builder(SafeService.this);
builder.setSmallIcon(R.drawable.smallplaceholder);
builder.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
builder.setContentTitle("Safeguard");
builder.setContentText("Be careful, Trainer! Remember to look up and stay aware of your surroundings!!");
builder.setStyle(new NotificationCompat.BigTextStyle().bigText("Be careful, Trainer! Remember to look up and stay aware of your surroundings!!"));
builder.setPriority(Notification.PRIORITY_HIGH);
builder.setVibrate(new long[] { 1000, 1000, 1000, 1000, 1000 });
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFICATION_ID, builder.build());
//Below Lollipop
} else {
new MaterialDialog.Builder(SafeService.this)
.title(R.string.warning_title)
.content(R.string.warning)
.positiveText(R.string.button_ok)
.show();
}

}
});

}

};
}


Here is the button I want to start and stop the service:

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Safeguard is now on!", Snackbar.LENGTH_LONG).show();
//Start service after showing SnackBar
}
});

Answer

You can use a Singleton instance which will bind/unbind from your service, this way, the service will not be unbound if your activity is destroyed by Android :

ServiceSingleton.java :

public class ServiceSingleton {

    private String TAG = ServiceSingleton.class.getSimpleName();

    private static ServiceSingleton mInstance;

    private Context mContext;

    private boolean mBound = false;

    private SafeService mService;

    private ServiceConnection mServiceConnection = null;

    public static ServiceSingleton getInstance(Context context) {
        if (mInstance == null)
            mInstance = new ServiceSingleton(context);
        return mInstance;
    }

    private ServiceSingleton(Context context) {
        this.mContext = context.getApplicationContext();
    }

    public boolean startNotification() {

        if (!mBound) {

            mServiceConnection = new ServiceConnection() {
                @Override
                public void onServiceConnected(ComponentName componentName, IBinder service) {

                    Log.i(TAG, "onServiceConnected");

                    mService = ((SafeService.LocalBinder) service).getService();

                    mService.startNotification();
                }

                @Override
                public void onServiceDisconnected(ComponentName componentName) {
                }
            };

            Intent intent = new Intent(this, SafeService.class);
            mBound = mContext.bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);

            if (!mBound) {
                Log.e(TAG, "Error cant bind to service !");
            }
        } else {
            if (mService != null) {
                mService.startNotification();
            }
        }
        return mBound;
    }

    public void stopNotification() {
        if (mBound && mService != null) {
            mService.stopNotification();
        }
    }

    public boolean isNotificationStarted() {
        if (mBound && mService != null) {
            return mService.isNotificationStarted();
        }
        return false;
    }

    public void close() {
        try {
            if (mBound) {
                if (mService!=null){
                    mService.stopNotification();
                }
                mContext.unbindService(mServiceConnection);
                mBound = false;
            }
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
    }

    public boolean isBound() {
        return mBound;
    }
}

In your onCreate()

mSingleton = ServiceSingleton.getInstance();

For your click listener :

FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);

fab.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {

        if (mSingleton.isNotificationStarted()){
            mSingleton.startNotification(); 
        }
        else {
            mSingleton.stopNotification();
        }

    }
});

stopNotification() wont unbind service if you want to reuse it, if you want to shut it down call close()

Comments