Android service yapısı, Android’in temel bileşenlerinden olup genel kullanım amacı yan iş parçacığı oluşturmaktır. Uzun süren işlemler (download vb.) için olmazsa olmaz bileşendir. Android in service bileşenini kendi ihtiyaçlarınız doğrultusunda özelleştirebilir ve uygulamanızı modern bir yapıya kavuşturabilirsiniz.

Burada yapacağımız örnekte kısaca şu aşamaları görücez;

  • Service i foreground olarak başlatmak
  • Ongoing(devamlı gözüken) notification oluşturmak
  • GoogleApiClient a bağlanmak
  • Location bilgisini notification da göstermek

İlk olarak Service imiz kodlarını yazalım. Gerekli açıklamalar kodların arasında mevcuttur.

ForegroundService.java

public class ForegroundService extends Service implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener {

 private static final int LOCATION_NOTIF_ID = 859;
 private static int LocationPeriod = 1000 * 30 ;
 
 private static Notification notification;
 private static GoogleApiClient _googleApiClient = null;
 private static Context mContext;
 private static NotificationCompat.Builder mBuilder;



 @Override
 public void onCreate() {
 super.onCreate();
 mContext = this;
 mBuilder = new NotificationCompat.Builder(mContext);
 }

 @Nullable
 @Override
 public IBinder onBind(Intent intent) {
 return null;
 }

 @Override
 public int onStartCommand(Intent intent, int flags, int startId) {


 // Eğer Service ilk defa çalıştırılıyor ise buildGoogleApiClient fonksiyonu ile GoogleApiClient build ediliyor
 if (_googleApiClient == null) {
 buildGoogleApiClient();
 }
 // GoogleApiClient a bağlanılıyor
 _googleApiClient.connect();

 // Notificaiton gösteriyoruz
 LocationNotification(null, "Konum Bilgisi Yok");

 // Service imizi foreground olarak başlatıyoruz
 // Foreground service bizden bir notification parametresi ister. Bunun sebebi sürekli ayakta olduğunu kullanıcıya bildirmektir.
 startForeground(LOCATION_NOTIF_ID, notification);

 // Herhangi bir sebeple service imizi durması halinde kendiliğinden tekrar başlaması için START_STICKY dönüyoruz.
 return START_STICKY;
 }


 public synchronized void buildGoogleApiClient() {
 if (_googleApiClient == null) {
 _googleApiClient = new GoogleApiClient.Builder(this)
 .addConnectionCallbacks(this)
 .addOnConnectionFailedListener(this)
 .addApi(LocationServices.API)
 .build();
 }
 }


 @Override
 public void onConnected(@Nullable Bundle bundle) {
 // GoogleApiClient a bağlanıldığında Location isteğinde bulunuyoruz.
 LocationRequest();
 }


 @Override
 public void onConnectionSuspended(int i) {

 }


 @Override
 public void onConnectionFailed(ConnectionResult result) {
 // tekrar bağlanmayı deniyoruz
 _googleApiClient.connect();
 }


