해당 코드는 위의 StackOverFlow에서 가져왔습니다.
전체 코드
class BackgroundLocationUpdateService : Service(),
GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, LocationListener {
/**
* Declare in manifest
* <service android:name=".BackgroundLocationUpdateService"/>
*/
private val TAG = "BackgroundLocationUpdateService"
private val TAG_LOCATION = "TAG_LOCATION"
private lateinit var context: Context
private var stopService = false
/** For Google Fused API **/
protected var mGoogleApiClient: GoogleApiClient? = null
protected var mLocationSettingsRequest: LocationSettingsRequest? = null
private var latitude = "0.0"
private var longitude = "0.0"
private var mFusedLocationClient: FusedLocationProviderClient? = null
private var mSettingsClient: SettingsClient? = null
private var mLocationCallback: LocationCallback? = null
private var mLocationRequest: LocationRequest? = null
private var mCurrentLocation: Location? = null
/** For Google Fused API **/
override fun onCreate() {
super.onCreate()
context = this
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
StartForeground()
val handler = Handler()
val runnable: Runnable = object : Runnable {
override fun run() {
try {
if (!stopService) {
//TODO Your Task
}
} catch (e: Exception) {
e.printStackTrace()
} finally {
if (!stopService) {
handler.postDelayed(this, TimeUnit.SECONDS.toMillis(10))
}
}
}
}
handler.postDelayed(runnable, 2000)
buildGoogleApiClient()
return START_STICKY
}
override fun onDestroy() {
Log.e(TAG, "Service Stopped")
stopService = true
if (mFusedLocationClient != null) {
mFusedLocationClient!!.removeLocationUpdates(mLocationCallback!!)
Log.e(TAG_LOCATION, "Location Update Callback Removed")
}
super.onDestroy()
}
override fun onBind(p0: Intent?): IBinder? {
return null
}
@SuppressLint("UnspecifiedImmutableFlag")
private fun StartForeground() {
val intent = Intent(context, MainActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
val pendingIntent = PendingIntent.getActivity(
this,
0 /* Request code */,
intent,
PendingIntent.FLAG_IMMUTABLE or FLAG_ONE_SHOT
)
val CHANNEL_ID = "channel_location"
val CHANNEL_NAME = "channel_location"
var builder: NotificationCompat.Builder? = null
val notificationManager =
applicationContext.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val channel = NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT
)
channel.lockscreenVisibility = Notification.VISIBILITY_PRIVATE
notificationManager.createNotificationChannel(channel)
builder = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
.setChannelId(CHANNEL_ID)
.setBadgeIconType(NotificationCompat.BADGE_ICON_NONE)
}
else {
builder = NotificationCompat.Builder(applicationContext, CHANNEL_ID)
}
val notificationSound: Uri =
RingtoneManager.getActualDefaultRingtoneUri(this, RingtoneManager.TYPE_NOTIFICATION)
builder
.setContentTitle("Your title")
.setContentText("You are now online")
.setSound(notificationSound)
.setAutoCancel(true)
// .setSmallIcon(R.drawable.ic_logo)
.setContentIntent(pendingIntent)
val notification: Notification = builder.build()
startForeground(101, notification)
}
override fun onLocationChanged(location: Location) {
Log.e(
TAG_LOCATION,
"Location Changed Latitude : " + location.latitude + "\tLongitude : " + location.longitude
)
latitude = location.latitude.toString()
longitude = location.longitude.toString()
if (latitude.equals("0.0", ignoreCase = true) && longitude.equals(
"0.0",
ignoreCase = true
)) {
requestLocationUpdate()
}
else {
Log.e(
TAG_LOCATION,
"Latitude : " + location.latitude + "\tLongitude : " + location.longitude
)
}
}
override fun onConnected(bundle: Bundle?) {
mLocationRequest = LocationRequest()
.setInterval((10 * 1000).toLong())
.setFastestInterval((5 * 1000).toLong())
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY)
val builder = LocationSettingsRequest.Builder()
.addLocationRequest(mLocationRequest!!)
.setAlwaysShow(true)
mLocationSettingsRequest = builder.build()
mSettingsClient!!
.checkLocationSettings(mLocationSettingsRequest!!)
.addOnSuccessListener {
Log.e(TAG_LOCATION, "GPS Success")
requestLocationUpdate()
}.addOnFailureListener { e ->
val statusCode = (e as ApiException).statusCode
when (statusCode) {
LocationSettingsStatusCodes.RESOLUTION_REQUIRED -> try {
val REQUEST_CHECK_SETTINGS = 214
val rae = e as ResolvableApiException
rae.startResolutionForResult(
(context as AppCompatActivity),
REQUEST_CHECK_SETTINGS
)
} catch (sie: SendIntentException) {
Log.e(TAG_LOCATION, "Unable to execute request.")
}
LocationSettingsStatusCodes.SETTINGS_CHANGE_UNAVAILABLE -> Log.e(
TAG_LOCATION,
"Location settings are inadequate, and cannot be fixed here. Fix in Settings."
)
}
}.addOnCanceledListener {
Log.e(
TAG_LOCATION,
"checkLocationSettings -> onCanceled"
)
}
}
override fun onConnectionSuspended(p0: Int) {
connectGoogleClient()
}
override fun onConnectionFailed(p0: ConnectionResult) {
buildGoogleApiClient()
}
@Synchronized
protected fun buildGoogleApiClient() {
mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context)
mSettingsClient = LocationServices.getSettingsClient(context)
mGoogleApiClient = GoogleApiClient.Builder(context)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API)
.build()
connectGoogleClient()
mLocationCallback = object : LocationCallback() {
override fun onLocationResult(locationResult: LocationResult) {
super.onLocationResult(locationResult)
Log.e(TAG_LOCATION, "Location Received")
mCurrentLocation = locationResult.lastLocation
onLocationChanged(mCurrentLocation!!)
}
}
}
private fun connectGoogleClient() {
val googleAPI = GoogleApiAvailability.getInstance()
val resultCode = googleAPI.isGooglePlayServicesAvailable(context)
if (resultCode == ConnectionResult.SUCCESS) {
mGoogleApiClient!!.connect()
}
}
@SuppressLint("MissingPermission")
private fun requestLocationUpdate() {
mFusedLocationClient!!.requestLocationUpdates(
mLocationRequest!!,
mLocationCallback!!, Looper.myLooper()!!
)
}
}
코드 분석
1. onStartCommand() , StartForegrond()
안드로이드 공식문서에 따르면
https://developer.android.com/guide/components/services?hl=ko#ExtendingIntentService
다음과 같이 나와있다.
서비스를 시작할 때 Intent를 startService() 또는 startForegroundServise()에 전달
Android 시스템이 서비스의 onStartCommand() 메서드를 호출하고 여기에 시작할 서비스를 지정하는 Intent를 전달
이후 5초 이내에 startForeground() 메서드를 호출하라고 되어있다.
따라서 onStartCommand 함수는 Service가 시작한 후 실행되는 함수이며, StartForeground 함수는 startForeground 메서드를 호출하기 위한 설정 및 호출 함수이다.
2. buildGoogleApiClient()
@Synchronized : 여러 스레드가 동시에 공용 자원에 접근하지 못하게 막는 어노테이션
사용자 위치 정보 공식 문서
https://developer.android.com/training/location?hl=ko
위치 서비스를 이용하기 위한 통합 위치 정보 제공자 클라이언트 등을 설정하는 함수
3. connectGoogleClient()
googleAPI가 사용 가능한 상태면 연결
4. onConnected()
위치 요청이 성공적이면 requestLocationUpdate 함수를 호출
실패 시 사용자에게 위치 설정을 수정할 수 있는 권한을 요청하는 대화상자를 표시한다.
5. requestLocationUpdate()
https://developer.android.com/develop/sensors-and-location/location/request-updates?hl=ko
위치 업데이트
6. LocaionCallback() : var mLocationCallback
업데이트 시 mLocationCallback 호출
현재 Location 저장 및 onLocationChanged 함수 호출
7. onLocationChanged()
현재 위치(위도, 경도) latitude & longitude에 저장
'안드로이드 > 안드로이드' 카테고리의 다른 글
[안드로이드] SharedPreferences (0) | 2023.11.29 |
---|---|
[안드로이드] MyApplication (1) | 2023.11.26 |
[안드로이드] Api Key 저장 방법 with local.properties (1) | 2023.11.25 |
[안드로이드] 푸쉬 알림 (기초) (1) | 2023.11.22 |
[안드로이드] AlertDialog (0) | 2023.11.22 |