 private void LocationRequest() {


 // PRIORITY_BALANCED_POWER_ACCURACY -> hassas konum bilgisine ihtiyacımız yok ise (Network, Cell Tower)
 // PRIORITY_HIGH_ACCURACY -> hassas konum bilgisine ihtiyacımız var ise (GPS)

 final LocationRequest locationRequest = LocationRequest.create()
 .setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
 .setInterval((LocationPeriod * 1000)) 
 .setFastestInterval(LOCATION_FASTEST_INTERVAL);


 //final LocationRequest locationRequest1 = LocationRequest.create()
 // .setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY)
 // .setInterval((LocationPeriod * 1000))
 // .setFastestInterval(LOCATION_FASTEST_INTERVAL);

 // İhtiyaçlarımız doğrultusunda yapılandırdığımız LocationRequest in gerekliliklerini kontrol ederek, cihazın davranışının otomatik olarak ayarlanması için
 // gerekli Dialog penceresinin çıkmasını sağlar ve Kullanıcının onayını ister

 // Örnek olarak eğer PRIORITY_HIGH_ACCURACY olrarak belirlenmişse ve cihazın GPS i kapalı ise bir Dialog çıkartarak GPS i açmanızı ister
 LocationSettingsRequest locationSettingsRequest = new LocationSettingsRequest.Builder()
 .addLocationRequest(locationRequest)
 .setAlwaysShow(true)
 .build();

 PendingResult<LocationSettingsResult> result =
 LocationServices.SettingsApi.checkLocationSettings(_googleApiClient, locationSettingsRequest);

 // Gösterilen Dilag penceresi ile Kullanıcının etkileşimi sonucunun yakalar
 result.setResultCallback(new ResultCallback<LocationSettingsResult>() {
 @DebugLog
 @Override
 public void onResult(LocationSettingsResult locationSettingsResult) {

 // locationSettingsStates ile cihazın durumunu kontrol ederek akışımızı yönlendirebiliriz
 LocationSettingsStates locationSettingsStates = locationSettingsResult.getLocationSettingsStates();
 
 // Konum dinlenmeye başlanır
 // mLocationListener ile konum değişikliği yakalanır.
 FusedLocationApi.requestLocationUpdates(_googleApiClient, locationRequest, mLocationListener);
 
 //FusedLocationApi.requestLocationUpdates(_googleApiClient, locationRequest1, mLocationListener);
 
 }
 });


 }


 private static LocationListener mLocationListener = new LocationListener() {
 @Override
 public void onLocationChanged(Location location) {


 // Location değişikliğini burada yakalayabiliriz.
 // Belirlemiş olduğumuz periyodik zaman aralığında Location değişikliği kontrol edilecektir.
 }
 };


 
 public ForegroundService() {
 }

 // Bu fonksiyon yardımı ile başka bir sınıftan konum bilgisine erişebiliriz.
 // static olarak tanımlanmış olması bize kolaylık sağlıcaktır.
 public static Location getLastLocation() {
 if (_googleApiClient != null) {
 return FusedLocationApi.getLastLocation(_googleApiClient);
 } else {
 return null;
 }
 }


 // GoogleApiClient nesnemize erişmek istersek bu kod bloğunu kullanabiliriz.
 public static GoogleApiClient getGoogleApiClient() {
 return _googleApiClient;
 }

 
 public static void removeLocationUpdates() {
 if (_googleApiClient != null) {
 FusedLocationApi.removeLocationUpdates(_googleApiClient, mLocationListener);
 }
 }

 @DebugLog
 private static void LocationNotification(Location location, String subText) {
 NotificationManager notificationManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE);
 //

 mBuilder.setSmallIcon(R.drawable.ic_stat_device_gps_fixed);
 mBuilder.setTicker("Konum");
 //.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
 mBuilder.setSubText(subText);
 mBuilder.setOnlyAlertOnce(true);
 mBuilder.setPriority(Notification.PRIORITY_HIGH);


 if (location != null) {
 mBuilder
 .setContentTitle("Sapma: " + String.valueOf(location.getAccuracy()))
 .setContentText("Lat: " + String.valueOf(location.getLatitude()) + " , " +
 "Long: " + String.valueOf(location.getLongitude()))
 .setWhen(System.currentTimeMillis())
 .setShowWhen(true)
 .setUsesChronometer(true)
 .setContentIntent(pendingIntent);


 } else {
 mBuilder
 .setContentTitle("")
 .setContentText("");
 }


 notification = mBuilder.build();
 notificationManager.notify(LOCATION_NOTIF_ID, notification);
 }

 @DebugLog
 @Override
 public void onDestroy() {
 if (_googleApiClient != null) {
 if (_googleApiClient.isConnected()) {
 FusedLocationApi.removeLocationUpdates(_googleApiClient, mLocationListener);
 _googleApiClient.disconnect();
 }
 }
 PeriodicHandler.removeMessages(1);
 stopForeground(true);
 super.onDestroy();
 }


}

Tanımlamış olduğumuz servisi başlatmak için istediğimiz yerden ( Activity , Fragment vb.) aşağıdaki kod bloğunu çalıştırmamız yeterli olucaktır.

Intent serviceIntent = new Intent(context, ForegroundService.class);
startService(serviceIntent);